diff options
author | Philip Herron <philip.herron@embecosm.com> | 2021-08-14 18:19:06 +0100 |
---|---|---|
committer | Philip Herron <philip.herron@embecosm.com> | 2021-08-19 15:30:19 +0100 |
commit | 3475f10cbf58ff748298be438a4bf8cf98fec4ab (patch) | |
tree | b8d15877eb5f6790d4a382acb66746c10fab2a04 | |
parent | 71cf0d44d3fceb235c95d5acaf92b498f8cf923b (diff) | |
download | gcc-3475f10cbf58ff748298be438a4bf8cf98fec4ab.zip gcc-3475f10cbf58ff748298be438a4bf8cf98fec4ab.tar.gz gcc-3475f10cbf58ff748298be438a4bf8cf98fec4ab.tar.bz2 |
Add QualifiedPathInExpression name resolution
Qualified paths such as: <Foo as Bar>::A give the ability to resolve to
trait-impls or trait-items directly. It is a type of projection.
Remember trait impl blocks have the relevant canonical path so we can
resolve with canonical paths and reuse the existing path in expression
code.
-rw-r--r-- | gcc/rust/ast/rust-path.h | 17 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-expr.h | 17 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-toplevel.h | 13 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve.cc | 117 |
4 files changed, 143 insertions, 21 deletions
diff --git a/gcc/rust/ast/rust-path.h b/gcc/rust/ast/rust-path.h index 011ac3e..74ea795 100644 --- a/gcc/rust/ast/rust-path.h +++ b/gcc/rust/ast/rust-path.h @@ -771,11 +771,9 @@ struct QualifiedPathType { private: std::unique_ptr<Type> type_to_invoke_on; - - // bool has_as_clause; TypePath trait_path; - Location locus; + NodeId node_id; public: // Constructor @@ -783,13 +781,15 @@ public: Location locus = Location (), TypePath trait_path = TypePath::create_error ()) : type_to_invoke_on (std::move (invoke_on_type)), - trait_path (std::move (trait_path)), locus (locus) + trait_path (std::move (trait_path)), locus (locus), + node_id (Analysis::Mappings::get ()->get_next_node_id ()) {} // Copy constructor uses custom deep copy for Type to preserve polymorphism QualifiedPathType (QualifiedPathType const &other) : trait_path (other.trait_path), locus (other.locus) { + node_id = other.node_id; // guard to prevent null dereference if (other.type_to_invoke_on != nullptr) type_to_invoke_on = other.type_to_invoke_on->clone_type (); @@ -801,6 +801,7 @@ public: // overload assignment operator to use custom clone method QualifiedPathType &operator= (QualifiedPathType const &other) { + node_id = other.node_id; trait_path = other.trait_path; locus = other.locus; @@ -846,6 +847,8 @@ public: rust_assert (has_as_clause ()); return trait_path; } + + NodeId get_node_id () const { return node_id; } }; /* AST node representing a qualified path-in-expression pattern (path that @@ -855,6 +858,7 @@ class QualifiedPathInExpression : public PathPattern, public PathExpr std::vector<Attribute> outer_attrs; QualifiedPathType path_type; Location locus; + NodeId _node_id; public: std::string as_string () const override; @@ -864,7 +868,8 @@ public: std::vector<Attribute> outer_attrs, Location locus) : PathPattern (std::move (path_segments)), outer_attrs (std::move (outer_attrs)), - path_type (std::move (qual_path_type)), locus (locus) + path_type (std::move (qual_path_type)), locus (locus), + _node_id (Analysis::Mappings::get ()->get_next_node_id ()) {} /* TODO: maybe make a shortcut constructor that has QualifiedPathType elements @@ -907,6 +912,8 @@ public: outer_attrs = std::move (new_attrs); } + NodeId get_node_id () const override { return _node_id; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h index e7e37d4..c5f88f9 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.h +++ b/gcc/rust/resolve/rust-ast-resolve-expr.h @@ -39,10 +39,22 @@ public: resolver.resolve_path (expr); } + static void go (AST::QualifiedPathInExpression *expr, NodeId parent) + { + ResolvePath resolver (parent); + resolver.resolve_path (expr); + } + private: ResolvePath (NodeId parent) : ResolverBase (parent) {} void resolve_path (AST::PathInExpression *expr); + + void resolve_path (AST::QualifiedPathInExpression *expr); + + void resolve_segments (CanonicalPath prefix, size_t offs, + std::vector<AST::PathExprSegment> &segs, + NodeId expr_node_id, Location expr_locus); }; class ResolveExpr : public ResolverBase @@ -75,6 +87,11 @@ public: ResolvePath::go (&expr, parent); } + void visit (AST::QualifiedPathInExpression &expr) override + { + ResolvePath::go (&expr, parent); + } + void visit (AST::ReturnExpr &expr) override { if (expr.has_returned_expr ()) diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h b/gcc/rust/resolve/rust-ast-resolve-toplevel.h index 2c1de66..1239206 100644 --- a/gcc/rust/resolve/rust-ast-resolve-toplevel.h +++ b/gcc/rust/resolve/rust-ast-resolve-toplevel.h @@ -206,6 +206,19 @@ public: impl_type_seg); CanonicalPath impl_prefix = prefix.append (projection); + resolver->get_name_scope ().insert ( + impl_prefix, impl_block.get_node_id (), impl_block.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (impl_block.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + resolver->insert_new_definition (impl_block.get_node_id (), + Definition{impl_block.get_node_id (), + impl_block.get_node_id ()}); + resolver->insert_resolved_name (impl_block.get_node_id (), + impl_block.get_node_id ()); + for (auto &impl_item : impl_block.get_impl_items ()) ResolveToplevelImplItem::go (impl_item.get (), impl_prefix); } diff --git a/gcc/rust/resolve/rust-ast-resolve.cc b/gcc/rust/resolve/rust-ast-resolve.cc index 5b24816..5b6bb24 100644 --- a/gcc/rust/resolve/rust-ast-resolve.cc +++ b/gcc/rust/resolve/rust-ast-resolve.cc @@ -483,12 +483,13 @@ void ResolvePath::resolve_path (AST::PathInExpression *expr) { // resolve root segment first then apply segments in turn - AST::PathExprSegment &root_segment = expr->get_segments ().at (0); + std::vector<AST::PathExprSegment> &segs = expr->get_segments (); + AST::PathExprSegment &root_segment = segs.at (0); AST::PathIdentSegment &root_ident_seg = root_segment.get_ident_segment (); bool segment_is_type = false; CanonicalPath root_seg_path - = CanonicalPath::new_seg (expr->get_node_id (), + = CanonicalPath::new_seg (root_segment.get_node_id (), root_ident_seg.as_string ()); // name scope first @@ -515,7 +516,7 @@ ResolvePath::resolve_path (AST::PathInExpression *expr) { rust_error_at (expr->get_locus (), "Cannot find path %<%s%> in this scope", - expr->as_string ().c_str ()); + root_segment.as_string ().c_str ()); return; } @@ -531,7 +532,8 @@ ResolvePath::resolve_path (AST::PathInExpression *expr) } } - if (expr->is_single_segment ()) + bool is_single_segment = segs.size () == 1; + if (is_single_segment) { if (segment_is_type) resolver->insert_resolved_type (expr->get_node_id (), resolved_node); @@ -544,11 +546,97 @@ ResolvePath::resolve_path (AST::PathInExpression *expr) return; } + resolve_segments (root_seg_path, 1, expr->get_segments (), + expr->get_node_id (), expr->get_locus ()); +} + +void +ResolvePath::resolve_path (AST::QualifiedPathInExpression *expr) +{ + AST::QualifiedPathType &root_segment = expr->get_qualified_path_type (); + + bool canonicalize_type_with_generics = false; + ResolveType::go (&root_segment.get_as_type_path (), + root_segment.get_node_id (), + canonicalize_type_with_generics); + + ResolveType::go (root_segment.get_type ().get (), root_segment.get_node_id (), + canonicalize_type_with_generics); + + bool canonicalize_type_args = true; + bool type_resolve_generic_args = true; + + CanonicalPath impl_type_seg + = ResolveTypeToCanonicalPath::resolve (*root_segment.get_type ().get (), + canonicalize_type_args, + type_resolve_generic_args); + + CanonicalPath trait_type_seg + = ResolveTypeToCanonicalPath::resolve (root_segment.get_as_type_path (), + canonicalize_type_args, + type_resolve_generic_args); + CanonicalPath root_seg_path + = TraitImplProjection::resolve (root_segment.get_node_id (), trait_type_seg, + impl_type_seg); + bool segment_is_type = false; + + // name scope first + if (resolver->get_name_scope ().lookup (root_seg_path, &resolved_node)) + { + segment_is_type = false; + resolver->insert_resolved_name (root_segment.get_node_id (), + resolved_node); + resolver->insert_new_definition (root_segment.get_node_id (), + Definition{expr->get_node_id (), + parent}); + } + // check the type scope + else if (resolver->get_type_scope ().lookup (root_seg_path, &resolved_node)) + { + segment_is_type = true; + resolver->insert_resolved_type (root_segment.get_node_id (), + resolved_node); + resolver->insert_new_definition (root_segment.get_node_id (), + Definition{expr->get_node_id (), + parent}); + } + else + { + rust_error_at (expr->get_locus (), + "Cannot find path %<%s%> in this scope", + root_segment.as_string ().c_str ()); + return; + } + + bool is_single_segment = expr->get_segments ().empty (); + if (is_single_segment) + { + if (segment_is_type) + resolver->insert_resolved_type (expr->get_node_id (), resolved_node); + else + resolver->insert_resolved_name (expr->get_node_id (), resolved_node); + + resolver->insert_new_definition (expr->get_node_id (), + Definition{expr->get_node_id (), + parent}); + return; + } + + resolve_segments (root_seg_path, 0, expr->get_segments (), + expr->get_node_id (), expr->get_locus ()); +} + +void +ResolvePath::resolve_segments (CanonicalPath prefix, size_t offs, + std::vector<AST::PathExprSegment> &segs, + NodeId expr_node_id, Location expr_locus) +{ // we can attempt to resolve this path fully - CanonicalPath path = root_seg_path; - for (size_t i = 1; i < expr->get_segments ().size (); i++) + CanonicalPath path = prefix; + bool segment_is_type = false; + for (size_t i = offs; i < segs.size (); i++) { - AST::PathExprSegment &seg = expr->get_segments ().at (i); + AST::PathExprSegment &seg = segs.at (i); auto s = ResolvePathSegmentToCanonicalPath::resolve (seg); path = path.append (s); @@ -560,8 +648,7 @@ ResolvePath::resolve_path (AST::PathInExpression *expr) { resolver->insert_resolved_name (seg.get_node_id (), resolved_node); resolver->insert_new_definition (seg.get_node_id (), - Definition{expr->get_node_id (), - parent}); + Definition{expr_node_id, parent}); } // check the type scope else if (resolver->get_type_scope ().lookup (path, &resolved_node)) @@ -569,8 +656,7 @@ ResolvePath::resolve_path (AST::PathInExpression *expr) segment_is_type = true; resolver->insert_resolved_type (seg.get_node_id (), resolved_node); resolver->insert_new_definition (seg.get_node_id (), - Definition{expr->get_node_id (), - parent}); + Definition{expr_node_id, parent}); } else { @@ -621,13 +707,12 @@ ResolvePath::resolve_path (AST::PathInExpression *expr) if (resolved_node != UNKNOWN_NODEID) { if (segment_is_type) - resolver->insert_resolved_type (expr->get_node_id (), resolved_node); + resolver->insert_resolved_type (expr_node_id, resolved_node); else - resolver->insert_resolved_name (expr->get_node_id (), resolved_node); + resolver->insert_resolved_name (expr_node_id, resolved_node); - resolver->insert_new_definition (expr->get_node_id (), - Definition{expr->get_node_id (), - parent}); + resolver->insert_new_definition (expr_node_id, + Definition{expr_node_id, parent}); } } |