aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2021-08-15 01:12:54 +0100
committerPhilip Herron <philip.herron@embecosm.com>2021-08-19 15:39:18 +0100
commitc25cdc84600e81bfd4d1ae104ff9eb524f7c49f0 (patch)
treed0b5d1437673ce5bd051aa21f75b0f5d20a9c934 /gcc
parentfe9dd83b41346fa667c693e5dd10dc9fe80e93b3 (diff)
downloadgcc-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.h12
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.h300
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)