diff options
author | Philip Herron <philip.herron@embecosm.com> | 2021-08-15 01:12:54 +0100 |
---|---|---|
committer | Philip Herron <philip.herron@embecosm.com> | 2021-08-19 15:39:18 +0100 |
commit | c25cdc84600e81bfd4d1ae104ff9eb524f7c49f0 (patch) | |
tree | d0b5d1437673ce5bd051aa21f75b0f5d20a9c934 /gcc | |
parent | fe9dd83b41346fa667c693e5dd10dc9fe80e93b3 (diff) | |
download | gcc-c25cdc84600e81bfd4d1ae104ff9eb524f7c49f0.zip gcc-c25cdc84600e81bfd4d1ae104ff9eb524f7c49f0.tar.gz gcc-c25cdc84600e81bfd4d1ae104ff9eb524f7c49f0.tar.bz2 |
Initial Typechecking for projections
QualifiedPathInExpressions resolve to trait items which require careful
management of substitutions which still need to be implemented. This is the
building block to get that work done.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-bounds.h | 12 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-expr.h | 300 |
2 files changed, 202 insertions, 110 deletions
diff --git a/gcc/rust/typecheck/rust-hir-type-bounds.h b/gcc/rust/typecheck/rust-hir-type-bounds.h index ce694da..2c06134 100644 --- a/gcc/rust/typecheck/rust-hir-type-bounds.h +++ b/gcc/rust/typecheck/rust-hir-type-bounds.h @@ -38,6 +38,18 @@ public: return probe.trait_references; } + static bool is_bound_satisfied_for_type (TyTy::BaseType *receiver, + TraitReference *ref) + { + std::vector<TraitReference *> bounds = Probe (receiver); + for (TraitReference *b : bounds) + { + if (b == ref) + return true; + } + return false; + } + private: void scan (); diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index d39b2ee..d82b5c7 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -28,6 +28,8 @@ #include "rust-hir-path-probe.h" #include "rust-substitution-mapper.h" #include "rust-hir-const-fold.h" +#include "rust-hir-trait-resolve.h" +#include "rust-hir-type-bounds.h" namespace Rust { namespace Resolver { @@ -923,6 +925,74 @@ public: infered = resolved->get_field_type (); } + void visit (HIR::QualifiedPathInExpression &expr) override + { + HIR::QualifiedPathType qual_path_type = expr.get_path_type (); + TyTy::BaseType *root + = TypeCheckType::Resolve (qual_path_type.get_type ().get ()); + if (root->get_kind () == TyTy::TypeKind::ERROR) + return; + + if (!qual_path_type.has_as_clause ()) + { + // then this is just a normal path-in-expression + NodeId root_resolved_node_id = UNKNOWN_NODEID; + bool ok = resolver->lookup_resolved_type ( + qual_path_type.get_type ()->get_mappings ().get_nodeid (), + &root_resolved_node_id); + rust_assert (ok); + + resolve_segments (root_resolved_node_id, expr.get_segments (), 0, root, + expr.get_mappings (), expr.get_locus ()); + } + + // Resolve the trait now + TraitReference *trait_ref + = TraitResolver::Resolve (*qual_path_type.get_trait ().get ()); + if (trait_ref->is_error ()) + return; + + // does this type actually implement this type-bound? + if (!TypeBoundsProbe::is_bound_satisfied_for_type (root, trait_ref)) + return; + + // then we need to look at the next segment to create perform the correct + // projection type + if (expr.get_segments ().empty ()) + return; + + DefId resolved_item_id = UNKNOWN_DEFID; + HIR::PathExprSegment &item_seg = expr.get_segments ().at (0); + + const TraitItemReference *trait_item_ref = nullptr; + bool ok + = trait_ref->lookup_trait_item (item_seg.get_segment ().as_string (), + &trait_item_ref); + if (!ok) + { + rust_error_at (item_seg.get_locus (), "unknown associated item"); + return; + } + + // TODO self and generic arguments + + infered = trait_item_ref->get_tyty (); + rust_debug_loc (expr.get_locus (), "resolved to:"); + infered->debug (); + + TyTy::ProjectionType *projection + = new TyTy::ProjectionType (qual_path_type.get_mappings ().get_hirid (), + TyTy::TyVar (root->get_ref ()), trait_ref, + resolved_item_id); + context->insert_type (qual_path_type.get_mappings (), projection); + + // continue on as a path-in-expression + NodeId root_resolved_node_id + = trait_item_ref->get_mappings ().get_nodeid (); + resolve_segments (root_resolved_node_id, expr.get_segments (), 1, infered, + expr.get_mappings (), expr.get_locus ()); + } + void visit (HIR::PathInExpression &expr) override { NodeId resolved_node_id = UNKNOWN_NODEID; @@ -931,15 +1001,15 @@ public: TyTy::BaseType *tyseg = resolve_root_path (expr, &offset, &resolved_node_id); + if (tyseg == nullptr) + { + rust_debug_loc (expr.get_locus (), "failed to resolve root_seg"); + } rust_assert (tyseg != nullptr); if (tyseg->get_kind () == TyTy::TypeKind::ERROR) return; - // this is the case where the name resolver has already fully resolved the - // name, which means all the work is already done. - bool name_resolved_fully = offset >= expr.get_num_segments (); - if (expr.get_num_segments () == 1) { Location locus = expr.get_segments ().back ().get_locus (); @@ -957,112 +1027,8 @@ public: return; } - TyTy::BaseType *prev_segment = tyseg; - for (size_t i = offset; i < expr.get_num_segments (); i++) - { - HIR::PathExprSegment &seg = expr.get_segments ().at (i); - - bool reciever_is_generic - = prev_segment->get_kind () == TyTy::TypeKind::PARAM; - bool probe_bounds = true; - bool probe_impls = !reciever_is_generic; - bool ignore_mandatory_trait_items = !reciever_is_generic; - - // probe the path - auto candidates - = PathProbeType::Probe (tyseg, seg.get_segment (), probe_impls, - probe_bounds, ignore_mandatory_trait_items); - if (candidates.size () == 0) - { - rust_error_at ( - seg.get_locus (), - "failed to resolve path segment using an impl Probe"); - return; - } - else if (candidates.size () > 1) - { - ReportMultipleCandidateError::Report (candidates, - seg.get_segment (), - seg.get_locus ()); - return; - } - - auto &candidate = candidates.at (0); - prev_segment = tyseg; - tyseg = candidate.ty; - - if (candidate.is_impl_candidate ()) - { - resolved_node_id - = candidate.item.impl.impl_item->get_impl_mappings () - .get_nodeid (); - } - else - { - resolved_node_id - = candidate.item.trait.item_ref->get_mappings ().get_nodeid (); - } - - if (seg.has_generic_args ()) - { - if (!tyseg->can_substitute ()) - { - rust_error_at (expr.get_locus (), - "substitutions not supported for %s", - tyseg->as_string ().c_str ()); - return; - } - - tyseg = SubstMapper::Resolve (tyseg, expr.get_locus (), - &seg.get_generic_args ()); - if (tyseg->get_kind () == TyTy::TypeKind::ERROR) - return; - } - } - - context->insert_receiver (expr.get_mappings ().get_hirid (), prev_segment); - if (tyseg->needs_generic_substitutions ()) - { - Location locus = expr.get_segments ().back ().get_locus (); - if (!prev_segment->needs_generic_substitutions ()) - { - auto used_args_in_prev_segment - = GetUsedSubstArgs::From (prev_segment); - if (!used_args_in_prev_segment.is_error ()) - tyseg = SubstMapperInternal::Resolve (tyseg, - used_args_in_prev_segment); - } - else - { - tyseg = SubstMapper::InferSubst (tyseg, locus); - } - - if (tyseg->get_kind () == TyTy::TypeKind::ERROR) - return; - } - - rust_assert (resolved_node_id != UNKNOWN_NODEID); - - // lookup if the name resolver was able to canonically resolve this or not - NodeId path_resolved_id = UNKNOWN_NODEID; - if (resolver->lookup_resolved_name (expr.get_mappings ().get_nodeid (), - &path_resolved_id)) - { - rust_assert (path_resolved_id == resolved_node_id); - } - // check the type scope - else if (resolver->lookup_resolved_type (expr.get_mappings ().get_nodeid (), - &path_resolved_id)) - { - rust_assert (path_resolved_id == resolved_node_id); - } - else if (!name_resolved_fully) - { - resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (), - resolved_node_id); - } - - infered = tyseg; + resolve_segments (resolved_node_id, expr.get_segments (), offset, tyseg, + expr.get_mappings (), expr.get_locus ()); } void visit (HIR::LoopExpr &expr) override @@ -1353,6 +1319,120 @@ private: return root_tyty; } + void resolve_segments (NodeId root_resolved_node_id, + std::vector<HIR::PathExprSegment> &segments, + size_t offset, TyTy::BaseType *tyseg, + const Analysis::NodeMapping &expr_mappings, + Location expr_locus) + { + NodeId resolved_node_id = root_resolved_node_id; + TyTy::BaseType *prev_segment = tyseg; + for (size_t i = offset; i < segments.size (); i++) + { + HIR::PathExprSegment &seg = segments.at (i); + + bool reciever_is_generic + = prev_segment->get_kind () == TyTy::TypeKind::PARAM; + bool probe_bounds = true; + bool probe_impls = !reciever_is_generic; + bool ignore_mandatory_trait_items = !reciever_is_generic; + + // probe the path + auto candidates + = PathProbeType::Probe (prev_segment, seg.get_segment (), probe_impls, + probe_bounds, ignore_mandatory_trait_items); + if (candidates.size () == 0) + { + rust_error_at ( + seg.get_locus (), + "failed to resolve path segment using an impl Probe"); + return; + } + else if (candidates.size () > 1) + { + ReportMultipleCandidateError::Report (candidates, + seg.get_segment (), + seg.get_locus ()); + return; + } + + auto &candidate = candidates.at (0); + prev_segment = tyseg; + tyseg = candidate.ty; + + if (candidate.is_impl_candidate ()) + { + resolved_node_id + = candidate.item.impl.impl_item->get_impl_mappings () + .get_nodeid (); + } + else + { + resolved_node_id + = candidate.item.trait.item_ref->get_mappings ().get_nodeid (); + } + + if (seg.has_generic_args ()) + { + if (!tyseg->can_substitute ()) + { + rust_error_at (expr_locus, "substitutions not supported for %s", + tyseg->as_string ().c_str ()); + return; + } + + tyseg = SubstMapper::Resolve (tyseg, expr_locus, + &seg.get_generic_args ()); + if (tyseg->get_kind () == TyTy::TypeKind::ERROR) + return; + } + } + + context->insert_receiver (expr_mappings.get_hirid (), prev_segment); + if (tyseg->needs_generic_substitutions ()) + { + Location locus = segments.back ().get_locus (); + if (!prev_segment->needs_generic_substitutions ()) + { + auto used_args_in_prev_segment + = GetUsedSubstArgs::From (prev_segment); + if (!used_args_in_prev_segment.is_error ()) + tyseg = SubstMapperInternal::Resolve (tyseg, + used_args_in_prev_segment); + } + else + { + tyseg = SubstMapper::InferSubst (tyseg, locus); + } + + if (tyseg->get_kind () == TyTy::TypeKind::ERROR) + return; + } + + rust_assert (resolved_node_id != UNKNOWN_NODEID); + + // lookup if the name resolver was able to canonically resolve this or not + NodeId path_resolved_id = UNKNOWN_NODEID; + if (resolver->lookup_resolved_name (expr_mappings.get_nodeid (), + &path_resolved_id)) + { + rust_assert (path_resolved_id == resolved_node_id); + } + // check the type scope + else if (resolver->lookup_resolved_type (expr_mappings.get_nodeid (), + &path_resolved_id)) + { + rust_assert (path_resolved_id == resolved_node_id); + } + else + { + resolver->insert_resolved_name (expr_mappings.get_nodeid (), + resolved_node_id); + } + + infered = tyseg; + } + bool validate_arithmetic_type (TyTy::BaseType *type, HIR::ArithmeticOrLogicalExpr::ExprType expr_type) |