aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/rust/resolve/rust-late-name-resolver-2.0.cc')
-rw-r--r--gcc/rust/resolve/rust-late-name-resolver-2.0.cc300
1 files changed, 261 insertions, 39 deletions
diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
index f743e1e..e39ca15 100644
--- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
@@ -19,6 +19,7 @@
#include "optional.h"
#include "rust-ast-full.h"
#include "rust-diagnostics.h"
+#include "rust-expr.h"
#include "rust-hir-map.h"
#include "rust-late-name-resolver-2.0.h"
#include "rust-default-resolver.h"
@@ -33,7 +34,9 @@
namespace Rust {
namespace Resolver2_0 {
-Late::Late (NameResolutionContext &ctx) : DefaultResolver (ctx) {}
+Late::Late (NameResolutionContext &ctx)
+ : DefaultResolver (ctx), funny_error (false), block_big_self (false)
+{}
static NodeId
next_node_id ()
@@ -114,8 +117,7 @@ Late::go (AST::Crate &crate)
{
setup_builtin_types ();
- for (auto &item : crate.items)
- item->accept_vis (*this);
+ visit (crate);
}
void
@@ -129,6 +131,51 @@ Late::new_label (Identifier name, NodeId id)
}
void
+Late::visit (AST::ForLoopExpr &expr)
+{
+ visit_outer_attrs (expr);
+
+ ctx.bindings.enter (BindingSource::For);
+
+ visit (expr.get_pattern ());
+
+ ctx.bindings.exit ();
+
+ visit (expr.get_iterator_expr ());
+
+ if (expr.has_loop_label ())
+ visit (expr.get_loop_label ());
+
+ visit (expr.get_loop_block ());
+}
+
+void
+Late::visit_if_let_patterns (AST::IfLetExpr &expr)
+{
+ ctx.bindings.enter (BindingSource::IfLet);
+
+ DefaultResolver::visit_if_let_patterns (expr);
+
+ ctx.bindings.exit ();
+}
+
+void
+Late::visit (AST::MatchArm &arm)
+{
+ visit_outer_attrs (arm);
+
+ ctx.bindings.enter (BindingSource::Match);
+
+ for (auto &pattern : arm.get_patterns ())
+ visit (pattern);
+
+ ctx.bindings.exit ();
+
+ if (arm.has_match_arm_guard ())
+ visit (arm.get_guard_expr ());
+}
+
+void
Late::visit (AST::LetStmt &let)
{
DefaultASTVisitor::visit_outer_attrs (let);
@@ -138,8 +185,13 @@ Late::visit (AST::LetStmt &let)
// this makes variable shadowing work properly
if (let.has_init_expr ())
visit (let.get_init_expr ());
+
+ ctx.bindings.enter (BindingSource::Let);
+
visit (let.get_pattern ());
+ ctx.bindings.exit ();
+
if (let.has_else_expr ())
visit (let.get_init_expr ());
@@ -161,15 +213,109 @@ Late::visit (AST::LetStmt &let)
}
void
-Late::visit (AST::IdentifierPattern &identifier)
+Late::visit (AST::WhileLetLoopExpr &while_let)
+{
+ DefaultASTVisitor::visit_outer_attrs (while_let);
+
+ if (while_let.has_loop_label ())
+ visit (while_let.get_loop_label ());
+
+ // visit expression before pattern
+ // this makes variable shadowing work properly
+ visit (while_let.get_scrutinee_expr ());
+
+ ctx.bindings.enter (BindingSource::WhileLet);
+
+ for (auto &pattern : while_let.get_patterns ())
+ visit (pattern);
+
+ ctx.bindings.exit ();
+
+ visit (while_let.get_loop_block ());
+}
+
+static void
+visit_identifier_as_pattern (NameResolutionContext &ctx,
+ const Identifier &ident, location_t locus,
+ NodeId node_id, bool is_ref, bool is_mut)
{
// do we insert in labels or in values
// but values does not allow shadowing... since functions cannot shadow
// do we insert functions in labels as well?
- // We do want to ignore duplicated data because some situations rely on it.
- std::ignore = ctx.values.insert_shadowable (identifier.get_ident (),
- identifier.get_node_id ());
+ if (ctx.bindings.peek ().is_and_bound (ident))
+ {
+ if (ctx.bindings.peek ().get_source () == BindingSource::Param)
+ rust_error_at (
+ locus, ErrorCode::E0415,
+ "identifier %qs is bound more than once in the same parameter list",
+ ident.as_string ().c_str ());
+ else
+ rust_error_at (
+ locus, ErrorCode::E0416,
+ "identifier %qs is bound more than once in the same pattern",
+ ident.as_string ().c_str ());
+ return;
+ }
+
+ ctx.bindings.peek ().insert_ident (ident.as_string (), locus, is_ref, is_mut);
+
+ if (ctx.bindings.peek ().is_or_bound (ident))
+ {
+ auto res = ctx.values.get (ident);
+ rust_assert (res.has_value () && !res->is_ambiguous ());
+ ctx.map_usage (Usage (node_id), Definition (res->get_node_id ()));
+ }
+ else
+ {
+ // We do want to ignore duplicated data because some situations rely on
+ // it.
+ std::ignore = ctx.values.insert_shadowable (ident, node_id);
+ }
+}
+
+void
+Late::visit (AST::IdentifierPattern &identifier)
+{
+ DefaultResolver::visit (identifier);
+
+ visit_identifier_as_pattern (ctx, identifier.get_ident (),
+ identifier.get_locus (),
+ identifier.get_node_id (),
+ identifier.get_is_ref (),
+ identifier.get_is_mut ());
+}
+
+void
+Late::visit (AST::AltPattern &pattern)
+{
+ ctx.bindings.peek ().push (Binding::Kind::Or);
+ for (auto &alt : pattern.get_alts ())
+ {
+ ctx.bindings.peek ().push (Binding::Kind::Product);
+ visit (alt);
+ ctx.bindings.peek ().merge ();
+ }
+ ctx.bindings.peek ().merge ();
+}
+
+void
+Late::visit_function_params (AST::Function &function)
+{
+ ctx.bindings.enter (BindingSource::Param);
+
+ for (auto &param : function.get_function_params ())
+ visit (param);
+
+ ctx.bindings.exit ();
+}
+
+void
+Late::visit (AST::StructPatternFieldIdent &field)
+{
+ visit_identifier_as_pattern (ctx, field.get_identifier (), field.get_locus (),
+ field.get_node_id (), field.is_ref (),
+ field.is_mut ());
}
void
@@ -263,8 +409,9 @@ Late::visit (AST::IdentifierExpr &expr)
}
else if (funny_error)
{
- diagnostic_text_finalizer (global_dc) = Resolver::funny_ice_text_finalizer;
- emit_diagnostic (DK_ICE_NOBT, expr.get_locus (), -1,
+ diagnostics::text_finalizer (global_dc)
+ = Resolver::funny_ice_text_finalizer;
+ emit_diagnostic (diagnostics::kind::ice_nobt, expr.get_locus (), -1,
"are you trying to break %s? how dare you?",
expr.as_string ().c_str ());
}
@@ -347,8 +494,8 @@ Late::visit (AST::PathInExpression &expr)
if (!resolved)
{
if (!ctx.lookup (expr.get_segments ().front ().get_node_id ()))
- rust_error_at (expr.get_locus (),
- "could not resolve path expression: %qs",
+ rust_error_at (expr.get_locus (), ErrorCode::E0433,
+ "Cannot find path %qs in this scope",
expr.as_simple_path ().as_string ().c_str ());
return;
}
@@ -365,6 +512,16 @@ Late::visit (AST::PathInExpression &expr)
}
void
+Late::visit_impl_type (AST::Type &type)
+{
+ // TODO: does this have to handle reentrancy?
+ rust_assert (!block_big_self);
+ block_big_self = true;
+ visit (type);
+ block_big_self = false;
+}
+
+void
Late::visit (AST::TypePath &type)
{
// should we add type path resolution in `ForeverStack` directly? Since it's
@@ -374,6 +531,16 @@ Late::visit (AST::TypePath &type)
DefaultResolver::visit (type);
+ // prevent "impl Self {}" and similar
+ if (type.get_segments ().size () == 1
+ && !type.get_segments ().front ()->is_lang_item ()
+ && type.get_segments ().front ()->is_big_self_seg () && block_big_self)
+ {
+ rust_error_at (type.get_locus (),
+ "%<Self%> is not valid in the self type of an impl block");
+ return;
+ }
+
// this *should* mostly work
// TODO: make sure typepath-like path resolution (?) is working
auto resolved = ctx.resolve_path (type, Namespace::Types);
@@ -381,23 +548,88 @@ Late::visit (AST::TypePath &type)
if (!resolved.has_value ())
{
if (!ctx.lookup (type.get_segments ().front ()->get_node_id ()))
- rust_error_at (type.get_locus (), "could not resolve type path %qs",
- type.as_string ().c_str ());
+ rust_error_at (type.get_locus (), ErrorCode::E0412,
+ "could not resolve type path %qs",
+ type.make_debug_string ().c_str ());
return;
}
if (resolved->is_ambiguous ())
{
rust_error_at (type.get_locus (), ErrorCode::E0659, "%qs is ambiguous",
- type.as_string ().c_str ());
+ type.make_debug_string ().c_str ());
return;
}
+ if (ctx.types.forward_declared (resolved->get_node_id (),
+ type.get_node_id ()))
+ {
+ rust_error_at (type.get_locus (), ErrorCode::E0128,
+ "type parameters with a default cannot use forward "
+ "declared identifiers");
+ }
+
ctx.map_usage (Usage (type.get_node_id ()),
Definition (resolved->get_node_id ()));
}
void
+Late::visit (AST::Visibility &vis)
+{
+ if (!vis.has_path ())
+ return;
+
+ AST::SimplePath &path = vis.get_path ();
+
+ rust_assert (path.get_segments ().size ());
+ auto &first_seg = path.get_segments ()[0];
+
+ auto mode = ResolutionMode::Normal;
+
+ if (path.has_opening_scope_resolution ())
+ {
+ if (get_rust_edition () == Edition::E2015)
+ mode = ResolutionMode::FromRoot;
+ else
+ mode = ResolutionMode::FromExtern;
+ }
+ else if (!first_seg.is_crate_path_seg () && !first_seg.is_super_path_seg ()
+ && !first_seg.is_lower_self_seg ())
+ {
+ if (get_rust_edition () == Edition::E2015)
+ {
+ mode = ResolutionMode::FromRoot;
+ }
+ else
+ {
+ rust_error_at (path.get_locus (),
+ "relative paths are not supported in visibilities in "
+ "2018 edition or later");
+ return;
+ }
+ }
+
+ auto res = ctx.resolve_path (path.get_segments (), mode, Namespace::Types);
+
+ if (!res.has_value ())
+ {
+ rust_error_at (path.get_locus (), ErrorCode::E0433,
+ "could not resolve path %qs", path.as_string ().c_str ());
+ return;
+ }
+
+ // TODO: is this possible?
+ if (res->is_ambiguous ())
+ {
+ rust_error_at (path.get_locus (), ErrorCode::E0659, "%qs is ambiguous",
+ path.as_string ().c_str ());
+ return;
+ }
+
+ ctx.map_usage (Usage (path.get_node_id ()), Definition (res->get_node_id ()));
+}
+
+void
Late::visit (AST::Trait &trait)
{
// kind of weird how this is done
@@ -411,13 +643,6 @@ Late::visit (AST::Trait &trait)
}
void
-Late::visit (AST::StructStruct &s)
-{
- auto s_vis = [this, &s] () { AST::DefaultASTVisitor::visit (s); };
- ctx.scoped (Rib::Kind::Item, s.get_node_id (), s_vis);
-}
-
-void
Late::visit (AST::StructExprStruct &s)
{
visit_outer_attrs (s);
@@ -493,30 +718,27 @@ Late::visit (AST::GenericArg &arg)
DefaultResolver::visit (arg);
}
-template <class Closure>
-static void
-add_captures (Closure &closure, NameResolutionContext &ctx)
-{
- auto vals = ctx.values.peek ().get_values ();
- for (auto &val : vals)
- {
- ctx.mappings.add_capture (closure.get_node_id (),
- val.second.get_node_id ());
- }
-}
-
void
-Late::visit (AST::ClosureExprInner &closure)
+Late::visit_closure_params (AST::ClosureExpr &closure)
{
- add_captures (closure, ctx);
- DefaultResolver::visit (closure);
+ ctx.bindings.enter (BindingSource::Param);
+
+ DefaultResolver::visit_closure_params (closure);
+
+ ctx.bindings.exit ();
}
void
-Late::visit (AST::ClosureExprInnerTyped &closure)
+Late::visit (AST::ClosureExpr &expr)
{
- add_captures (closure, ctx);
- DefaultResolver::visit (closure);
+ // add captures
+ auto vals = ctx.values.peek ().get_values ();
+ for (auto &val : vals)
+ {
+ ctx.mappings.add_capture (expr.get_node_id (), val.second.get_node_id ());
+ }
+
+ DefaultResolver::visit (expr);
}
} // namespace Resolver2_0