aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2021-08-14 18:19:06 +0100
committerPhilip Herron <philip.herron@embecosm.com>2021-08-19 15:30:19 +0100
commit3475f10cbf58ff748298be438a4bf8cf98fec4ab (patch)
treeb8d15877eb5f6790d4a382acb66746c10fab2a04
parent71cf0d44d3fceb235c95d5acaf92b498f8cf923b (diff)
downloadgcc-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.h17
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-expr.h17
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-toplevel.h13
-rw-r--r--gcc/rust/resolve/rust-ast-resolve.cc117
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});
}
}