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 /gcc | |
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.
Diffstat (limited to 'gcc')
-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}); } } |