aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/resolve
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/rust/resolve')
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-base.cc5
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-base.h6
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-expr.cc165
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-expr.h5
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-implitem.h19
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-item.cc110
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-path.cc225
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-pattern.cc3
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-stmt.cc21
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-stmt.h56
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-toplevel.h53
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-type.cc302
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-type.h152
-rw-r--r--gcc/rust/resolve/rust-ast-resolve.cc7
-rw-r--r--gcc/rust/resolve/rust-default-resolver.cc577
-rw-r--r--gcc/rust/resolve/rust-default-resolver.h129
-rw-r--r--gcc/rust/resolve/rust-early-name-resolver-2.0.cc264
-rw-r--r--gcc/rust/resolve/rust-early-name-resolver-2.0.h168
-rw-r--r--gcc/rust/resolve/rust-early-name-resolver.cc46
-rw-r--r--gcc/rust/resolve/rust-early-name-resolver.h7
-rw-r--r--gcc/rust/resolve/rust-finalize-imports-2.0.cc129
-rw-r--r--gcc/rust/resolve/rust-finalize-imports-2.0.h53
-rw-r--r--gcc/rust/resolve/rust-forever-stack.cc318
-rw-r--r--gcc/rust/resolve/rust-forever-stack.h266
-rw-r--r--gcc/rust/resolve/rust-forever-stack.hxx494
-rw-r--r--gcc/rust/resolve/rust-ice-finalizer.cc36
-rw-r--r--gcc/rust/resolve/rust-ice-finalizer.h65
-rw-r--r--gcc/rust/resolve/rust-late-name-resolver-2.0.cc489
-rw-r--r--gcc/rust/resolve/rust-late-name-resolver-2.0.h25
-rw-r--r--gcc/rust/resolve/rust-name-resolution-context.cc104
-rw-r--r--gcc/rust/resolve/rust-name-resolution-context.h190
-rw-r--r--gcc/rust/resolve/rust-name-resolver.cc32
-rw-r--r--gcc/rust/resolve/rust-name-resolver.h42
-rw-r--r--gcc/rust/resolve/rust-rib.cc118
-rw-r--r--gcc/rust/resolve/rust-rib.h80
-rw-r--r--gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc499
-rw-r--r--gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h154
37 files changed, 3809 insertions, 1605 deletions
diff --git a/gcc/rust/resolve/rust-ast-resolve-base.cc b/gcc/rust/resolve/rust-ast-resolve-base.cc
index 69f146c..b781ce33 100644
--- a/gcc/rust/resolve/rust-ast-resolve-base.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-base.cc
@@ -20,6 +20,7 @@
#include "rust-ast-resolve-expr.h"
#include "rust-ast-resolve-path.h"
#include "rust-item.h"
+#include "rust-path.h"
namespace Rust {
namespace Resolver {
@@ -327,6 +328,10 @@ ResolverBase::visit (AST::InlineAsm &)
{}
void
+ResolverBase::visit (AST::LlvmInlineAsm &)
+{}
+
+void
ResolverBase::visit (AST::TypeParam &)
{}
diff --git a/gcc/rust/resolve/rust-ast-resolve-base.h b/gcc/rust/resolve/rust-ast-resolve-base.h
index 0d497f8..5bb9e4f 100644
--- a/gcc/rust/resolve/rust-ast-resolve-base.h
+++ b/gcc/rust/resolve/rust-ast-resolve-base.h
@@ -27,6 +27,11 @@
namespace Rust {
namespace Resolver {
+inline void
+redefined_error (const rich_location &loc)
+{
+ rust_error_at (loc, "redefined multiple times");
+}
class ResolverBase : public AST::ASTVisitor
{
@@ -105,6 +110,7 @@ public:
void visit (AST::AwaitExpr &);
void visit (AST::AsyncBlockExpr &);
void visit (AST::InlineAsm &);
+ void visit (AST::LlvmInlineAsm &);
void visit (AST::TypeParam &);
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.cc b/gcc/rust/resolve/rust-ast-resolve-expr.cc
index 44ba2a8..6242235 100644
--- a/gcc/rust/resolve/rust-ast-resolve-expr.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-expr.cc
@@ -22,7 +22,8 @@
#include "rust-ast-resolve-type.h"
#include "rust-ast-resolve-pattern.h"
#include "rust-ast-resolve-path.h"
-#include "diagnostic.h"
+#include "rust-expr.h"
+#include "rust-ice-finalizer.h"
namespace Rust {
namespace Resolver {
@@ -95,50 +96,16 @@ ResolveExpr::visit (AST::MethodCallExpr &expr)
}
void
-ResolveExpr::visit (AST::AssignmentExpr &expr)
+ResolveExpr::visit (AST::ErrorPropagationExpr &expr)
{
- ResolveExpr::go (expr.get_left_expr (), prefix, canonical_prefix);
- ResolveExpr::go (expr.get_right_expr (), prefix, canonical_prefix);
+ ResolveExpr::go (expr.get_propagating_expr (), prefix, canonical_prefix);
}
-/* The "break rust" Easter egg.
-
- Backstory: once upon a time, there used to be a bug in rustc: it would ICE
- during typechecking on a 'break' with an expression outside of a loop. The
- issue has been reported [0] and fixed [1], but in recognition of this, as a
- special Easter egg, "break rust" was made to intentionally cause an ICE.
-
- [0]: https://github.com/rust-lang/rust/issues/43162
- [1]: https://github.com/rust-lang/rust/pull/43745
-
- This was made in a way that does not break valid programs: namely, it only
- happens when the 'break' is outside of a loop (so invalid anyway).
-
- GCC Rust supports this essential feature as well, but in a slightly
- different way. Instead of delaying the error until type checking, we emit
- it here in the resolution phase. We, too, only do this to programs that
- are already invalid: we only emit our funny ICE if the name "rust" (which
- must be immediately inside a break-with-a-value expression) fails to
- resolve. Note that "break (rust)" does not trigger our ICE, only using
- "break rust" directly does, and only if there's no "rust" in scope. We do
- this in the same way regardless of whether the "break" is outside of a loop
- or inside one.
-
- As a GNU extension, we also support "break gcc", much to the same effect,
- subject to the same rules. */
-
-/* The finalizer for our funny ICE. This prints a custom message instead of
- the default bug reporting instructions, as there is no bug to report. */
-
-static void ATTRIBUTE_NORETURN
-funny_ice_text_finalizer (diagnostic_text_output_format &text_output,
- const diagnostic_info *diagnostic,
- diagnostic_t diag_kind)
+void
+ResolveExpr::visit (AST::AssignmentExpr &expr)
{
- gcc_assert (diag_kind == DK_ICE_NOBT);
- default_diagnostic_text_finalizer (text_output, diagnostic, diag_kind);
- fnotice (stderr, "You have broken GCC Rust. This is a feature.\n");
- exit (ICE_EXIT_CODE);
+ ResolveExpr::go (expr.get_left_expr (), prefix, canonical_prefix);
+ ResolveExpr::go (expr.get_right_expr (), prefix, canonical_prefix);
}
void
@@ -242,7 +209,7 @@ ResolveExpr::visit (AST::IfLetExpr &expr)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
// We know expr.get_patterns () has one pattern at most
// so there's no reason to handle it like an AltPattern.
@@ -272,7 +239,7 @@ ResolveExpr::visit (AST::IfLetExprConseqElse &expr)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
// We know expr.get_patterns () has one pattern at most
// so there's no reason to handle it like an AltPattern.
@@ -301,7 +268,7 @@ ResolveExpr::visit (AST::BlockExpr &expr)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
if (expr.has_label ())
{
@@ -320,7 +287,7 @@ ResolveExpr::visit (AST::BlockExpr &expr)
CanonicalPath::new_seg (label.get_node_id (), label_name),
label_lifetime_node_id, label.get_locus (), false, Rib::ItemType::Label,
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
- rust_error_at (label.get_locus (), "label redefined multiple times");
+ rust_error_at (label.get_locus (), "label defined multiple times");
rust_error_at (locus, "was defined here");
});
}
@@ -348,6 +315,71 @@ ResolveExpr::visit (AST::BlockExpr &expr)
}
void
+translate_operand (AST::InlineAsm &expr, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+{
+ const auto &operands = expr.get_operands ();
+ using RegisterType = AST::InlineAsmOperand::RegisterType;
+ for (auto &operand : operands)
+ {
+ switch (operand.get_register_type ())
+ {
+ case RegisterType::In: {
+ auto in = operand.get_in ();
+ ResolveExpr::go (*in.expr, prefix, canonical_prefix);
+ break;
+ }
+ case RegisterType::Out: {
+ auto out = operand.get_out ();
+ ResolveExpr::go (*out.expr, prefix, canonical_prefix);
+ break;
+ }
+ case RegisterType::InOut: {
+ auto in_out = operand.get_in_out ();
+ ResolveExpr::go (*in_out.expr, prefix, canonical_prefix);
+ break;
+ }
+ case RegisterType::SplitInOut: {
+ auto split_in_out = operand.get_split_in_out ();
+ ResolveExpr::go (*split_in_out.in_expr, prefix, canonical_prefix);
+ ResolveExpr::go (*split_in_out.out_expr, prefix, canonical_prefix);
+ break;
+ }
+ case RegisterType::Const: {
+ auto anon_const = operand.get_const ().anon_const;
+ ResolveExpr::go (*anon_const.expr, prefix, canonical_prefix);
+ break;
+ }
+ case RegisterType::Sym: {
+ auto sym = operand.get_sym ();
+ ResolveExpr::go (*sym.expr, prefix, canonical_prefix);
+ break;
+ }
+ case RegisterType::Label: {
+ auto label = operand.get_label ();
+ ResolveExpr::go (*label.expr, prefix, canonical_prefix);
+ break;
+ }
+ }
+ }
+}
+void
+ResolveExpr::visit (AST::InlineAsm &expr)
+{
+ translate_operand (expr, prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::LlvmInlineAsm &expr)
+{
+ for (auto &output : expr.get_outputs ())
+ ResolveExpr::go (*output.expr, prefix, canonical_prefix);
+
+ for (auto &input : expr.get_inputs ())
+ ResolveExpr::go (*input.expr, prefix, canonical_prefix);
+}
+
+void
ResolveExpr::visit (AST::UnsafeBlockExpr &expr)
{
expr.get_block_expr ().accept_vis (*this);
@@ -438,7 +470,7 @@ ResolveExpr::visit (AST::LoopExpr &expr)
CanonicalPath::new_seg (expr.get_node_id (), label_name),
label_lifetime_node_id, label.get_locus (), false, Rib::ItemType::Label,
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
- rust_error_at (label.get_locus (), "label redefined multiple times");
+ rust_error_at (label.get_locus (), "label defined multiple times");
rust_error_at (locus, "was defined here");
});
}
@@ -450,7 +482,7 @@ ResolveExpr::visit (AST::BreakExpr &expr)
{
if (expr.has_label ())
{
- auto label = expr.get_label ().get_lifetime ();
+ auto label = expr.get_label_unchecked ().get_lifetime ();
if (label.get_lifetime_type () != AST::Lifetime::LifetimeType::NAMED)
{
rust_error_at (label.get_locus (),
@@ -465,8 +497,8 @@ ResolveExpr::visit (AST::BreakExpr &expr)
&resolved_node))
{
rust_error_at (label.get_locus (), ErrorCode::E0426,
- "use of undeclared label %qs in %<break%>",
- label.get_lifetime_name ().c_str ());
+ "use of undeclared label %qs",
+ label.as_string ().c_str ());
return;
}
resolver->insert_resolved_label (label.get_node_id (), resolved_node);
@@ -476,14 +508,15 @@ ResolveExpr::visit (AST::BreakExpr &expr)
{
bool funny_error = false;
auto &break_expr = expr.get_break_expr ();
- if (break_expr.get_ast_kind () == AST::Kind::IDENTIFIER)
+ if (break_expr.get_expr_kind () == AST::Expr::Kind::Identifier)
{
- /* This is a break with an expression, and the expression is just a
- single identifier. See if the identifier is either "rust" or
- "gcc", in which case we have "break rust" or "break gcc", and so
- may need to emit our funny error. We cannot yet emit the error
- here though, because the identifier may still be in scope, and
- ICE'ing on valid programs would not be very funny. */
+ /* This is a break with an expression, and the expression is
+ just a single identifier. See if the identifier is either
+ "rust" or "gcc", in which case we have "break rust" or "break
+ gcc", and so may need to emit our funny error. We cannot yet
+ emit the error here though, because the identifier may still
+ be in scope, and ICE'ing on valid programs would not be very
+ funny. */
std::string ident
= static_cast<AST::IdentifierExpr &> (break_expr).as_string ();
if (ident == "rust" || ident == "gcc")
@@ -513,7 +546,7 @@ ResolveExpr::visit (AST::WhileLoopExpr &expr)
CanonicalPath::new_seg (label.get_node_id (), label_name),
label_lifetime_node_id, label.get_locus (), false, Rib::ItemType::Label,
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
- rust_error_at (label.get_locus (), "label redefined multiple times");
+ rust_error_at (label.get_locus (), "label defined multiple times");
rust_error_at (locus, "was defined here");
});
}
@@ -542,7 +575,7 @@ ResolveExpr::visit (AST::ForLoopExpr &expr)
CanonicalPath::new_seg (label.get_node_id (), label_name),
label_lifetime_node_id, label.get_locus (), false, Rib::ItemType::Label,
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
- rust_error_at (label.get_locus (), "label redefined multiple times");
+ rust_error_at (label.get_locus (), "label defined multiple times");
rust_error_at (locus, "was defined here");
});
}
@@ -554,7 +587,7 @@ ResolveExpr::visit (AST::ForLoopExpr &expr)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
// resolve the expression
PatternDeclaration::go (expr.get_pattern (), Rib::ItemType::Var);
@@ -572,7 +605,7 @@ ResolveExpr::visit (AST::ContinueExpr &expr)
{
if (expr.has_label ())
{
- auto label = expr.get_label ();
+ auto label = expr.get_label_unchecked ();
if (label.get_lifetime_type () != AST::Lifetime::LifetimeType::NAMED)
{
rust_error_at (label.get_locus (),
@@ -586,9 +619,9 @@ ResolveExpr::visit (AST::ContinueExpr &expr)
label.get_lifetime_name ()),
&resolved_node))
{
- rust_error_at (expr.get_label ().get_locus (), ErrorCode::E0426,
- "use of undeclared label %qs in %<continue%>",
- label.get_lifetime_name ().c_str ());
+ rust_error_at (expr.get_label_unchecked ().get_locus (),
+ ErrorCode::E0426, "use of undeclared label %qs",
+ label.as_string ().c_str ());
return;
}
resolver->insert_resolved_label (label.get_node_id (), resolved_node);
@@ -620,7 +653,7 @@ ResolveExpr::visit (AST::MatchExpr &expr)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
// resolve
AST::MatchArm &arm = match_case.get_arm ();
@@ -689,7 +722,7 @@ ResolveExpr::visit (AST::ClosureExprInner &expr)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
std::vector<PatternBinding> bindings
= {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())};
@@ -719,7 +752,7 @@ ResolveExpr::visit (AST::ClosureExprInnerTyped &expr)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
std::vector<PatternBinding> bindings
= {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())};
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h
index 75b07b8..b296d66 100644
--- a/gcc/rust/resolve/rust-ast-resolve-expr.h
+++ b/gcc/rust/resolve/rust-ast-resolve-expr.h
@@ -20,7 +20,9 @@
#define RUST_AST_RESOLVE_EXPR_H
#include "rust-ast-resolve-base.h"
+#include "rust-ast.h"
#include "rust-ast-resolve-pattern.h"
+#include "rust-expr.h"
namespace Rust {
namespace Resolver {
@@ -54,6 +56,8 @@ public:
void visit (AST::IfLetExpr &expr) override;
void visit (AST::IfLetExprConseqElse &expr) override;
void visit (AST::BlockExpr &expr) override;
+ void visit (AST::InlineAsm &expr) override;
+ void visit (AST::LlvmInlineAsm &expr) override;
void visit (AST::UnsafeBlockExpr &expr) override;
void visit (AST::ArrayElemsValues &elems) override;
void visit (AST::ArrayExpr &expr) override;
@@ -78,6 +82,7 @@ public:
void visit (AST::RangeFromToInclExpr &expr) override;
void visit (AST::ClosureExprInner &expr) override;
void visit (AST::ClosureExprInnerTyped &expr) override;
+ void visit (AST::ErrorPropagationExpr &expr) override;
protected:
void resolve_closure_param (AST::ClosureParam &param,
diff --git a/gcc/rust/resolve/rust-ast-resolve-implitem.h b/gcc/rust/resolve/rust-ast-resolve-implitem.h
index 2ca1296..2081697 100644
--- a/gcc/rust/resolve/rust-ast-resolve-implitem.h
+++ b/gcc/rust/resolve/rust-ast-resolve-implitem.h
@@ -51,7 +51,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, type.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
}
@@ -67,7 +67,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, constant.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
}
@@ -84,7 +84,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, function.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
}
@@ -124,7 +124,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, function.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
mappings.insert_canonical_path (function.get_node_id (), cpath);
@@ -144,7 +144,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, constant.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
mappings.insert_canonical_path (constant.get_node_id (), cpath);
@@ -162,7 +162,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, type.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
mappings.insert_canonical_path (type.get_node_id (), cpath);
@@ -202,7 +202,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, function.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId current_module = resolver->peek_current_module_scope ();
@@ -221,7 +221,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, item.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId current_module = resolver->peek_current_module_scope ();
@@ -239,8 +239,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, type.get_locus ());
r.add_range (locus);
-
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId current_module = resolver->peek_current_module_scope ();
diff --git a/gcc/rust/resolve/rust-ast-resolve-item.cc b/gcc/rust/resolve/rust-ast-resolve-item.cc
index 34098bc..30f6d43 100644
--- a/gcc/rust/resolve/rust-ast-resolve-item.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-item.cc
@@ -61,11 +61,11 @@ ResolveTraitItems::visit (AST::Function &function)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
if (function.has_generics ())
- for (auto &generic : function.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go (function.get_generic_params (), prefix,
+ canonical_prefix);
if (function.has_return_type ())
ResolveType::go (function.get_return_type ());
@@ -188,8 +188,8 @@ ResolveItem::visit (AST::TypeAlias &alias)
resolver->get_type_scope ().push (scope_node_id);
if (alias.has_generics ())
- for (auto &generic : alias.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go (alias.get_generic_params (), prefix,
+ canonical_prefix);
if (alias.has_where_clause ())
ResolveWhereClause::Resolve (alias.get_where_clause ());
@@ -216,7 +216,7 @@ ResolveItem::visit (AST::Module &module)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
// FIXME: Should we reinsert a child here? Any reason we ResolveTopLevel::go
// in ResolveTopLevel::visit (AST::Module) as well as here?
@@ -250,8 +250,8 @@ ResolveItem::visit (AST::TupleStruct &struct_decl)
resolver->get_type_scope ().push (scope_node_id);
if (struct_decl.has_generics ())
- for (auto &generic : struct_decl.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go (struct_decl.get_generic_params (), prefix,
+ canonical_prefix);
if (struct_decl.has_where_clause ())
ResolveWhereClause::Resolve (struct_decl.get_where_clause ());
@@ -284,8 +284,8 @@ ResolveItem::visit (AST::Enum &enum_decl)
resolver->get_type_scope ().push (scope_node_id);
if (enum_decl.has_generics ())
- for (auto &generic : enum_decl.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, cpath);
+ ResolveGenericParams::go (enum_decl.get_generic_params (), prefix,
+ canonical_prefix);
if (enum_decl.has_where_clause ())
ResolveWhereClause::Resolve (enum_decl.get_where_clause ());
@@ -356,6 +356,8 @@ ResolveItem::visit (AST::EnumItemDiscriminant &item)
auto cpath = canonical_prefix.append (decl);
mappings.insert_canonical_path (item.get_node_id (), cpath);
+
+ ResolveExpr::go (item.get_expr (), path, cpath);
}
void
@@ -374,8 +376,8 @@ ResolveItem::visit (AST::StructStruct &struct_decl)
resolver->get_type_scope ().push (scope_node_id);
if (struct_decl.has_generics ())
- for (auto &generic : struct_decl.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go (struct_decl.get_generic_params (), prefix,
+ canonical_prefix);
if (struct_decl.has_where_clause ())
ResolveWhereClause::Resolve (struct_decl.get_where_clause ());
@@ -409,8 +411,8 @@ ResolveItem::visit (AST::Union &union_decl)
resolver->get_type_scope ().push (scope_node_id);
if (union_decl.has_generics ())
- for (auto &generic : union_decl.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go (union_decl.get_generic_params (), prefix,
+ canonical_prefix);
if (union_decl.has_where_clause ())
ResolveWhereClause::Resolve (union_decl.get_where_clause ());
@@ -473,11 +475,11 @@ ResolveItem::visit (AST::Function &function)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
if (function.has_generics ())
- for (auto &generic : function.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go (function.get_generic_params (), prefix,
+ canonical_prefix);
// resolve any where clause items
if (function.has_where_clause ())
@@ -567,8 +569,8 @@ ResolveItem::visit (AST::InherentImpl &impl_block)
resolve_visibility (impl_block.get_visibility ());
if (impl_block.has_generics ())
- for (auto &generic : impl_block.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go (impl_block.get_generic_params (), prefix,
+ canonical_prefix);
// resolve any where clause items
if (impl_block.has_where_clause ())
@@ -582,7 +584,14 @@ ResolveItem::visit (AST::InherentImpl &impl_block)
// Setup paths
CanonicalPath self_cpath = CanonicalPath::create_empty ();
bool ok = ResolveTypeToCanonicalPath::go (impl_block.get_type (), self_cpath);
- rust_assert (ok);
+ if (!ok)
+ {
+ resolver->get_name_scope ().pop ();
+ resolver->get_type_scope ().pop ();
+ resolver->get_label_scope ().pop ();
+ return;
+ }
+
rust_debug ("AST::InherentImpl resolve Self: {%s}",
self_cpath.get ().c_str ());
@@ -641,11 +650,11 @@ ResolveItem::visit (AST::TraitImpl &impl_block)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
if (impl_block.has_generics ())
- for (auto &generic : impl_block.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go (impl_block.get_generic_params (), prefix,
+ canonical_prefix);
// resolve any where clause items
if (impl_block.has_where_clause ())
@@ -671,12 +680,20 @@ ResolveItem::visit (AST::TraitImpl &impl_block)
return;
}
- bool ok;
+ bool ok = true;
+
// setup paths
CanonicalPath canonical_trait_type = CanonicalPath::create_empty ();
+
ok = ResolveTypeToCanonicalPath::go (impl_block.get_trait_path (),
canonical_trait_type);
- rust_assert (ok);
+ if (!ok)
+ {
+ resolver->get_name_scope ().pop ();
+ resolver->get_type_scope ().pop ();
+ resolver->get_label_scope ().pop ();
+ return;
+ }
rust_debug ("AST::TraitImpl resolve trait type: {%s}",
canonical_trait_type.get ().c_str ());
@@ -684,7 +701,13 @@ ResolveItem::visit (AST::TraitImpl &impl_block)
CanonicalPath canonical_impl_type = CanonicalPath::create_empty ();
ok = ResolveTypeToCanonicalPath::go (impl_block.get_type (),
canonical_impl_type);
- rust_assert (ok);
+ if (!ok)
+ {
+ resolver->get_name_scope ().pop ();
+ resolver->get_type_scope ().pop ();
+ resolver->get_label_scope ().pop ();
+ return;
+ }
rust_debug ("AST::TraitImpl resolve self: {%s}",
canonical_impl_type.get ().c_str ());
@@ -755,20 +778,14 @@ ResolveItem::visit (AST::Trait &trait)
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- // we need to inject an implicit self TypeParam here
- // FIXME: which location should be used for Rust::Identifier `Self`?
- AST::TypeParam *implicit_self
- = new AST::TypeParam ({"Self"}, trait.get_locus ());
- trait.insert_implict_self (
- std::unique_ptr<AST::GenericParam> (implicit_self));
- CanonicalPath Self = CanonicalPath::get_big_self (trait.get_node_id ());
-
- for (auto &generic : trait.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go_single (trait.get_implicit_self (), prefix,
+ canonical_prefix);
+ ResolveGenericParams::go (trait.get_generic_params (), prefix,
+ canonical_prefix);
// Self is an implicit TypeParam so lets mark it as such
resolver->get_type_scope ().append_reference_for_def (
- Self.get_node_id (), implicit_self->get_node_id ());
+ trait.get_node_id (), trait.get_implicit_self ().get_node_id ());
if (trait.has_type_param_bounds ())
{
@@ -888,7 +905,18 @@ flatten_list (const AST::UseTreeList &list, std::vector<Import> &imports)
for (auto import = imports.begin () + start_idx; import != imports.end ();
import++)
- import->add_prefix (prefix);
+ {
+ // avoid duplicate node ids
+ auto prefix_copy
+ = AST::SimplePath ({}, prefix.has_opening_scope_resolution (),
+ prefix.get_locus ());
+ for (auto &seg : prefix.get_segments ())
+ prefix_copy.get_segments ().push_back (
+ AST::SimplePathSegment (seg.get_segment_name (),
+ seg.get_locus ()));
+
+ import->add_prefix (std::move (prefix_copy));
+ }
}
}
@@ -1025,12 +1053,12 @@ ResolveExternItem::visit (AST::Function &function)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
// resolve the generics
if (function.has_generics ())
- for (auto &generic : function.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go (function.get_generic_params (), prefix,
+ canonical_prefix);
if (function.has_return_type ())
ResolveType::go (function.get_return_type ());
diff --git a/gcc/rust/resolve/rust-ast-resolve-path.cc b/gcc/rust/resolve/rust-ast-resolve-path.cc
index ea39fd4..fb6715d 100644
--- a/gcc/rust/resolve/rust-ast-resolve-path.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-path.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2020-2025 Free Software Foundation, Inc.
+// Copyright (C) 2020-2024 Free Software Foundation, Inc.
// This file is part of GCC.
@@ -18,6 +18,7 @@
#include "rust-ast-resolve-path.h"
#include "rust-ast-resolve-type.h"
+#include "rust-hir-map.h"
#include "rust-path.h"
namespace Rust {
@@ -49,6 +50,10 @@ ResolvePath::go (AST::SimplePath &expr)
NodeId
ResolvePath::resolve_path (AST::PathInExpression &expr)
{
+ if (expr.is_lang_item ())
+ return Analysis::Mappings::get ().get_lang_item_node (
+ expr.get_lang_item ());
+
NodeId resolved_node_id = UNKNOWN_NODEID;
NodeId module_scope_id = resolver->peek_current_module_scope ();
NodeId previous_resolved_node_id = module_scope_id;
@@ -63,8 +68,7 @@ ResolvePath::resolve_path (AST::PathInExpression &expr)
if (in_middle_of_path && segment.is_lower_self_seg ())
{
rust_error_at (segment.get_locus (), ErrorCode::E0433,
- "failed to resolve: %qs in paths can only be used "
- "in start position",
+ "%qs in paths can only be used in start position",
segment.as_string ().c_str ());
return UNKNOWN_NODEID;
}
@@ -75,8 +79,16 @@ ResolvePath::resolve_path (AST::PathInExpression &expr)
// what is the current crate scope node id?
module_scope_id = crate_scope_id;
previous_resolved_node_id = module_scope_id;
- resolver->insert_resolved_name (segment.get_node_id (),
- module_scope_id);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_name (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == module_scope_id);
+ else
+ resolver->insert_resolved_name (segment.get_node_id (),
+ module_scope_id);
continue;
}
else if (segment.is_super_path_seg ())
@@ -90,8 +102,16 @@ ResolvePath::resolve_path (AST::PathInExpression &expr)
module_scope_id = resolver->peek_parent_module_scope ();
previous_resolved_node_id = module_scope_id;
- resolver->insert_resolved_name (segment.get_node_id (),
- module_scope_id);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_name (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == module_scope_id);
+ else
+ resolver->insert_resolved_name (segment.get_node_id (),
+ module_scope_id);
continue;
}
@@ -135,23 +155,45 @@ ResolvePath::resolve_path (AST::PathInExpression &expr)
ident_seg.as_string ());
if (resolver->get_name_scope ().lookup (path, &resolved_node))
{
- resolver->insert_resolved_name (segment.get_node_id (),
- resolved_node);
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_name (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_name (segment.get_node_id (),
+ resolved_node);
resolved_node_id = resolved_node;
}
// check the type scope
else if (resolver->get_type_scope ().lookup (path, &resolved_node))
{
- resolver->insert_resolved_type (segment.get_node_id (),
- resolved_node);
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_type (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_type (segment.get_node_id (),
+ resolved_node);
resolved_node_id = resolved_node;
}
else if (segment.is_lower_self_seg ())
{
module_scope_id = crate_scope_id;
previous_resolved_node_id = module_scope_id;
- resolver->insert_resolved_name (segment.get_node_id (),
- module_scope_id);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_name (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == module_scope_id);
+ else
+ resolver->insert_resolved_name (segment.get_node_id (),
+ module_scope_id);
continue;
}
else
@@ -174,20 +216,38 @@ ResolvePath::resolve_path (AST::PathInExpression &expr)
resolved_node))
{
resolved_node_id = resolved_node;
- resolver->insert_resolved_name (segment.get_node_id (),
- resolved_node);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok
+ = resolver->lookup_resolved_name (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_name (segment.get_node_id (),
+ resolved_node);
}
else if (resolver->get_type_scope ().decl_was_declared_here (
resolved_node))
{
resolved_node_id = resolved_node;
- resolver->insert_resolved_type (segment.get_node_id (),
- resolved_node);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok
+ = resolver->lookup_resolved_type (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_type (segment.get_node_id (),
+ resolved_node);
}
else
{
rust_error_at (segment.get_locus (),
- "Cannot find path %qs in this scope",
+ "Cannot find path %<%s%> in this scope",
segment.as_string ().c_str ());
return UNKNOWN_NODEID;
}
@@ -207,7 +267,7 @@ ResolvePath::resolve_path (AST::PathInExpression &expr)
else if (is_first_segment)
{
rust_error_at (segment.get_locus (), ErrorCode::E0433,
- "Cannot find path %qs in this scope",
+ "Cannot find path %<%s%> in this scope",
segment.as_string ().c_str ());
return UNKNOWN_NODEID;
}
@@ -219,15 +279,29 @@ ResolvePath::resolve_path (AST::PathInExpression &expr)
// name scope first
if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id))
{
- resolver->insert_resolved_name (expr.get_node_id (),
- resolved_node_id);
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok
+ = resolver->lookup_resolved_name (expr.get_node_id (), &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node_id);
+ else
+ resolver->insert_resolved_name (expr.get_node_id (),
+ resolved_node_id);
}
// check the type scope
else if (resolver->get_type_scope ().decl_was_declared_here (
resolved_node_id))
{
- resolver->insert_resolved_type (expr.get_node_id (),
- resolved_node_id);
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok
+ = resolver->lookup_resolved_type (expr.get_node_id (), &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node_id);
+ else
+ resolver->insert_resolved_type (expr.get_node_id (),
+ resolved_node_id);
}
else
{
@@ -279,14 +353,29 @@ ResolvePath::resolve_path (AST::SimplePath &expr)
// what is the current crate scope node id?
module_scope_id = crate_scope_id;
previous_resolved_node_id = module_scope_id;
- resolver->insert_resolved_name (segment.get_node_id (),
- module_scope_id);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_name (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == module_scope_id);
+ else
+ resolver->insert_resolved_name (segment.get_node_id (),
+ module_scope_id);
resolved_node_id = module_scope_id;
continue;
}
else if (segment.is_super_path_seg ())
{
+ if (!is_first_segment)
+ {
+ rust_error_at (
+ segment.get_locus (), ErrorCode::E0433,
+ "%<super%> in paths can only be used in start position");
+ return UNKNOWN_NODEID;
+ }
if (module_scope_id == crate_scope_id)
{
rust_error_at (segment.get_locus (),
@@ -296,8 +385,16 @@ ResolvePath::resolve_path (AST::SimplePath &expr)
module_scope_id = resolver->peek_parent_module_scope ();
previous_resolved_node_id = module_scope_id;
- resolver->insert_resolved_name (segment.get_node_id (),
- module_scope_id);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_name (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == module_scope_id);
+ else
+ resolver->insert_resolved_name (segment.get_node_id (),
+ module_scope_id);
resolved_node_id = module_scope_id;
continue;
@@ -313,20 +410,36 @@ ResolvePath::resolve_path (AST::SimplePath &expr)
resolved_node))
{
resolved_node_id = resolved_node;
- resolver->insert_resolved_name (segment.get_node_id (),
- resolved_node);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_name (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_name (segment.get_node_id (),
+ resolved_node);
}
else if (resolver->get_type_scope ().decl_was_declared_here (
resolved_node))
{
resolved_node_id = resolved_node;
- resolver->insert_resolved_type (segment.get_node_id (),
- resolved_node);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_type (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_type (segment.get_node_id (),
+ resolved_node);
}
else
{
rust_error_at (segment.get_locus (),
- "Cannot find path %qs in this scope",
+ "Cannot find path %<%s%> in this scope",
segment.as_string ().c_str ());
return UNKNOWN_NODEID;
}
@@ -342,15 +455,31 @@ ResolvePath::resolve_path (AST::SimplePath &expr)
if (resolver->get_name_scope ().lookup (path, &resolved_node))
{
resolved_node_id = resolved_node;
- resolver->insert_resolved_name (segment.get_node_id (),
- resolved_node);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_name (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_name (segment.get_node_id (),
+ resolved_node);
}
// check the type scope
else if (resolver->get_type_scope ().lookup (path, &resolved_node))
{
resolved_node_id = resolved_node;
- resolver->insert_resolved_type (segment.get_node_id (),
- resolved_node);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_type (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_type (segment.get_node_id (),
+ resolved_node);
}
}
@@ -374,7 +503,7 @@ ResolvePath::resolve_path (AST::SimplePath &expr)
if (resolved_node_id == UNKNOWN_NODEID)
{
rust_error_at (segment.get_locus (),
- "cannot find simple path segment %qs in this scope",
+ "cannot find simple path segment %<%s%> in this scope",
segment.as_string ().c_str ());
return UNKNOWN_NODEID;
}
@@ -393,15 +522,29 @@ ResolvePath::resolve_path (AST::SimplePath &expr)
// name scope first
if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id))
{
- resolver->insert_resolved_name (expr.get_node_id (),
- resolved_node_id);
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok
+ = resolver->lookup_resolved_name (expr.get_node_id (), &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node_id);
+ else
+ resolver->insert_resolved_name (expr.get_node_id (),
+ resolved_node_id);
}
// check the type scope
else if (resolver->get_type_scope ().decl_was_declared_here (
resolved_node_id))
{
- resolver->insert_resolved_type (expr.get_node_id (),
- resolved_node_id);
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok
+ = resolver->lookup_resolved_type (expr.get_node_id (), &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node_id);
+ else
+ resolver->insert_resolved_type (expr.get_node_id (),
+ resolved_node_id);
}
else
{
diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.cc b/gcc/rust/resolve/rust-ast-resolve-pattern.cc
index 9b383b7..ee84be8 100644
--- a/gcc/rust/resolve/rust-ast-resolve-pattern.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-pattern.cc
@@ -330,7 +330,8 @@ PatternDeclaration::check_bindings_consistency (
if (!ident_is_outer_bound && !missing_bindings.count (ident))
missing_bindings.insert ({ident, inner_info});
- else if (outer_bindings_map[ident] != inner_info
+ else if (outer_bindings_map.count (ident)
+ && outer_bindings_map[ident] != inner_info
&& !inconsistent_bindings.count (ident))
inconsistent_bindings.insert ({ident, inner_info});
}
diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.cc b/gcc/rust/resolve/rust-ast-resolve-stmt.cc
index 2885291..bfba302 100644
--- a/gcc/rust/resolve/rust-ast-resolve-stmt.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-stmt.cc
@@ -56,5 +56,26 @@ ResolveStmt::visit (AST::TraitImpl &impl_block)
ResolveItem::go (impl_block, prefix, canonical_prefix);
}
+void
+ResolveStmt::visit (AST::StaticItem &var)
+{
+ auto decl = CanonicalPath::new_seg (var.get_node_id (),
+ var.get_identifier ().as_string ());
+ auto path = decl;
+ auto cpath = canonical_prefix.append (decl);
+ mappings.insert_canonical_path (var.get_node_id (), cpath);
+
+ resolver->get_name_scope ().insert (
+ path, var.get_node_id (), var.get_locus (), false, Rib::ItemType::Static,
+ [&] (const CanonicalPath &, NodeId, location_t locus) -> void {
+ rich_location r (line_table, var.get_locus ());
+ r.add_range (locus);
+ redefined_error (r);
+ });
+
+ ResolveType::go (var.get_type ());
+ ResolveExpr::go (var.get_expr (), path, cpath);
+}
+
} // namespace Resolver
} // namespace Rust
diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.h b/gcc/rust/resolve/rust-ast-resolve-stmt.h
index 8e64a76..d413a7c 100644
--- a/gcc/rust/resolve/rust-ast-resolve-stmt.h
+++ b/gcc/rust/resolve/rust-ast-resolve-stmt.h
@@ -63,7 +63,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, constant.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
ResolveType::go (constant.get_type ());
@@ -73,9 +73,10 @@ public:
void visit (AST::LetStmt &stmt) override
{
if (stmt.has_init_expr ())
- {
- ResolveExpr::go (stmt.get_init_expr (), prefix, canonical_prefix);
- }
+ ResolveExpr::go (stmt.get_init_expr (), prefix, canonical_prefix);
+
+ if (stmt.has_else_expr ())
+ ResolveExpr::go (stmt.get_else_expr (), prefix, canonical_prefix);
PatternDeclaration::go (stmt.get_pattern (), Rib::ItemType::Var);
if (stmt.has_type ())
@@ -97,17 +98,15 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, struct_decl.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId scope_node_id = struct_decl.get_node_id ();
resolver->get_type_scope ().push (scope_node_id);
if (struct_decl.has_generics ())
- {
- for (auto &generic : struct_decl.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
- }
+ ResolveGenericParams::go (struct_decl.get_generic_params (), prefix,
+ canonical_prefix);
for (AST::TupleField &field : struct_decl.get_fields ())
ResolveType::go (field.get_field_type ());
@@ -130,17 +129,15 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, enum_decl.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId scope_node_id = enum_decl.get_node_id ();
resolver->get_type_scope ().push (scope_node_id);
if (enum_decl.has_generics ())
- {
- for (auto &generic : enum_decl.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
- }
+ ResolveGenericParams::go (enum_decl.get_generic_params (), prefix,
+ canonical_prefix);
for (auto &variant : enum_decl.get_variants ())
ResolveStmt::go (*variant, path, canonical_prefix, path);
@@ -162,7 +159,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, item.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
// Done, no fields.
@@ -182,7 +179,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, item.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
for (auto &field : item.get_tuple_fields ())
@@ -208,7 +205,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, item.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
for (auto &field : item.get_struct_fields ())
@@ -234,7 +231,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, item.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
// Done, no fields.
@@ -255,17 +252,15 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, struct_decl.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId scope_node_id = struct_decl.get_node_id ();
resolver->get_type_scope ().push (scope_node_id);
if (struct_decl.has_generics ())
- {
- for (auto &generic : struct_decl.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
- }
+ ResolveGenericParams::go (struct_decl.get_generic_params (), prefix,
+ canonical_prefix);
for (AST::StructField &field : struct_decl.get_fields ())
{
@@ -293,15 +288,15 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, union_decl.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId scope_node_id = union_decl.get_node_id ();
resolver->get_type_scope ().push (scope_node_id);
if (union_decl.has_generics ())
- for (auto &generic : union_decl.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go (union_decl.get_generic_params (), prefix,
+ canonical_prefix);
for (AST::StructField &field : union_decl.get_variants ())
{
@@ -329,7 +324,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, function.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId scope_node_id = function.get_node_id ();
@@ -338,11 +333,11 @@ public:
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
if (function.has_generics ())
- for (auto &generic : function.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go (function.get_generic_params (), prefix,
+ canonical_prefix);
if (function.has_return_type ())
ResolveType::go (function.get_return_type ());
@@ -388,6 +383,7 @@ public:
void visit (AST::Trait &trait) override;
void visit (AST::InherentImpl &impl_block) override;
void visit (AST::TraitImpl &impl_block) override;
+ void visit (AST::StaticItem &var) override;
private:
ResolveStmt (const CanonicalPath &prefix,
diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
index 565ca92..f52fb8a 100644
--- a/gcc/rust/resolve/rust-ast-resolve-toplevel.h
+++ b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
@@ -58,7 +58,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, module.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId current_module = resolver->peek_current_module_scope ();
@@ -88,7 +88,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, alias.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId current_module = resolver->peek_current_module_scope ();
@@ -110,7 +110,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, struct_decl.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId current_module = resolver->peek_current_module_scope ();
@@ -132,7 +132,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, enum_decl.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
resolver->push_new_module_scope (enum_decl.get_node_id ());
@@ -158,7 +158,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, item.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
mappings.insert_canonical_path (item.get_node_id (), cpath);
@@ -180,7 +180,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, item.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
mappings.insert_canonical_path (item.get_node_id (), cpath);
@@ -202,7 +202,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, item.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
mappings.insert_canonical_path (item.get_node_id (), cpath);
@@ -224,7 +224,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, item.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
mappings.insert_canonical_path (item.get_node_id (), cpath);
@@ -242,14 +242,21 @@ public:
auto path = prefix.append (decl);
auto cpath = canonical_prefix.append (decl);
- resolver->get_type_scope ().insert (
- path, struct_decl.get_node_id (), struct_decl.get_locus (), false,
- Rib::ItemType::Type,
- [&] (const CanonicalPath &, NodeId, location_t locus) -> void {
- rich_location r (line_table, struct_decl.get_locus ());
- r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
- });
+ auto duplicate_item
+ = [&] (const CanonicalPath &, NodeId, location_t locus) -> void {
+ rich_location r (line_table, struct_decl.get_locus ());
+ r.add_range (locus);
+ redefined_error (r);
+ };
+
+ resolver->get_type_scope ().insert (path, struct_decl.get_node_id (),
+ struct_decl.get_locus (), false,
+ Rib::ItemType::Type, duplicate_item);
+
+ if (struct_decl.is_unit_struct ())
+ resolver->get_name_scope ().insert (path, struct_decl.get_node_id (),
+ struct_decl.get_locus (), false,
+ Rib::ItemType::Type, duplicate_item);
NodeId current_module = resolver->peek_current_module_scope ();
mappings.insert_module_child_item (current_module, decl);
@@ -270,7 +277,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, union_decl.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId current_module = resolver->peek_current_module_scope ();
@@ -290,7 +297,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, var.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId current_module = resolver->peek_current_module_scope ();
@@ -311,7 +318,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, constant.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId current_module = resolver->peek_current_module_scope ();
@@ -333,7 +340,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, function.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId current_module = resolver->peek_current_module_scope ();
@@ -381,7 +388,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, impl_block.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
for (auto &impl_item : impl_block.get_impl_items ())
@@ -401,7 +408,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, trait.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
for (auto &item : trait.get_trait_items ())
@@ -473,7 +480,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, extern_crate.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
}
diff --git a/gcc/rust/resolve/rust-ast-resolve-type.cc b/gcc/rust/resolve/rust-ast-resolve-type.cc
index 934d6ea..8fd69c3 100644
--- a/gcc/rust/resolve/rust-ast-resolve-type.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-type.cc
@@ -18,12 +18,58 @@
#include "rust-ast-resolve-type.h"
#include "rust-ast-resolve-expr.h"
+#include "rust-canonical-path.h"
+#include "rust-type.h"
+#include "rust-hir-map.h"
namespace Rust {
namespace Resolver {
// rust-ast-resolve-type.h
+NodeId
+ResolveType::go (AST::Type &type)
+{
+ ResolveType resolver;
+ type.accept_vis (resolver);
+ return resolver.resolved_node;
+}
+
+void
+ResolveType::visit (AST::BareFunctionType &fntype)
+{
+ for (auto &param : fntype.get_function_params ())
+ ResolveType::go (param.get_type ());
+
+ if (fntype.has_return_type ())
+ ResolveType::go (fntype.get_return_type ());
+}
+
+void
+ResolveType::visit (AST::TupleType &tuple)
+{
+ if (tuple.is_unit_type ())
+ {
+ resolved_node = resolver->get_unit_type_node_id ();
+ return;
+ }
+
+ for (auto &elem : tuple.get_elems ())
+ ResolveType::go (*elem);
+}
+
+void
+ResolveType::visit (AST::TypePath &path)
+{
+ ResolveRelativeTypePath::go (path, resolved_node);
+}
+
+void
+ResolveType::visit (AST::QualifiedPathInType &path)
+{
+ ResolveRelativeQualTypePath::go (path);
+}
+
void
ResolveType::visit (AST::ArrayType &type)
{
@@ -49,6 +95,12 @@ ResolveType::visit (AST::TraitObjectType &type)
}
void
+ResolveType::visit (AST::ParenthesisedType &type)
+{
+ resolved_node = ResolveType::go (*type.get_type_in_parens ());
+}
+
+void
ResolveType::visit (AST::ReferenceType &type)
{
resolved_node = ResolveType::go (type.get_type_referenced ());
@@ -63,13 +115,13 @@ ResolveType::visit (AST::RawPointerType &type)
void
ResolveType::visit (AST::InferredType &)
{
- // FIXME
+ // nothing to do
}
void
ResolveType::visit (AST::NeverType &)
{
- // FIXME
+ resolved_node = resolver->get_never_type_node_id ();
}
void
@@ -78,6 +130,19 @@ ResolveType::visit (AST::SliceType &type)
resolved_node = ResolveType::go (type.get_elem_type ());
}
+void
+ResolveType::visit (AST::ImplTraitType &type)
+{
+ for (auto &bound : type.get_type_param_bounds ())
+ ResolveTypeBound::go (*bound);
+}
+
+void
+ResolveType::visit (AST::ImplTraitTypeOneBound &type)
+{
+ ResolveTypeBound::go (type.get_trait_bound ());
+}
+
// resolve relative type-paths
bool
@@ -91,45 +156,56 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id)
for (size_t i = 0; i < path.get_segments ().size (); i++)
{
auto &segment = path.get_segments ().at (i);
- const AST::PathIdentSegment &ident_seg = segment->get_ident_segment ();
bool is_first_segment = i == 0;
- resolved_node_id = UNKNOWN_NODEID;
+ NodeId crate_scope_id = resolver->peek_crate_module_scope ();
+ auto ident_string = segment->is_lang_item ()
+ ? LangItem::PrettyString (segment->get_lang_item ())
+ : segment->get_ident_segment ().as_string ();
- bool in_middle_of_path = i > 0;
- if (in_middle_of_path && segment->is_lower_self_seg ())
- {
- rust_error_at (segment->get_locus (), ErrorCode::E0433,
- "failed to resolve: %qs in paths can only be used "
- "in start position",
- segment->as_string ().c_str ());
- return false;
- }
+ resolved_node_id = UNKNOWN_NODEID;
- NodeId crate_scope_id = resolver->peek_crate_module_scope ();
- if (segment->is_crate_path_seg ())
+ if (segment->is_lang_item ())
{
- // what is the current crate scope node id?
- module_scope_id = crate_scope_id;
- previous_resolved_node_id = module_scope_id;
- resolver->insert_resolved_name (segment->get_node_id (),
- module_scope_id);
-
- continue;
+ resolved_node_id = Analysis::Mappings::get ().get_lang_item_node (
+ segment->get_lang_item ());
+ previous_resolved_node_id = resolved_node_id;
}
- else if (segment->is_super_path_seg ())
+ else
{
- if (module_scope_id == crate_scope_id)
+ bool in_middle_of_path = i > 0;
+ if (in_middle_of_path && segment->is_lower_self_seg ())
{
- rust_error_at (segment->get_locus (),
- "cannot use super at the crate scope");
+ rust_error_at (segment->get_locus (), ErrorCode::E0433,
+ "%qs in paths can only be used in start position",
+ segment->as_string ().c_str ());
return false;
}
- module_scope_id = resolver->peek_parent_module_scope ();
- previous_resolved_node_id = module_scope_id;
- resolver->insert_resolved_name (segment->get_node_id (),
- module_scope_id);
- continue;
+ if (segment->is_crate_path_seg ())
+ {
+ // what is the current crate scope node id?
+ module_scope_id = crate_scope_id;
+ previous_resolved_node_id = module_scope_id;
+ resolver->insert_resolved_name (segment->get_node_id (),
+ module_scope_id);
+
+ continue;
+ }
+ else if (segment->is_super_path_seg ())
+ {
+ if (module_scope_id == crate_scope_id)
+ {
+ rust_error_at (segment->get_locus (),
+ "cannot use super at the crate scope");
+ return false;
+ }
+
+ module_scope_id = resolver->peek_parent_module_scope ();
+ previous_resolved_node_id = module_scope_id;
+ resolver->insert_resolved_name (segment->get_node_id (),
+ module_scope_id);
+ continue;
+ }
}
switch (segment->get_type ())
@@ -169,27 +245,48 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id)
// name scope first
NodeId resolved_node = UNKNOWN_NODEID;
const CanonicalPath path
- = CanonicalPath::new_seg (segment->get_node_id (),
- ident_seg.as_string ());
+ = CanonicalPath::new_seg (segment->get_node_id (), ident_string);
if (resolver->get_type_scope ().lookup (path, &resolved_node))
{
- resolver->insert_resolved_type (segment->get_node_id (),
- resolved_node);
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_type (segment->get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_type (segment->get_node_id (),
+ resolved_node);
resolved_node_id = resolved_node;
}
else if (resolver->get_name_scope ().lookup (path, &resolved_node))
{
- resolver->insert_resolved_name (segment->get_node_id (),
- resolved_node);
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_name (segment->get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_name (segment->get_node_id (),
+ resolved_node);
resolved_node_id = resolved_node;
}
- else if (segment->is_lower_self_seg ())
+ else if (!segment->is_lang_item () && segment->is_lower_self_seg ())
{
// what is the current crate scope node id?
module_scope_id = crate_scope_id;
previous_resolved_node_id = module_scope_id;
- resolver->insert_resolved_name (segment->get_node_id (),
- module_scope_id);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_name (segment->get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == module_scope_id);
+ else
+ resolver->insert_resolved_name (segment->get_node_id (),
+ module_scope_id);
continue;
}
@@ -199,8 +296,7 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id)
&& previous_resolved_node_id == module_scope_id)
{
tl::optional<CanonicalPath &> resolved_child
- = mappings.lookup_module_child (module_scope_id,
- ident_seg.as_string ());
+ = mappings.lookup_module_child (module_scope_id, ident_string);
if (resolved_child.has_value ())
{
NodeId resolved_node = resolved_child->get_node_id ();
@@ -208,15 +304,33 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id)
resolved_node))
{
resolved_node_id = resolved_node;
- resolver->insert_resolved_name (segment->get_node_id (),
- resolved_node);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok
+ = resolver->lookup_resolved_name (segment->get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_name (segment->get_node_id (),
+ resolved_node);
}
else if (resolver->get_type_scope ().decl_was_declared_here (
resolved_node))
{
resolved_node_id = resolved_node;
- resolver->insert_resolved_type (segment->get_node_id (),
- resolved_node);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok
+ = resolver->lookup_resolved_type (segment->get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_type (segment->get_node_id (),
+ resolved_node);
}
else
{
@@ -241,8 +355,8 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id)
else if (is_first_segment)
{
rust_error_at (segment->get_locus (), ErrorCode::E0412,
- "failed to resolve TypePath: %s in this scope",
- segment->as_string ().c_str ());
+ "could not resolve type path %qs",
+ segment->get_ident_segment ().as_string ().c_str ());
return false;
}
}
@@ -252,15 +366,29 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id)
// name scope first
if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id))
{
- resolver->insert_resolved_name (path.get_node_id (),
- resolved_node_id);
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok
+ = resolver->lookup_resolved_name (path.get_node_id (), &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node_id);
+ else
+ resolver->insert_resolved_name (path.get_node_id (),
+ resolved_node_id);
}
// check the type scope
else if (resolver->get_type_scope ().decl_was_declared_here (
resolved_node_id))
{
- resolver->insert_resolved_type (path.get_node_id (),
- resolved_node_id);
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok
+ = resolver->lookup_resolved_type (path.get_node_id (), &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node_id);
+ else
+ resolver->insert_resolved_type (path.get_node_id (),
+ resolved_node_id);
}
else
{
@@ -495,10 +623,74 @@ ResolveTypeToCanonicalPath::visit (AST::TraitObjectTypeOneBound &type)
}
void
-ResolveTypeToCanonicalPath::visit (AST::TraitObjectType &)
+ResolveTypeToCanonicalPath::visit (AST::TraitObjectType &type)
{
- // FIXME is this actually allowed? dyn A+B
- rust_unreachable ();
+ rust_assert (!type.get_type_param_bounds ().empty ());
+
+ auto &first_bound = type.get_type_param_bounds ().front ();
+
+ // Is it allowed or even possible to have a lifetime bound as a first bound?
+ if (first_bound->get_bound_type () == AST::TraitBound::LIFETIME)
+ rust_unreachable ();
+
+ auto &trait = static_cast<AST::TraitBound &> (*first_bound);
+
+ CanonicalPath path = CanonicalPath::create_empty ();
+ bool ok = ResolveTypeToCanonicalPath::go (trait.get_type_path (), path);
+
+ // right?
+ rust_assert (ok);
+
+ auto slice_path = "<dyn " + path.get ();
+
+ for (size_t idx = 1; idx < type.get_type_param_bounds ().size (); idx++)
+ {
+ auto &additional_bound = type.get_type_param_bounds ()[idx];
+
+ std::string str;
+
+ switch (additional_bound->get_bound_type ())
+ {
+ case AST::TypeParamBound::TRAIT: {
+ auto bound_path = CanonicalPath::create_empty ();
+
+ auto &bound_type_path
+ = static_cast<AST::TraitBound &> (*additional_bound)
+ .get_type_path ();
+ bool ok
+ = ResolveTypeToCanonicalPath::go (bound_type_path, bound_path);
+
+ if (!ok)
+ continue;
+
+ str = bound_path.get ();
+ break;
+ }
+ case AST::TypeParamBound::LIFETIME:
+ rust_unreachable ();
+ break;
+ }
+ slice_path += " + " + str;
+ }
+
+ slice_path += ">";
+
+ result = CanonicalPath::new_seg (type.get_node_id (), slice_path);
+}
+
+void
+ResolveTypeToCanonicalPath::visit (AST::NeverType &type)
+{
+ result = CanonicalPath::new_seg (type.get_node_id (), "!");
+}
+
+void
+ResolveTypeToCanonicalPath::visit (AST::TupleType &type)
+{
+ if (!type.is_unit_type ())
+ rust_unreachable ();
+
+ result = CanonicalPath::new_seg (type.get_node_id (), "()");
}
ResolveTypeToCanonicalPath::ResolveTypeToCanonicalPath ()
diff --git a/gcc/rust/resolve/rust-ast-resolve-type.h b/gcc/rust/resolve/rust-ast-resolve-type.h
index 0076424..f1481fc 100644
--- a/gcc/rust/resolve/rust-ast-resolve-type.h
+++ b/gcc/rust/resolve/rust-ast-resolve-type.h
@@ -21,6 +21,11 @@
#include "rust-ast-resolve-base.h"
#include "rust-ast-resolve-expr.h"
+#include "rust-diagnostics.h"
+#include "rust-hir-map.h"
+#include "rust-path.h"
+#include "rust-type.h"
+#include "util/rust-hir-map.h"
namespace Rust {
namespace Resolver {
@@ -56,59 +61,23 @@ class ResolveType : public ResolverBase
using Rust::Resolver::ResolverBase::visit;
public:
- static NodeId go (AST::Type &type)
- {
- ResolveType resolver;
- type.accept_vis (resolver);
- return resolver.resolved_node;
- }
-
- void visit (AST::BareFunctionType &fntype) override
- {
- for (auto &param : fntype.get_function_params ())
- ResolveType::go (param.get_type ());
-
- if (fntype.has_return_type ())
- ResolveType::go (fntype.get_return_type ());
- }
-
- void visit (AST::TupleType &tuple) override
- {
- if (tuple.is_unit_type ())
- {
- resolved_node = resolver->get_unit_type_node_id ();
- return;
- }
-
- for (auto &elem : tuple.get_elems ())
- ResolveType::go (*elem);
- }
-
- void visit (AST::TypePath &path) override
- {
- ResolveRelativeTypePath::go (path, resolved_node);
- }
-
- void visit (AST::QualifiedPathInType &path) override
- {
- ResolveRelativeQualTypePath::go (path);
- }
+ static NodeId go (AST::Type &type);
+ void visit (AST::BareFunctionType &fntype) override;
+ void visit (AST::TupleType &tuple) override;
+ void visit (AST::TypePath &path) override;
+ void visit (AST::QualifiedPathInType &path) override;
void visit (AST::ArrayType &type) override;
-
void visit (AST::ReferenceType &type) override;
-
void visit (AST::InferredType &type) override;
-
void visit (AST::NeverType &type) override;
-
void visit (AST::RawPointerType &type) override;
-
void visit (AST::TraitObjectTypeOneBound &type) override;
-
void visit (AST::TraitObjectType &type) override;
-
+ void visit (AST::ParenthesisedType &type) override;
void visit (AST::SliceType &type) override;
+ void visit (AST::ImplTraitType &type) override;
+ void visit (AST::ImplTraitTypeOneBound &type) override;
private:
ResolveType () : ResolverBase () {}
@@ -135,66 +104,83 @@ private:
ResolveTypeBound () : ResolverBase () {}
};
-class ResolveGenericParam : public ResolverBase
+class ResolveGenericParams : public ResolverBase
{
using Rust::Resolver::ResolverBase::visit;
public:
- static NodeId go (AST::GenericParam &param, const CanonicalPath &prefix,
- const CanonicalPath &canonical_prefix)
+ static void go (std::vector<std::unique_ptr<AST::GenericParam>> &params,
+ const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
{
- ResolveGenericParam resolver (prefix, canonical_prefix);
- param.accept_vis (resolver);
- return resolver.resolved_node;
+ ResolveGenericParams resolver (prefix, canonical_prefix);
+
+ // this needs to be done in two phases as they can be used and defined later
+ // in bounds
+ for (auto &param : params)
+ param->accept_vis (resolver);
+
+ resolver.first_pass = false;
+
+ for (auto &param : params)
+ param->accept_vis (resolver);
}
- void visit (AST::ConstGenericParam &param) override
+ static void go_single (AST::GenericParam &param, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
{
- ResolveType::go (param.get_type ());
-
- if (param.has_default_value ())
- ResolveExpr::go (param.get_default_value ().get_expression (), prefix,
- canonical_prefix);
+ ResolveGenericParams resolver (prefix, canonical_prefix);
- ok = true;
+ param.accept_vis (resolver);
+ resolver.first_pass = false;
+ param.accept_vis (resolver);
}
- void visit (AST::TypeParam &param) override
+ void visit (AST::ConstGenericParam &param) override
{
- // if it has a type lets resolve it
- if (param.has_type ())
+ if (first_pass)
ResolveType::go (param.get_type ());
+ else if (param.has_default_value ())
+ ResolveExpr::go (param.get_default_value_unchecked ().get_expression (),
+ prefix, canonical_prefix);
+ }
- if (param.has_type_param_bounds ())
+ void visit (AST::TypeParam &param) override
+ {
+ if (first_pass)
+ {
+ // if it has a type lets resolve it
+ if (param.has_type ())
+ ResolveType::go (param.get_type ());
+
+ auto seg = CanonicalPath::new_seg (
+ param.get_node_id (), param.get_type_representation ().as_string ());
+ resolver->get_type_scope ().insert (
+ seg, param.get_node_id (), param.get_locus (), false,
+ Rib::ItemType::Type,
+ [&] (const CanonicalPath &, NodeId, location_t locus) -> void {
+ rust_error_at (param.get_locus (),
+ "generic param defined multiple times");
+ rust_error_at (locus, "was defined here");
+ });
+
+ mappings.insert_canonical_path (param.get_node_id (), seg);
+ }
+ else if (param.has_type_param_bounds ())
{
for (auto &bound : param.get_type_param_bounds ())
- {
- ResolveTypeBound::go (*bound);
- }
+ ResolveTypeBound::go (*bound);
}
-
- auto seg
- = CanonicalPath::new_seg (param.get_node_id (),
- param.get_type_representation ().as_string ());
- resolver->get_type_scope ().insert (
- seg, param.get_node_id (), param.get_locus (), false, Rib::ItemType::Type,
- [&] (const CanonicalPath &, NodeId, location_t locus) -> void {
- rust_error_at (param.get_locus (),
- "generic param redefined multiple times");
- rust_error_at (locus, "was defined here");
- });
-
- mappings.insert_canonical_path (param.get_node_id (), seg);
}
private:
- ResolveGenericParam (const CanonicalPath &prefix,
- const CanonicalPath &canonical_prefix)
- : ResolverBase (), ok (false), prefix (prefix),
+ ResolveGenericParams (const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+ : ResolverBase (), first_pass (true), prefix (prefix),
canonical_prefix (canonical_prefix)
{}
- bool ok;
+ bool first_pass;
const CanonicalPath &prefix;
const CanonicalPath &canonical_prefix;
};
@@ -246,6 +232,10 @@ public:
void visit (AST::TraitObjectType &type) override;
+ void visit (AST::NeverType &type) override;
+
+ void visit (AST::TupleType &type) override;
+
private:
ResolveTypeToCanonicalPath ();
diff --git a/gcc/rust/resolve/rust-ast-resolve.cc b/gcc/rust/resolve/rust-ast-resolve.cc
index a467d1e..3e3c992 100644
--- a/gcc/rust/resolve/rust-ast-resolve.cc
+++ b/gcc/rust/resolve/rust-ast-resolve.cc
@@ -63,7 +63,10 @@ NameResolution::go (AST::Crate &crate)
{
// lookup current crate name
CrateNum cnum = mappings.get_current_crate ();
- const auto &crate_name = mappings.get_crate_name (cnum).value ();
+
+ // Clones the crate name instead of references due to gcc's possibly
+ // dangling references warnings
+ const auto crate_name = mappings.get_crate_name (cnum).value ();
// setup the ribs
NodeId scope_node_id = crate.get_node_id ();
@@ -72,7 +75,7 @@ NameResolution::go (AST::Crate &crate)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
// get the root segment
CanonicalPath crate_prefix
diff --git a/gcc/rust/resolve/rust-default-resolver.cc b/gcc/rust/resolve/rust-default-resolver.cc
index 6de694f..480034c 100644
--- a/gcc/rust/resolve/rust-default-resolver.cc
+++ b/gcc/rust/resolve/rust-default-resolver.cc
@@ -30,13 +30,7 @@ DefaultResolver::visit (AST::BlockExpr &expr)
// extracting the lambda from the `scoped` call otherwise the code looks like
// a hot turd thanks to our .clang-format
- auto inner_fn = [this, &expr] () {
- for (auto &stmt : expr.get_statements ())
- stmt->accept_vis (*this);
-
- if (expr.has_tail_expr ())
- expr.get_tail_expr ().accept_vis (*this);
- };
+ auto inner_fn = [this, &expr] () { AST::DefaultASTVisitor::visit (expr); };
ctx.scoped (Rib::Kind::Normal, expr.get_node_id (), inner_fn);
}
@@ -44,10 +38,7 @@ DefaultResolver::visit (AST::BlockExpr &expr)
void
DefaultResolver::visit (AST::Module &module)
{
- auto item_fn = [this, &module] () {
- for (auto &item : module.get_items ())
- item->accept_vis (*this);
- };
+ auto item_fn = [this, &module] () { AST::DefaultASTVisitor::visit (module); };
ctx.scoped (Rib::Kind::Module, module.get_node_id (), item_fn,
module.get_name ());
@@ -56,35 +47,8 @@ DefaultResolver::visit (AST::Module &module)
void
DefaultResolver::visit (AST::Function &function)
{
- auto def_fn = [this, &function] () {
- for (auto &p : function.get_function_params ())
- {
- if (p->is_variadic ())
- {
- auto &param = static_cast<AST::VariadicParam &> (*p);
- if (param.has_pattern ())
- param.get_pattern ().accept_vis (*this);
- }
- else if (p->is_self ())
- {
- auto &param = static_cast<AST::SelfParam &> (*p);
- param.get_type ().accept_vis (*this);
- param.get_lifetime ().accept_vis (*this);
- }
- else
- {
- auto &param = static_cast<AST::FunctionParam &> (*p);
- param.get_pattern ().accept_vis (*this);
- param.get_type ().accept_vis (*this);
- }
- }
-
- if (function.has_return_type ())
- visit (function.get_return_type ());
-
- if (function.has_body ())
- function.get_definition ().value ()->accept_vis (*this);
- };
+ auto def_fn
+ = [this, &function] () { AST::DefaultASTVisitor::visit (function); };
ctx.scoped (Rib::Kind::Function, function.get_node_id (), def_fn);
}
@@ -92,20 +56,14 @@ DefaultResolver::visit (AST::Function &function)
void
DefaultResolver::visit (AST::ForLoopExpr &expr)
{
- ctx.scoped (Rib::Kind::Normal, expr.get_node_id (), [this, &expr] () {
- expr.get_pattern ().accept_vis (*this);
- expr.get_iterator_expr ().accept_vis (*this);
- expr.get_loop_block ().accept_vis (*this);
- });
+ ctx.scoped (Rib::Kind::Normal, expr.get_node_id (),
+ [this, &expr] () { AST::DefaultASTVisitor::visit (expr); });
}
void
DefaultResolver::visit (AST::Trait &trait)
{
- auto inner_fn = [this, &trait] () {
- for (auto &item : trait.get_trait_items ())
- item->accept_vis (*this);
- };
+ auto inner_fn = [this, &trait] () { AST::DefaultASTVisitor::visit (trait); };
ctx.scoped (Rib::Kind::TraitOrImpl, trait.get_node_id (), inner_fn,
trait.get_identifier () /* FIXME: Is that valid?*/);
@@ -114,11 +72,7 @@ DefaultResolver::visit (AST::Trait &trait)
void
DefaultResolver::visit (AST::InherentImpl &impl)
{
- auto inner_fn = [this, &impl] () {
- visit (impl.get_type ());
- for (auto &item : impl.get_impl_items ())
- item->accept_vis (*this);
- };
+ auto inner_fn = [this, &impl] () { AST::DefaultASTVisitor::visit (impl); };
ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn);
}
@@ -126,10 +80,7 @@ DefaultResolver::visit (AST::InherentImpl &impl)
void
DefaultResolver::visit (AST::TraitImpl &impl)
{
- auto inner_fn = [this, &impl] () {
- for (auto &item : impl.get_impl_items ())
- item->accept_vis (*this);
- };
+ auto inner_fn = [this, &impl] () { AST::DefaultASTVisitor::visit (impl); };
ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn);
}
@@ -137,343 +88,73 @@ DefaultResolver::visit (AST::TraitImpl &impl)
void
DefaultResolver::visit (AST::StructStruct &type)
{
- // do we need to scope anything here? no, right?
-
- // we also can't visit `StructField`s by default, so there's nothing to do -
- // correct? or should we do something like
+ auto inner_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); };
- AST::DefaultASTVisitor::visit (type);
-
- // FIXME: ???
+ ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (),
+ inner_fn, type.get_struct_name ());
}
void
-DefaultResolver::visit (AST::Enum &type)
+DefaultResolver::visit (AST::TupleStruct &type)
{
- // FIXME: Do we need to scope anything by default?
-
- auto variant_fn = [this, &type] () {
- for (auto &variant : type.get_variants ())
- variant->accept_vis (*this);
- };
+ auto inner_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); };
ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (),
- variant_fn, type.get_identifier ());
+ inner_fn, type.get_struct_name ());
}
void
-DefaultResolver::visit (AST::StructExprFieldIdentifierValue &)
-{}
-
-void
-DefaultResolver::visit (AST::StructExprFieldIndexValue &)
-{}
-
-void
-DefaultResolver::visit (AST::ClosureExprInner &expr)
+DefaultResolver::visit (AST::Enum &type)
{
- if (expr.is_marked_for_strip ())
- return;
+ auto variant_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); };
- for (auto &param : expr.get_params ())
- {
- if (param.is_error ())
- continue;
-
- param.get_pattern ().accept_vis (*this);
- if (param.has_type_given ())
- param.get_type ().accept_vis (*this);
- }
-
- expr.get_definition_expr ().accept_vis (*this);
+ ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (),
+ variant_fn, type.get_identifier ());
}
void
-DefaultResolver::visit (AST::ClosureExprInnerTyped &expr)
+DefaultResolver::visit (AST::Union &type)
{
- if (expr.is_marked_for_strip ())
- return;
-
- for (auto &param : expr.get_params ())
- {
- if (param.is_error ())
- continue;
+ auto inner_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); };
- param.get_pattern ().accept_vis (*this);
- if (param.has_type_given ())
- param.get_type ().accept_vis (*this);
- }
-
- expr.get_definition_block ().accept_vis (*this);
- expr.get_return_type ().accept_vis (*this);
+ ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (),
+ inner_fn, type.get_identifier ());
}
void
-DefaultResolver::visit (AST::ContinueExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::RangeFromToExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::RangeFromExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::RangeToExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::RangeFromToInclExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::RangeToInclExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::ReturnExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::CallExpr &expr)
+DefaultResolver::visit (AST::TypeAlias &type)
{
- expr.get_function_expr ().accept_vis (*this);
+ auto inner_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); };
- for (auto &param : expr.get_params ())
- param->accept_vis (*this);
+ ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (),
+ inner_fn, type.get_new_type_name ());
}
void
-DefaultResolver::visit (AST::MethodCallExpr &expr)
+DefaultResolver::visit (AST::ClosureExprInner &expr)
{
- expr.get_receiver_expr ().accept_vis (*this);
-
- if (expr.get_method_name ().has_generic_args ())
- {
- auto &args = expr.get_method_name ().get_generic_args ();
- for (auto &arg : args.get_generic_args ())
- arg.accept_vis (*this);
- for (auto &arg : args.get_binding_args ())
- if (!arg.is_error ())
- arg.get_type ().accept_vis (*this);
- for (auto &arg : args.get_lifetime_args ())
- arg.accept_vis (*this);
- }
+ if (expr.is_marked_for_strip ())
+ return;
- for (auto &param : expr.get_params ())
- param->accept_vis (*this);
+ AST::DefaultASTVisitor::visit (expr);
}
void
-DefaultResolver::visit (AST::LoopExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::WhileLoopExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::WhileLetLoopExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::IfExpr &expr)
+DefaultResolver::visit (AST::ClosureExprInnerTyped &expr)
{
- expr.get_condition_expr ().accept_vis (*this);
- expr.get_if_block ().accept_vis (*this);
-}
+ if (expr.is_marked_for_strip ())
+ return;
-void
-DefaultResolver::visit (AST::IfExprConseqElse &expr)
-{
- expr.get_condition_expr ().accept_vis (*this);
- expr.get_if_block ().accept_vis (*this);
- expr.get_else_block ().accept_vis (*this);
+ AST::DefaultASTVisitor::visit (expr);
}
void
-DefaultResolver::visit (AST::IfLetExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::IfLetExprConseqElse &)
-{}
-
-void
DefaultResolver::visit (AST::MatchExpr &expr)
{
if (expr.is_marked_for_strip ())
return;
- expr.get_scrutinee_expr ().accept_vis (*this);
- for (auto &arm : expr.get_match_cases ())
- {
- arm.get_expr ().accept_vis (*this);
- for (auto &pat : arm.get_arm ().get_patterns ())
- pat->accept_vis (*this);
- if (arm.get_arm ().has_match_arm_guard ())
- arm.get_arm ().get_guard_expr ().accept_vis (*this);
- }
-}
-
-void
-DefaultResolver::visit (AST::AwaitExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::AsyncBlockExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::DelimTokenTree &)
-{}
-
-void
-DefaultResolver::visit (AST::AttrInputMetaItemContainer &)
-{}
-
-void
-DefaultResolver::visit (AST::IdentifierExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::LifetimeParam &)
-{}
-
-void
-DefaultResolver::visit (AST::ConstGenericParam &)
-{}
-
-void
-DefaultResolver::visit (AST::PathInExpression &expr)
-{
- for (auto &seg : expr.get_segments ())
- if (seg.has_generic_args ())
- {
- auto &args = seg.get_generic_args ();
- for (auto &arg : args.get_generic_args ())
- arg.accept_vis (*this);
- for (auto &arg : args.get_binding_args ())
- if (!arg.is_error ())
- arg.get_type ().accept_vis (*this);
- for (auto &arg : args.get_lifetime_args ())
- arg.accept_vis (*this);
- }
-}
-
-void
-DefaultResolver::visit (AST::TypePathSegmentGeneric &)
-{}
-
-void
-DefaultResolver::visit (AST::TypePathSegmentFunction &)
-{}
-
-void
-DefaultResolver::visit (AST::TypePath &)
-{}
-
-void
-DefaultResolver::visit (AST::QualifiedPathInExpression &)
-{}
-
-void
-DefaultResolver::visit (AST::QualifiedPathInType &)
-{}
-
-void
-DefaultResolver::visit (AST::LiteralExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::AttrInputLiteral &)
-{}
-
-void
-DefaultResolver::visit (AST::AttrInputMacro &)
-{}
-
-void
-DefaultResolver::visit (AST::MetaItemLitExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::MetaItemPathLit &)
-{}
-
-void
-DefaultResolver::visit (AST::StructExprStruct &)
-{}
-
-void
-DefaultResolver::visit (AST::StructExprStructFields &)
-{}
-
-void
-DefaultResolver::visit (AST::StructExprStructBase &)
-{}
-
-void
-DefaultResolver::visit (AST::TypeParam &)
-{}
-
-void
-DefaultResolver::visit (AST::LifetimeWhereClauseItem &)
-{}
-
-void
-DefaultResolver::visit (AST::TypeBoundWhereClauseItem &)
-{}
-
-void
-DefaultResolver::visit (AST::ExternCrate &)
-{}
-
-void
-DefaultResolver::visit (AST::UseTreeGlob &)
-{}
-
-void
-DefaultResolver::visit (AST::UseTreeList &)
-{}
-
-void
-DefaultResolver::visit (AST::UseTreeRebind &)
-{}
-
-void
-DefaultResolver::visit (AST::UseDeclaration &)
-{}
-
-void
-DefaultResolver::visit (AST::TypeAlias &)
-{}
-
-void
-DefaultResolver::visit (AST::EnumItem &)
-{}
-
-void
-DefaultResolver::visit (AST::EnumItemTuple &item)
-{
- for (auto &field : item.get_tuple_fields ())
- field.get_field_type ().accept_vis (*this);
-}
-
-void
-DefaultResolver::visit (AST::EnumItemStruct &item)
-{
- for (auto &field : item.get_struct_fields ())
- field.get_field_type ().accept_vis (*this);
-}
-
-void
-DefaultResolver::visit (AST::EnumItemDiscriminant &item)
-{
- if (item.has_expr ())
- item.get_expr ().accept_vis (*this);
+ AST::DefaultASTVisitor::visit (expr);
}
void
@@ -481,10 +162,8 @@ DefaultResolver::visit (AST::ConstantItem &item)
{
if (item.has_expr ())
{
- auto expr_vis = [this, &item] () {
- item.get_expr ().accept_vis (*this);
- visit (item.get_type ());
- };
+ auto expr_vis
+ = [this, &item] () { AST::DefaultASTVisitor::visit (item); };
// FIXME: Why do we need a Rib here?
ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis);
@@ -494,187 +173,19 @@ DefaultResolver::visit (AST::ConstantItem &item)
void
DefaultResolver::visit (AST::StaticItem &item)
{
- auto expr_vis = [this, &item] () { item.get_expr ().accept_vis (*this); };
+ auto expr_vis = [this, &item] () { AST::DefaultASTVisitor::visit (item); };
// FIXME: Why do we need a Rib here?
ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis);
}
void
-DefaultResolver::visit (AST::TraitItemConst &)
-{}
-
-void
-DefaultResolver::visit (AST::TraitItemType &)
-{}
-
-void
-DefaultResolver::visit (AST::ExternalTypeItem &)
-{}
-
-void
-DefaultResolver::visit (AST::ExternalStaticItem &)
-{}
-
-void
-DefaultResolver::visit (AST::MacroMatchRepetition &)
-{}
-
-void
-DefaultResolver::visit (AST::MacroMatcher &)
-{}
-
-void
-DefaultResolver::visit (AST::MacroRulesDefinition &)
-{}
-
-void
-DefaultResolver::visit (AST::MacroInvocation &)
-{}
-
-void
-DefaultResolver::visit (AST::MetaItemPath &)
-{}
-
-void
-DefaultResolver::visit (AST::MetaItemSeq &)
-{}
-
-void
-DefaultResolver::visit (AST::MetaListPaths &)
-{}
-
-void
-DefaultResolver::visit (AST::MetaListNameValueStr &)
-{}
-
-void
-DefaultResolver::visit (AST::RangePatternBoundPath &)
-{}
-
-void
-DefaultResolver::visit (AST::RangePatternBoundQualPath &)
-{}
-
-void
-DefaultResolver::visit (AST::RangePattern &)
-{}
-
-void
-DefaultResolver::visit (AST::ReferencePattern &)
-{}
-
-void
-DefaultResolver::visit (AST::StructPatternFieldTuplePat &)
-{}
-
-void
-DefaultResolver::visit (AST::StructPatternFieldIdentPat &)
-{}
-
-void
-DefaultResolver::visit (AST::StructPatternFieldIdent &)
-{}
-
-void
-DefaultResolver::visit (AST::StructPattern &)
-{}
-
-void
-DefaultResolver::visit (AST::TupleStructItemsNoRange &)
-{}
-
-void
-DefaultResolver::visit (AST::TupleStructItemsRange &)
-{}
-
-void
-DefaultResolver::visit (AST::TupleStructPattern &)
-{}
-
-void
-DefaultResolver::visit (AST::TuplePatternItemsMultiple &)
-{}
-
-void
-DefaultResolver::visit (AST::TuplePatternItemsRanged &)
-{}
-
-void
-DefaultResolver::visit (AST::TuplePattern &)
-{}
-
-void
-DefaultResolver::visit (AST::GroupedPattern &)
-{}
-
-void
-DefaultResolver::visit (AST::SlicePattern &)
-{}
-
-void
-DefaultResolver::visit (AST::AltPattern &)
-{}
-
-void
-DefaultResolver::visit (AST::EmptyStmt &)
-{}
-
-void
-DefaultResolver::visit (AST::TraitBound &)
-{}
-
-void
-DefaultResolver::visit (AST::ImplTraitType &)
-{}
-
-void
-DefaultResolver::visit (AST::TraitObjectType &)
-{}
-
-void
-DefaultResolver::visit (AST::ParenthesisedType &)
-{}
-
-void
-DefaultResolver::visit (AST::ImplTraitTypeOneBound &)
-{}
-
-void
-DefaultResolver::visit (AST::TraitObjectTypeOneBound &)
-{}
-
-void
-DefaultResolver::visit (AST::TupleType &)
-{}
-
-void
-DefaultResolver::visit (AST::ReferenceType &)
-{}
-
-void
-DefaultResolver::visit (AST::ArrayType &)
-{}
-
-void
-DefaultResolver::visit (AST::SliceType &)
-{}
-
-void
-DefaultResolver::visit (AST::BareFunctionType &)
-{}
-
-void
-DefaultResolver::visit (AST::SelfParam &)
-{}
-
-void
-DefaultResolver::visit (AST::FunctionParam &)
-{}
+DefaultResolver::visit (AST::TypeParam &param)
+{
+ auto expr_vis = [this, &param] () { AST::DefaultASTVisitor::visit (param); };
-void
-DefaultResolver::visit (AST::VariadicParam &)
-{}
+ ctx.scoped (Rib::Kind::ForwardTypeParamBan, param.get_node_id (), expr_vis);
+}
} // namespace Resolver2_0
} // namespace Rust
diff --git a/gcc/rust/resolve/rust-default-resolver.h b/gcc/rust/resolve/rust-default-resolver.h
index 6bca8b7..2a987ef 100644
--- a/gcc/rust/resolve/rust-default-resolver.h
+++ b/gcc/rust/resolve/rust-default-resolver.h
@@ -42,122 +42,31 @@ public:
// First, our lexical scope expressions - these visit their sub nodes, always
// these nodes create new scopes and ribs - they are often used to declare new
// variables, such as a for loop's iterator, or a function's arguments
- void visit (AST::BlockExpr &);
- void visit (AST::Module &);
- void visit (AST::Function &);
- void visit (AST::ForLoopExpr &);
- void visit (AST::Trait &);
- void visit (AST::InherentImpl &);
- void visit (AST::TraitImpl &);
+ void visit (AST::BlockExpr &) override;
+ void visit (AST::Module &) override;
+ void visit (AST::Function &) override;
+ void visit (AST::ForLoopExpr &expr) override;
+ void visit (AST::Trait &) override;
+ void visit (AST::InherentImpl &) override;
+ void visit (AST::TraitImpl &) override;
+
+ void visit (AST::TypeParam &) override;
// type dec nodes, which visit their fields or variants by default
- void visit (AST::StructStruct &);
- void visit (AST::Enum &);
+ void visit (AST::StructStruct &) override;
+ void visit (AST::TupleStruct &) override;
+ void visit (AST::Enum &) override;
+ void visit (AST::Union &) override;
+ void visit (AST::TypeAlias &) override;
// Visitors that visit their expression node(s)
- void visit (AST::StructExprFieldIdentifierValue &);
- void visit (AST::StructExprFieldIndexValue &);
- void visit (AST::ClosureExprInner &);
- void visit (AST::ClosureExprInnerTyped &);
- void visit (AST::ContinueExpr &);
- void visit (AST::RangeFromToExpr &);
- void visit (AST::RangeFromExpr &);
- void visit (AST::RangeToExpr &);
- void visit (AST::RangeFromToInclExpr &);
- void visit (AST::RangeToInclExpr &);
- void visit (AST::ReturnExpr &);
- void visit (AST::CallExpr &);
- void visit (AST::MethodCallExpr &);
- void visit (AST::LoopExpr &);
- void visit (AST::WhileLoopExpr &);
- void visit (AST::WhileLetLoopExpr &);
- void visit (AST::IfExpr &);
- void visit (AST::IfExprConseqElse &);
- void visit (AST::IfLetExpr &);
- void visit (AST::IfLetExprConseqElse &);
- void visit (AST::MatchExpr &);
- void visit (AST::AwaitExpr &);
- void visit (AST::AsyncBlockExpr &);
+ void visit (AST::ClosureExprInner &) override;
+ void visit (AST::ClosureExprInnerTyped &) override;
+ void visit (AST::MatchExpr &) override;
// Leaf visitors, which do nothing by default
- void visit (AST::DelimTokenTree &);
- void visit (AST::AttrInputMetaItemContainer &);
- void visit (AST::IdentifierExpr &);
- void visit (AST::LifetimeParam &);
- void visit (AST::ConstGenericParam &);
- void visit (AST::PathInExpression &);
- void visit (AST::TypePathSegmentGeneric &);
- void visit (AST::TypePathSegmentFunction &);
- void visit (AST::TypePath &);
- void visit (AST::QualifiedPathInExpression &);
- void visit (AST::QualifiedPathInType &);
- void visit (AST::LiteralExpr &);
- void visit (AST::AttrInputLiteral &);
- void visit (AST::AttrInputMacro &);
- void visit (AST::MetaItemLitExpr &);
- void visit (AST::MetaItemPathLit &);
- void visit (AST::StructExprStruct &);
- void visit (AST::StructExprStructFields &);
- void visit (AST::StructExprStructBase &);
- void visit (AST::TypeParam &);
- void visit (AST::LifetimeWhereClauseItem &);
- void visit (AST::TypeBoundWhereClauseItem &);
- void visit (AST::ExternCrate &);
- void visit (AST::UseTreeGlob &);
- void visit (AST::UseTreeList &);
- void visit (AST::UseTreeRebind &);
- void visit (AST::UseDeclaration &);
- void visit (AST::TypeAlias &);
- void visit (AST::EnumItem &);
- void visit (AST::EnumItemTuple &);
- void visit (AST::EnumItemStruct &);
- void visit (AST::EnumItemDiscriminant &);
- void visit (AST::ConstantItem &);
- void visit (AST::StaticItem &);
- void visit (AST::TraitItemConst &);
- void visit (AST::TraitItemType &);
- void visit (AST::ExternalTypeItem &);
- void visit (AST::ExternalStaticItem &);
- void visit (AST::MacroMatchRepetition &);
- void visit (AST::MacroMatcher &);
- void visit (AST::MacroRulesDefinition &);
- void visit (AST::MacroInvocation &);
- void visit (AST::MetaItemPath &);
- void visit (AST::MetaItemSeq &);
- void visit (AST::MetaListPaths &);
- void visit (AST::MetaListNameValueStr &);
- void visit (AST::RangePatternBoundPath &);
- void visit (AST::RangePatternBoundQualPath &);
- void visit (AST::RangePattern &);
- void visit (AST::ReferencePattern &);
- void visit (AST::StructPatternFieldTuplePat &);
- void visit (AST::StructPatternFieldIdentPat &);
- void visit (AST::StructPatternFieldIdent &);
- void visit (AST::StructPattern &);
- void visit (AST::TupleStructItemsNoRange &);
- void visit (AST::TupleStructItemsRange &);
- void visit (AST::TupleStructPattern &);
- void visit (AST::TuplePatternItemsMultiple &);
- void visit (AST::TuplePatternItemsRanged &);
- void visit (AST::TuplePattern &);
- void visit (AST::GroupedPattern &);
- void visit (AST::SlicePattern &);
- void visit (AST::AltPattern &);
- void visit (AST::EmptyStmt &);
- void visit (AST::TraitBound &);
- void visit (AST::ImplTraitType &);
- void visit (AST::TraitObjectType &);
- void visit (AST::ParenthesisedType &);
- void visit (AST::ImplTraitTypeOneBound &);
- void visit (AST::TraitObjectTypeOneBound &);
- void visit (AST::TupleType &);
- void visit (AST::ReferenceType &);
- void visit (AST::ArrayType &);
- void visit (AST::SliceType &);
- void visit (AST::BareFunctionType &);
- void visit (AST::FunctionParam &);
- void visit (AST::VariadicParam &);
- void visit (AST::SelfParam &);
+ void visit (AST::ConstantItem &) override;
+ void visit (AST::StaticItem &) override;
protected:
DefaultResolver (NameResolutionContext &ctx) : ctx (ctx) {}
diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
index 1b21e11..3390f09 100644
--- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
@@ -18,13 +18,18 @@
#include "rust-early-name-resolver-2.0.h"
#include "rust-ast-full.h"
+#include "rust-diagnostics.h"
#include "rust-toplevel-name-resolver-2.0.h"
#include "rust-attributes.h"
+#include "rust-finalize-imports-2.0.h"
+#include "rust-attribute-values.h"
namespace Rust {
namespace Resolver2_0 {
-Early::Early (NameResolutionContext &ctx) : DefaultResolver (ctx) {}
+Early::Early (NameResolutionContext &ctx)
+ : DefaultResolver (ctx), toplevel (TopLevel (ctx)), dirty (false)
+{}
void
Early::insert_once (AST::MacroInvocation &invocation, NodeId resolved)
@@ -48,19 +53,117 @@ void
Early::go (AST::Crate &crate)
{
// First we go through TopLevel resolution to get all our declared items
- auto toplevel = TopLevel (ctx);
toplevel.go (crate);
- textual_scope.push ();
+ // We start with resolving the list of imports that `TopLevel` has built for
+ // us
- // Then we proceed to the proper "early" name resolution: Import and macro
- // name resolution
+ dirty = toplevel.is_dirty ();
+ // We now proceed with resolving macros, which can be nested in almost any
+ // items
+ textual_scope.push ();
for (auto &item : crate.items)
item->accept_vis (*this);
-
textual_scope.pop ();
}
+bool
+Early::resolve_glob_import (NodeId use_dec_id, TopLevel::ImportKind &&glob)
+{
+ auto resolved = ctx.resolve_path (glob.to_resolve, Namespace::Types);
+ if (!resolved.has_value ())
+ return false;
+
+ auto result
+ = Analysis::Mappings::get ().lookup_ast_module (resolved->get_node_id ());
+ if (!result)
+ return false;
+
+ // here, we insert the module's NodeId into the import_mappings and will look
+ // up the module proper in `FinalizeImports`
+ // The namespace does not matter here since we are dealing with a glob
+ // TODO: Ugly
+ import_mappings.insert (use_dec_id,
+ ImportPair (std::move (glob),
+ ImportData::Glob (*resolved)));
+
+ return true;
+}
+
+bool
+Early::resolve_simple_import (NodeId use_dec_id, TopLevel::ImportKind &&import)
+{
+ auto definitions = resolve_path_in_all_ns (import.to_resolve);
+
+ // if we've found at least one definition, then we're good
+ if (definitions.empty ())
+ return false;
+
+ auto &imports = import_mappings.new_or_access (use_dec_id);
+
+ imports.emplace_back (
+ ImportPair (std::move (import),
+ ImportData::Simple (std::move (definitions))));
+
+ return true;
+}
+
+bool
+Early::resolve_rebind_import (NodeId use_dec_id,
+ TopLevel::ImportKind &&rebind_import)
+{
+ auto definitions = resolve_path_in_all_ns (rebind_import.to_resolve);
+
+ // if we've found at least one definition, then we're good
+ if (definitions.empty ())
+ return false;
+
+ auto &imports = import_mappings.new_or_access (use_dec_id);
+
+ imports.emplace_back (
+ ImportPair (std::move (rebind_import),
+ ImportData::Rebind (std::move (definitions))));
+
+ return true;
+}
+
+void
+Early::build_import_mapping (
+ std::pair<NodeId, std::vector<TopLevel::ImportKind>> &&use_import)
+{
+ auto found = false;
+ auto use_dec_id = use_import.first;
+
+ for (auto &&import : use_import.second)
+ {
+ // We create a copy of the path in case of errors, since the `import` will
+ // be moved into the newly created import mappings
+ auto path = import.to_resolve;
+
+ // used to skip the "unresolved import" error
+ // if we output other errors during resolution
+ size_t old_error_count = macro_resolve_errors.size ();
+
+ switch (import.kind)
+ {
+ case TopLevel::ImportKind::Kind::Glob:
+ found = resolve_glob_import (use_dec_id, std::move (import));
+ break;
+ case TopLevel::ImportKind::Kind::Simple:
+ found = resolve_simple_import (use_dec_id, std::move (import));
+ break;
+ case TopLevel::ImportKind::Kind::Rebind:
+ found = resolve_rebind_import (use_dec_id, std::move (import));
+ break;
+ }
+
+ if (!found && old_error_count == macro_resolve_errors.size ())
+ collect_error (Error (path.get_final_segment ().get_locus (),
+ ErrorCode::E0433, "unresolved import %qs",
+ path.as_string ().c_str ()));
+ }
+}
+
void
Early::TextualScope::push ()
{
@@ -123,11 +226,24 @@ Early::visit (AST::BlockExpr &block)
void
Early::visit (AST::Module &module)
{
- textual_scope.push ();
+ bool is_macro_use = false;
+
+ for (const auto &attr : module.get_outer_attrs ())
+ {
+ if (attr.get_path ().as_string () == Values::Attributes::MACRO_USE)
+ {
+ is_macro_use = true;
+ break;
+ }
+ }
+
+ if (!is_macro_use)
+ textual_scope.push ();
DefaultResolver::visit (module);
- textual_scope.pop ();
+ if (!is_macro_use)
+ textual_scope.pop ();
}
void
@@ -135,6 +251,10 @@ Early::visit (AST::MacroInvocation &invoc)
{
auto path = invoc.get_invoc_data ().get_path ();
+ if (invoc.get_kind () == AST::MacroInvocation::InvocKind::Builtin)
+ for (auto &pending_invoc : invoc.get_pending_eager_invocations ())
+ pending_invoc->accept_vis (*this);
+
// When a macro is invoked by an unqualified identifier (not part of a
// multi-part path), it is first looked up in textual scoping. If this does
// not yield any results, then it is looked up in path-based scoping. If the
@@ -152,13 +272,14 @@ Early::visit (AST::MacroInvocation &invoc)
// we won't have changed `definition` from `nullopt` if there are more
// than one segments in our path
if (!definition.has_value ())
- definition = ctx.macros.resolve_path (path.get_segments ());
+ definition = ctx.resolve_path (path.get_segments (), Namespace::Macros);
// if the definition still does not have a value, then it's an error
if (!definition.has_value ())
{
collect_error (Error (invoc.get_locus (), ErrorCode::E0433,
- "could not resolve macro invocation"));
+ "could not resolve macro invocation %qs",
+ path.as_string ().c_str ()));
return;
}
@@ -193,36 +314,37 @@ Early::visit_attributes (std::vector<AST::Attribute> &attrs)
auto traits = attr.get_traits_to_derive ();
for (auto &trait : traits)
{
- auto definition
- = ctx.macros.resolve_path (trait.get ().get_segments ());
+ auto definition = ctx.resolve_path (trait.get ().get_segments (),
+ Namespace::Macros);
if (!definition.has_value ())
{
// FIXME: Change to proper error message
- rust_error_at (trait.get ().get_locus (),
- "could not resolve trait");
+ collect_error (Error (trait.get ().get_locus (),
+ "could not resolve trait %qs",
+ trait.get ().as_string ().c_str ()));
continue;
}
auto pm_def = mappings.lookup_derive_proc_macro_def (
definition->get_node_id ());
- rust_assert (pm_def.has_value ());
-
- mappings.insert_derive_proc_macro_invocation (trait,
- pm_def.value ());
+ if (pm_def.has_value ())
+ mappings.insert_derive_proc_macro_invocation (trait,
+ pm_def.value ());
}
}
else if (Analysis::BuiltinAttributeMappings::get ()
->lookup_builtin (name)
.is_error ()) // Do not resolve builtins
{
- auto definition
- = ctx.macros.resolve_path (attr.get_path ().get_segments ());
+ auto definition = ctx.resolve_path (attr.get_path ().get_segments (),
+ Namespace::Macros);
if (!definition.has_value ())
{
// FIXME: Change to proper error message
- rust_error_at (attr.get_locus (),
- "could not resolve attribute macro invocation");
+ collect_error (
+ Error (attr.get_locus (),
+ "could not resolve attribute macro invocation"));
return;
}
auto pm_def = mappings.lookup_attribute_proc_macro_def (
@@ -250,5 +372,103 @@ Early::visit (AST::StructStruct &s)
DefaultResolver::visit (s);
}
+void
+Early::finalize_simple_import (const Early::ImportPair &mapping)
+{
+ // FIXME: We probably need to store namespace information
+
+ auto locus = mapping.import_kind.to_resolve.get_locus ();
+ auto data = mapping.data;
+ auto identifier
+ = mapping.import_kind.to_resolve.get_final_segment ().get_segment_name ();
+
+ for (auto &&definition : data.definitions ())
+ toplevel
+ .insert_or_error_out (
+ identifier, locus, definition.first.get_node_id (), definition.second /* TODO: This isn't clear - it would be better if it was called .ns or something */);
+}
+
+void
+Early::finalize_glob_import (NameResolutionContext &ctx,
+ const Early::ImportPair &mapping)
+{
+ auto module = Analysis::Mappings::get ().lookup_ast_module (
+ mapping.data.module ().get_node_id ());
+ rust_assert (module);
+
+ GlobbingVisitor glob_visitor (ctx);
+ glob_visitor.go (module.value ());
+}
+
+void
+Early::finalize_rebind_import (const Early::ImportPair &mapping)
+{
+ // We can fetch the value here as `resolve_rebind` will only be called on
+ // imports of the right kind
+ auto &path = mapping.import_kind.to_resolve;
+ auto &rebind = mapping.import_kind.rebind.value ();
+ auto data = mapping.data;
+
+ location_t locus = UNKNOWN_LOCATION;
+ std::string declared_name;
+
+ // FIXME: This needs to be done in `FinalizeImports`
+ switch (rebind.get_new_bind_type ())
+ {
+ case AST::UseTreeRebind::NewBindType::IDENTIFIER:
+ declared_name = rebind.get_identifier ().as_string ();
+ locus = rebind.get_identifier ().get_locus ();
+ break;
+ case AST::UseTreeRebind::NewBindType::NONE: {
+ const auto &segments = path.get_segments ();
+ // We don't want to insert `self` with `use module::self`
+ if (path.get_final_segment ().is_lower_self_seg ())
+ {
+ rust_assert (segments.size () > 1);
+ declared_name = segments[segments.size () - 2].as_string ();
+ }
+ else
+ declared_name = path.get_final_segment ().as_string ();
+ locus = path.get_final_segment ().get_locus ();
+ break;
+ }
+ case AST::UseTreeRebind::NewBindType::WILDCARD:
+ rust_unreachable ();
+ break;
+ }
+
+ for (auto &&definition : data.definitions ())
+ toplevel.insert_or_error_out (
+ declared_name, locus, definition.first.get_node_id (), definition.second /* TODO: This isn't clear - it would be better if it was called .ns or something */);
+}
+
+void
+Early::visit (AST::UseDeclaration &decl)
+{
+ auto &imports = toplevel.get_imports_to_resolve ();
+ auto current_import = imports.find (decl.get_node_id ());
+ if (current_import != imports.end ())
+ {
+ build_import_mapping (*current_import);
+ }
+
+ // Once this is done, we finalize their resolution
+ for (const auto &mapping : import_mappings.get (decl.get_node_id ()))
+ switch (mapping.import_kind.kind)
+ {
+ case TopLevel::ImportKind::Kind::Glob:
+ finalize_glob_import (ctx, mapping);
+ break;
+ case TopLevel::ImportKind::Kind::Simple:
+ finalize_simple_import (mapping);
+ break;
+ case TopLevel::ImportKind::Kind::Rebind:
+ finalize_rebind_import (mapping);
+ break;
+ }
+
+ DefaultResolver::visit (decl);
+}
+
} // namespace Resolver2_0
} // namespace Rust
diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.h b/gcc/rust/resolve/rust-early-name-resolver-2.0.h
index 590a256..e78bec0 100644
--- a/gcc/rust/resolve/rust-early-name-resolver-2.0.h
+++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.h
@@ -24,6 +24,8 @@
#include "rust-ast-visitor.h"
#include "rust-name-resolution-context.h"
#include "rust-default-resolver.h"
+#include "rust-rib.h"
+#include "rust-toplevel-name-resolver-2.0.h"
namespace Rust {
namespace Resolver2_0 {
@@ -32,9 +34,14 @@ class Early : public DefaultResolver
{
using DefaultResolver::visit;
+ TopLevel toplevel;
+ bool dirty;
+
public:
Early (NameResolutionContext &ctx);
+ bool is_dirty () { return dirty; }
+
void go (AST::Crate &crate);
const std::vector<Error> &get_macro_resolve_errors () const
@@ -53,6 +60,111 @@ public:
void visit (AST::Function &) override;
void visit (AST::StructStruct &) override;
+ void visit (AST::UseDeclaration &) override;
+
+ struct ImportData
+ {
+ enum class Kind
+ {
+ Simple,
+ Glob,
+ Rebind
+ } kind;
+
+ static ImportData
+ Simple (std::vector<std::pair<Rib::Definition, Namespace>> &&definitions)
+ {
+ return ImportData (Kind::Simple, std::move (definitions));
+ }
+
+ static ImportData
+ Rebind (std::vector<std::pair<Rib::Definition, Namespace>> &&definitions)
+ {
+ return ImportData (Kind::Rebind, std::move (definitions));
+ }
+
+ static ImportData Glob (Rib::Definition module)
+ {
+ return ImportData (Kind::Glob, module);
+ }
+
+ Rib::Definition module () const
+ {
+ rust_assert (kind == Kind::Glob);
+ return glob_module;
+ }
+
+ std::vector<std::pair<Rib::Definition, Namespace>> definitions () const
+ {
+ rust_assert (kind != Kind::Glob);
+ return std::move (resolved_definitions);
+ }
+
+ private:
+ ImportData (
+ Kind kind,
+ std::vector<std::pair<Rib::Definition, Namespace>> &&definitions)
+ : kind (kind), resolved_definitions (std::move (definitions))
+ {}
+
+ ImportData (Kind kind, Rib::Definition module)
+ : kind (kind), glob_module (module)
+ {}
+
+ // TODO: Should this be a union?
+
+ // For Simple and Rebind
+ std::vector<std::pair<Rib::Definition, Namespace>> resolved_definitions;
+
+ // For Glob
+ Rib::Definition glob_module;
+ };
+
+ struct ImportPair
+ {
+ TopLevel::ImportKind import_kind;
+ ImportData data;
+
+ explicit ImportPair (TopLevel::ImportKind &&kind, ImportData &&data)
+ : import_kind (std::move (kind)), data (std::move (data))
+ {}
+ };
+
+ class ImportMappings
+ {
+ public:
+ std::vector<ImportPair> &new_or_access (NodeId path_id)
+ {
+ // We insert an empty vector, unless an element was already present for
+ // `use_dec_id` - which is returned in the tuple's first member
+ auto iter = mappings.insert ({{path_id}, {}});
+
+ // We then get that tuple's first member, which will be an iterator to the
+ // existing vec<pair<ImportKind, ImportData>> OR an iterator to our newly
+ // created empty vector (plus its key since this is a hashmap iterator).
+ // we then access the second member of the pair to get access to the
+ // vector directly.
+ return iter.first->second;
+ }
+
+ void insert (NodeId path_id, std::vector<ImportPair> &&pairs)
+ {
+ mappings.insert ({{path_id}, std::move (pairs)});
+ }
+
+ // Same as `insert`, but with just one node
+ void insert (NodeId path_id, ImportPair &&pair)
+ {
+ mappings.insert ({{path_id}, {pair}});
+ }
+
+ std::vector<ImportPair> &get (NodeId use_id) { return mappings[use_id]; }
+
+ private:
+ // Each path can import in multiple namespaces, hence the mapping from one
+ // path to a vector of import pairs
+ std::unordered_map<NodeId, std::vector<ImportPair>> mappings;
+ };
private:
void visit_attributes (std::vector<AST::Attribute> &attrs);
@@ -91,10 +203,66 @@ private:
std::vector<std::unordered_map<std::string, NodeId>> scopes;
};
+ // Mappings between an import and the definition it imports
+ ImportMappings import_mappings;
+
+ // FIXME: Documentation
+ // Call this on all the paths of a UseDec - so each flattened path in a
+ // UseTreeList for example
+ // FIXME: Should that return `found`?
+ bool resolve_simple_import (NodeId use_dec_id, TopLevel::ImportKind &&import);
+ bool resolve_glob_import (NodeId use_dec_id, TopLevel::ImportKind &&import);
+ bool resolve_rebind_import (NodeId use_dec_id, TopLevel::ImportKind &&import);
+
+ template <typename P>
+ std::vector<std::pair<Rib::Definition, Namespace>>
+ resolve_path_in_all_ns (const P &path)
+ {
+ std::vector<std::pair<Rib::Definition, Namespace>> resolved;
+
+ // Pair a definition with the namespace it was found in
+ auto pair_with_ns = [&] (Namespace ns) {
+ return [&, ns] (Rib::Definition def) {
+ auto pair = std::make_pair (def, ns);
+ return resolved.emplace_back (std::move (pair));
+ };
+ };
+
+ std::vector<Error> value_errors;
+ std::vector<Error> type_errors;
+ std::vector<Error> macro_errors;
+
+ ctx.resolve_path (path, value_errors, Namespace::Values)
+ .map (pair_with_ns (Namespace::Values));
+ ctx.resolve_path (path, type_errors, Namespace::Types)
+ .map (pair_with_ns (Namespace::Types));
+ ctx.resolve_path (path, macro_errors, Namespace::Macros)
+ .map (pair_with_ns (Namespace::Macros));
+
+ if (!value_errors.empty () && !type_errors.empty ()
+ && !macro_errors.empty ())
+ for (auto &ent : value_errors)
+ collect_error (std::move (ent));
+
+ return resolved;
+ }
+
+ // Handle an import, resolving it to its definition and adding it to the list
+ // of import mappings
+ void build_import_mapping (
+ std::pair<NodeId, std::vector<TopLevel::ImportKind>> &&use_import);
+
TextualScope textual_scope;
std::vector<Error> macro_resolve_errors;
void collect_error (Error e) { macro_resolve_errors.push_back (e); }
+
+ void finalize_simple_import (const Early::ImportPair &mapping);
+
+ void finalize_glob_import (NameResolutionContext &ctx,
+ const Early::ImportPair &mapping);
+
+ void finalize_rebind_import (const Early::ImportPair &mapping);
};
} // namespace Resolver2_0
diff --git a/gcc/rust/resolve/rust-early-name-resolver.cc b/gcc/rust/resolve/rust-early-name-resolver.cc
index ce427dd..fc9a26c 100644
--- a/gcc/rust/resolve/rust-early-name-resolver.cc
+++ b/gcc/rust/resolve/rust-early-name-resolver.cc
@@ -17,7 +17,7 @@
// <http://www.gnu.org/licenses/>.
#include "rust-early-name-resolver.h"
-#include "rust-ast-full.h"
+#include "rust-pattern.h"
#include "rust-name-resolver.h"
#include "rust-macro-builtins.h"
#include "rust-attribute-values.h"
@@ -53,7 +53,7 @@ EarlyNameResolver::accumulate_escaped_macros (AST::Module &module)
scoped (module.get_node_id (), [&module, &escaped_macros, this] {
for (auto &item : module.get_items ())
{
- if (item->get_ast_kind () == AST::Kind::MODULE)
+ if (item->get_item_kind () == AST::Item::Kind::Module)
{
auto &module = *static_cast<AST::Module *> (item.get ());
auto new_macros = accumulate_escaped_macros (module);
@@ -64,7 +64,7 @@ EarlyNameResolver::accumulate_escaped_macros (AST::Module &module)
continue;
}
- if (item->get_ast_kind () == AST::Kind::MACRO_RULES_DEFINITION)
+ if (item->get_item_kind () == AST::Item::Kind::MacroRulesDefinition)
escaped_macros.emplace_back (item->clone_item ());
}
});
@@ -113,7 +113,7 @@ EarlyNameResolver::visit (AST::Crate &crate)
{
auto new_macros = std::vector<std::unique_ptr<AST::Item>> ();
- if (item->get_ast_kind () == AST::Kind::MODULE)
+ if (item->get_item_kind () == AST::Item::Kind::Module)
new_macros = accumulate_escaped_macros (
*static_cast<AST::Module *> (item.get ()));
@@ -156,9 +156,10 @@ EarlyNameResolver::visit (AST::ConstGenericParam &)
void
EarlyNameResolver::visit (AST::PathInExpression &path)
{
- for (auto &segment : path.get_segments ())
- if (segment.has_generic_args ())
- resolve_generic_args (segment.get_generic_args ());
+ if (!path.is_lang_item ())
+ for (auto &segment : path.get_segments ())
+ if (segment.has_generic_args ())
+ resolve_generic_args (segment.get_generic_args ());
}
void
@@ -300,7 +301,7 @@ EarlyNameResolver::visit (AST::Module &module)
{
auto new_macros = std::vector<std::unique_ptr<AST::Item>> ();
- if (item->get_ast_kind () == AST::Kind::MODULE)
+ if (item->get_item_kind () == AST::Item::Kind::Module)
new_macros = accumulate_escaped_macros (
*static_cast<AST::Module *> (item.get ()));
@@ -353,6 +354,8 @@ EarlyNameResolver::visit (AST::TraitItemType &)
void
EarlyNameResolver::visit (AST::Trait &trait)
{
+ // shouldn't need to visit trait.get_implicit_self ()
+
for (auto &generic : trait.get_generic_params ())
generic->accept_vis (*this);
@@ -474,7 +477,8 @@ EarlyNameResolver::visit (AST::MacroInvocation &invoc)
bool found = resolver.get_macro_scope ().lookup (seg, &resolved_node);
if (!found)
{
- rust_error_at (invoc.get_locus (), "unknown macro: [%s]",
+ rust_error_at (invoc.get_locus (), ErrorCode::E0433,
+ "could not resolve macro invocation %qs",
seg.get ().c_str ());
return;
}
@@ -558,30 +562,6 @@ EarlyNameResolver::visit (AST::TupleStructPattern &pattern)
}
void
-EarlyNameResolver::visit (AST::TraitBound &)
-{}
-
-void
-EarlyNameResolver::visit (AST::ImplTraitType &)
-{}
-
-void
-EarlyNameResolver::visit (AST::TraitObjectType &)
-{}
-
-void
-EarlyNameResolver::visit (AST::ParenthesisedType &)
-{}
-
-void
-EarlyNameResolver::visit (AST::ImplTraitTypeOneBound &)
-{}
-
-void
-EarlyNameResolver::visit (AST::TraitObjectTypeOneBound &)
-{}
-
-void
EarlyNameResolver::visit (AST::TupleType &)
{}
diff --git a/gcc/rust/resolve/rust-early-name-resolver.h b/gcc/rust/resolve/rust-early-name-resolver.h
index 48562df..26fc84d 100644
--- a/gcc/rust/resolve/rust-early-name-resolver.h
+++ b/gcc/rust/resolve/rust-early-name-resolver.h
@@ -36,6 +36,7 @@ public:
private:
using AST::DefaultASTVisitor::visit;
+
/**
* Execute a lambda within a scope. This is equivalent to calling
* `enter_scope` before your code and `exit_scope` after. This ensures
@@ -181,12 +182,6 @@ private:
virtual void visit (AST::StructPatternFieldIdent &field);
virtual void visit (AST::StructPattern &pattern);
virtual void visit (AST::TupleStructPattern &pattern);
- virtual void visit (AST::TraitBound &bound);
- virtual void visit (AST::ImplTraitType &type);
- virtual void visit (AST::TraitObjectType &type);
- virtual void visit (AST::ParenthesisedType &type);
- virtual void visit (AST::ImplTraitTypeOneBound &type);
- virtual void visit (AST::TraitObjectTypeOneBound &type);
virtual void visit (AST::TupleType &type);
virtual void visit (AST::RawPointerType &type);
virtual void visit (AST::ReferenceType &type);
diff --git a/gcc/rust/resolve/rust-finalize-imports-2.0.cc b/gcc/rust/resolve/rust-finalize-imports-2.0.cc
new file mode 100644
index 0000000..b0e8651
--- /dev/null
+++ b/gcc/rust/resolve/rust-finalize-imports-2.0.cc
@@ -0,0 +1,129 @@
+// Copyright (C) 2020-2024 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-finalize-imports-2.0.h"
+#include "rust-default-resolver.h"
+#include "rust-hir-map.h"
+#include "rust-name-resolution-context.h"
+#include "rust-rib.h"
+#include "rust-toplevel-name-resolver-2.0.h"
+
+namespace Rust {
+namespace Resolver2_0 {
+
+void
+GlobbingVisitor::go (AST::Module *module)
+{
+ for (auto &i : module->get_items ())
+ visit (i);
+}
+
+void
+GlobbingVisitor::visit (AST::Module &module)
+{
+ if (module.get_visibility ().is_public ())
+ ctx.insert_globbed (module.get_name (), module.get_node_id (),
+ Namespace::Types);
+}
+
+void
+GlobbingVisitor::visit (AST::MacroRulesDefinition &macro)
+{
+ if (macro.get_visibility ().is_public ())
+ ctx.insert_globbed (macro.get_rule_name (), macro.get_node_id (),
+ Namespace::Macros);
+}
+
+void
+GlobbingVisitor::visit (AST::Function &function)
+{
+ if (function.get_visibility ().is_public ())
+ ctx.insert_globbed (function.get_function_name (), function.get_node_id (),
+ Namespace::Values);
+}
+
+void
+GlobbingVisitor::visit (AST::StaticItem &static_item)
+{
+ if (static_item.get_visibility ().is_public ())
+ ctx.insert_globbed (static_item.get_identifier (),
+ static_item.get_node_id (), Namespace::Values);
+}
+
+void
+GlobbingVisitor::visit (AST::StructStruct &struct_item)
+{
+ if (struct_item.get_visibility ().is_public ())
+ {
+ ctx.insert_globbed (struct_item.get_identifier (),
+ struct_item.get_node_id (), Namespace::Types);
+ if (struct_item.is_unit_struct ())
+ ctx.insert_globbed (struct_item.get_identifier (),
+ struct_item.get_node_id (), Namespace::Values);
+ }
+}
+
+void
+GlobbingVisitor::visit (AST::TupleStruct &tuple_struct)
+{
+ if (tuple_struct.get_visibility ().is_public ())
+ {
+ ctx.insert_globbed (tuple_struct.get_identifier (),
+ tuple_struct.get_node_id (), Namespace::Types);
+
+ ctx.insert_globbed (tuple_struct.get_identifier (),
+ tuple_struct.get_node_id (), Namespace::Values);
+ }
+}
+
+void
+GlobbingVisitor::visit (AST::Enum &enum_item)
+{
+ if (enum_item.get_visibility ().is_public ())
+ ctx.insert_globbed (enum_item.get_identifier (), enum_item.get_node_id (),
+ Namespace::Types);
+}
+
+void
+GlobbingVisitor::visit (AST::Union &union_item)
+{
+ if (union_item.get_visibility ().is_public ())
+ ctx.insert_globbed (union_item.get_identifier (), union_item.get_node_id (),
+ Namespace::Values);
+}
+
+void
+GlobbingVisitor::visit (AST::ConstantItem &const_item)
+{
+ if (const_item.get_visibility ().is_public ())
+ ctx.insert_globbed (const_item.get_identifier (), const_item.get_node_id (),
+ Namespace::Values);
+}
+
+void
+GlobbingVisitor::visit (AST::ExternCrate &crate)
+{}
+
+void
+GlobbingVisitor::visit (AST::UseDeclaration &use)
+{
+ // Handle cycles ?
+}
+
+} // namespace Resolver2_0
+} // namespace Rust
diff --git a/gcc/rust/resolve/rust-finalize-imports-2.0.h b/gcc/rust/resolve/rust-finalize-imports-2.0.h
new file mode 100644
index 0000000..d587a5e
--- /dev/null
+++ b/gcc/rust/resolve/rust-finalize-imports-2.0.h
@@ -0,0 +1,53 @@
+// Copyright (C) 2020-2024 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast.h"
+#include "rust-expr.h"
+#include "rust-name-resolution-context.h"
+#include "rust-toplevel-name-resolver-2.0.h"
+#include "rust-early-name-resolver-2.0.h"
+
+namespace Rust {
+namespace Resolver2_0 {
+
+class GlobbingVisitor : public AST::DefaultASTVisitor
+{
+ using AST::DefaultASTVisitor::visit;
+
+public:
+ GlobbingVisitor (NameResolutionContext &ctx) : ctx (ctx) {}
+
+ void go (AST::Module *module);
+ void visit (AST::Module &module) override;
+ void visit (AST::MacroRulesDefinition &macro) override;
+ void visit (AST::Function &function) override;
+ void visit (AST::StaticItem &static_item) override;
+ void visit (AST::StructStruct &struct_item) override;
+ void visit (AST::TupleStruct &tuple_struct) override;
+ void visit (AST::Enum &enum_item) override;
+ void visit (AST::Union &union_item) override;
+ void visit (AST::ConstantItem &const_item) override;
+ void visit (AST::ExternCrate &crate) override;
+ void visit (AST::UseDeclaration &use) override;
+
+private:
+ NameResolutionContext &ctx;
+};
+
+} // namespace Resolver2_0
+} // namespace Rust
diff --git a/gcc/rust/resolve/rust-forever-stack.cc b/gcc/rust/resolve/rust-forever-stack.cc
new file mode 100644
index 0000000..725ae0e
--- /dev/null
+++ b/gcc/rust/resolve/rust-forever-stack.cc
@@ -0,0 +1,318 @@
+// Copyright (C) 2024 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "expected.h"
+#include "rust-ast.h"
+#include "rust-diagnostics.h"
+#include "rust-forever-stack.h"
+#include "rust-rib.h"
+#include "optional.h"
+
+namespace Rust {
+namespace Resolver2_0 {
+
+bool
+ForeverStackStore::Node::is_root () const
+{
+ return !parent.has_value ();
+}
+
+bool
+ForeverStackStore::Node::is_leaf () const
+{
+ return children.empty ();
+}
+
+NodeId
+ForeverStackStore::Node::get_id () const
+{
+ return id;
+}
+
+ForeverStackStore::Node &
+ForeverStackStore::Node::insert_child (NodeId id, tl::optional<Identifier> path,
+ Rib::Kind kind)
+{
+ auto res = children.insert ({Link (id, path), Node (kind, id, *this)});
+
+ rust_debug ("inserting link: Link(%d [%s]): existed? %s", id,
+ path.has_value () ? path.value ().as_string ().c_str ()
+ : "<anon>",
+ !res.second ? "yes" : "no");
+
+ // sanity check on rib kind
+ // pick the value rib, since all ribs should have the same kind anyways
+ rust_assert (res.second || res.first->second.value_rib.kind == kind);
+
+ // verify, if we're using an existing node, our paths don't contradict
+ if (!res.second && path.has_value ())
+ {
+ auto other_path = res.first->first.path;
+ rust_assert (!other_path.has_value ()
+ || other_path.value ().as_string ()
+ == path.value ().as_string ());
+ }
+
+ return res.first->second;
+}
+
+tl::optional<ForeverStackStore::Node &>
+ForeverStackStore::Node::get_child (const Identifier &path)
+{
+ for (auto &ent : children)
+ {
+ if (ent.first.path.has_value ()
+ && ent.first.path->as_string () == path.as_string ())
+ return ent.second;
+ }
+ return tl::nullopt;
+}
+
+tl::optional<const ForeverStackStore::Node &>
+ForeverStackStore::Node::get_child (const Identifier &path) const
+{
+ for (auto &ent : children)
+ {
+ if (ent.first.path.has_value ()
+ && ent.first.path->as_string () == path.as_string ())
+ return ent.second;
+ }
+ return tl::nullopt;
+}
+
+tl::optional<ForeverStackStore::Node &>
+ForeverStackStore::Node::get_parent ()
+{
+ return parent;
+}
+
+tl::optional<const ForeverStackStore::Node &>
+ForeverStackStore::Node::get_parent () const
+{
+ if (parent)
+ return *parent;
+ return tl::nullopt;
+}
+
+tl::optional<const Identifier &>
+ForeverStackStore::Node::get_parent_path () const
+{
+ if (parent.has_value ())
+ for (auto &ent : parent->children)
+ if (ent.first.id == id && ent.first.path.has_value ())
+ return ent.first.path.value ();
+ return tl::nullopt;
+}
+
+Rib &
+ForeverStackStore::Node::get_rib (Namespace ns)
+{
+ switch (ns)
+ {
+ case Namespace::Values:
+ return value_rib;
+ case Namespace::Types:
+ return type_rib;
+ case Namespace::Labels:
+ return label_rib;
+ case Namespace::Macros:
+ return macro_rib;
+ default:
+ rust_unreachable ();
+ }
+}
+
+const Rib &
+ForeverStackStore::Node::get_rib (Namespace ns) const
+{
+ switch (ns)
+ {
+ case Namespace::Values:
+ return value_rib;
+ case Namespace::Types:
+ return type_rib;
+ case Namespace::Labels:
+ return label_rib;
+ case Namespace::Macros:
+ return macro_rib;
+ default:
+ rust_unreachable ();
+ }
+}
+
+tl::expected<NodeId, DuplicateNameError>
+ForeverStackStore::Node::insert (const Identifier &name, NodeId node,
+ Namespace ns)
+{
+ // So what do we do here - if the Rib has already been pushed in an earlier
+ // pass, we might end up in a situation where it is okay to re-add new names.
+ // Do we just ignore that here? Do we keep track of if the Rib is new or not?
+ // should our cursor have info on the current node like "is it newly pushed"?
+ return get_rib (ns).insert (name.as_string (),
+ Rib::Definition::NonShadowable (node));
+}
+
+tl::expected<NodeId, DuplicateNameError>
+ForeverStackStore::Node::insert_shadowable (const Identifier &name, NodeId node,
+ Namespace ns)
+{
+ return get_rib (ns).insert (name.as_string (),
+ Rib::Definition::Shadowable (node));
+}
+
+tl::expected<NodeId, DuplicateNameError>
+ForeverStackStore::Node::insert_globbed (const Identifier &name, NodeId node,
+ Namespace ns)
+{
+ return get_rib (ns).insert (name.as_string (),
+ Rib::Definition::Globbed (node));
+}
+
+void
+ForeverStackStore::Node::reverse_iter (std::function<KeepGoing (Node &)> lambda)
+{
+ for (Node *tmp = this; lambda (*tmp) == KeepGoing::Yes && !tmp->is_root ();
+ tmp = &tmp->parent.value ())
+ ;
+}
+
+void
+ForeverStackStore::Node::reverse_iter (
+ std::function<KeepGoing (const Node &)> lambda) const
+{
+ for (const Node *tmp = this;
+ lambda (*tmp) == KeepGoing::Yes && !tmp->is_root ();
+ tmp = &tmp->parent.value ())
+ ;
+}
+
+void
+ForeverStackStore::Node::child_iter (
+ std::function<KeepGoing (NodeId, tl::optional<const Identifier &>, Node &)>
+ lambda)
+{
+ for (auto &ent : children)
+ {
+ tl::optional<const Identifier &> path;
+ if (ent.first.path.has_value ())
+ path = ent.first.path.value ();
+ auto keep_going = lambda (ent.first.id, path, ent.second);
+ if (keep_going == KeepGoing::No)
+ return;
+ }
+}
+
+void
+ForeverStackStore::Node::child_iter (
+ std::function<KeepGoing (NodeId, tl::optional<const Identifier &>,
+ const Node &)>
+ lambda) const
+{
+ for (auto &ent : children)
+ {
+ tl::optional<const Identifier &> path;
+ if (ent.first.path.has_value ())
+ path = ent.first.path.value ();
+ auto keep_going = lambda (ent.first.id, path, ent.second);
+ if (keep_going == KeepGoing::No)
+ return;
+ }
+}
+
+ForeverStackStore::Node &
+ForeverStackStore::Node::find_closest_module ()
+{
+ // get kind of value_rib
+ // but all ribs should share the same kind anyways
+ if (value_rib.kind == Rib::Kind::Module || !parent.has_value ())
+ return *this;
+ else
+ return parent->find_closest_module ();
+}
+
+const ForeverStackStore::Node &
+ForeverStackStore::Node::find_closest_module () const
+{
+ // get kind of value_rib
+ // but all ribs should share the same kind anyways
+ if (value_rib.kind != Rib::Kind::Module || !parent.has_value ())
+ return *this;
+ else
+ return parent->find_closest_module ();
+}
+
+tl::optional<ForeverStackStore::Node &>
+ForeverStackStore::Node::dfs_node (NodeId to_find)
+{
+ if (id == to_find)
+ return *this;
+
+ for (auto &child : children)
+ {
+ auto candidate = child.second.dfs_node (to_find);
+
+ if (candidate.has_value ())
+ return candidate;
+ }
+
+ return tl::nullopt;
+}
+
+tl::optional<const ForeverStackStore::Node &>
+ForeverStackStore::Node::dfs_node (NodeId to_find) const
+{
+ if (id == to_find)
+ return *this;
+
+ for (auto &child : children)
+ {
+ auto candidate = child.second.dfs_node (to_find);
+
+ if (candidate.has_value ())
+ return candidate;
+ }
+
+ return tl::nullopt;
+}
+
+ForeverStackStore::Node &
+ForeverStackStore::get_root ()
+{
+ return root;
+}
+
+const ForeverStackStore::Node &
+ForeverStackStore::get_root () const
+{
+ return root;
+}
+
+tl::optional<ForeverStackStore::Node &>
+ForeverStackStore::get_node (NodeId node_id)
+{
+ return root.dfs_node (node_id);
+}
+
+tl::optional<const ForeverStackStore::Node &>
+ForeverStackStore::get_node (NodeId node_id) const
+{
+ return root.dfs_node (node_id);
+}
+
+} // namespace Resolver2_0
+} // namespace Rust
diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h
index a9aca0f..81468e5 100644
--- a/gcc/rust/resolve/rust-forever-stack.h
+++ b/gcc/rust/resolve/rust-forever-stack.h
@@ -392,17 +392,173 @@ not contain any imports, macro definitions or macro invocations. You can look at
this pass's documentation for more details on this resolution process.
**/
+
+/**
+ * Intended for use by ForeverStack to store Nodes
+ * Unlike ForeverStack, does not store a cursor reference
+ * Intended to make path resolution in multiple namespaces simpler
+ **/
+class ForeverStackStore
+{
+public:
+ ForeverStackStore (NodeId crate_id) : root (Rib::Kind::Normal, crate_id)
+ {
+ rust_assert (root.is_root ());
+ rust_assert (root.is_leaf ());
+ }
+
+private:
+ /**
+ * A link between two Nodes in our trie data structure. This class represents
+ * the edges of the graph
+ */
+ class Link
+ {
+ public:
+ Link (NodeId id, tl::optional<Identifier> path) : id (id), path (path) {}
+
+ bool compare (const Link &other) const { return id < other.id; }
+
+ NodeId id;
+ tl::optional<Identifier> path;
+ };
+
+ /* Link comparison class, which we use in a Node's `children` map */
+ class LinkCmp
+ {
+ public:
+ bool operator() (const Link &lhs, const Link &rhs) const
+ {
+ return lhs.compare (rhs);
+ }
+ };
+
+public:
+ class Node;
+
+ struct DfsResult
+ {
+ Node &first;
+ std::string second;
+ };
+
+ struct ConstDfsResult
+ {
+ const Node &first;
+ std::string second;
+ };
+
+ /* Should we keep going upon seeing a Rib? */
+ enum class KeepGoing
+ {
+ Yes,
+ No,
+ };
+
+ class Node
+ {
+ private:
+ friend class ForeverStackStore::ForeverStackStore;
+
+ Node (Rib::Kind rib_kind, NodeId id, tl::optional<Node &> parent)
+ : value_rib (rib_kind), type_rib (rib_kind), label_rib (rib_kind),
+ macro_rib (rib_kind), id (id), parent (parent)
+ {}
+ Node (Rib::Kind rib_kind, NodeId id) : Node (rib_kind, id, tl::nullopt) {}
+ Node (Rib::Kind rib_kind, NodeId id, Node &parent)
+ : Node (rib_kind, id, tl::optional<Node &> (parent))
+ {}
+
+ public:
+ Node (const Node &) = default;
+ Node (Node &&) = default;
+ Node &operator= (const Node &) = delete;
+ Node &operator= (Node &&) = default;
+
+ bool is_root () const;
+ bool is_leaf () const;
+
+ NodeId get_id () const;
+
+ Node &insert_child (NodeId id, tl::optional<Identifier> path,
+ Rib::Kind kind);
+
+ tl::optional<Node &> get_child (const Identifier &path);
+ tl::optional<const Node &> get_child (const Identifier &path) const;
+
+ tl::optional<Node &> get_parent ();
+ tl::optional<const Node &> get_parent () const;
+
+ // finds the identifier, if any, used to link
+ // this node's parent to this node
+ tl::optional<const Identifier &> get_parent_path () const;
+
+ Rib &get_rib (Namespace ns);
+ const Rib &get_rib (Namespace ns) const;
+
+ tl::expected<NodeId, DuplicateNameError> insert (const Identifier &name,
+ NodeId node, Namespace ns);
+ tl::expected<NodeId, DuplicateNameError>
+ insert_shadowable (const Identifier &name, NodeId node, Namespace ns);
+ tl::expected<NodeId, DuplicateNameError>
+ insert_globbed (const Identifier &name, NodeId node, Namespace ns);
+
+ void reverse_iter (std::function<KeepGoing (Node &)> lambda);
+ void reverse_iter (std::function<KeepGoing (const Node &)> lambda) const;
+
+ void child_iter (std::function<KeepGoing (
+ NodeId, tl::optional<const Identifier &>, Node &)>
+ lambda);
+ void child_iter (std::function<KeepGoing (
+ NodeId, tl::optional<const Identifier &>, const Node &)>
+ lambda) const;
+
+ Node &find_closest_module ();
+ const Node &find_closest_module () const;
+
+ tl::optional<Node &> dfs_node (NodeId to_find);
+ tl::optional<const Node &> dfs_node (NodeId to_find) const;
+
+ private:
+ // per-namespace ribs
+ Rib value_rib;
+ Rib type_rib;
+ Rib label_rib;
+ Rib macro_rib;
+ // all linked nodes
+ std::map<Link, Node, LinkCmp> children;
+
+ NodeId id; // The node id of the Node's scope
+
+ tl::optional<Node &> parent; // `None` only if the node is a root
+ };
+
+ Node &get_root ();
+ const Node &get_root () const;
+
+ tl::optional<Node &> get_node (NodeId node_id);
+ tl::optional<const Node &> get_node (NodeId node_id) const;
+
+private:
+ Node root;
+};
+
template <Namespace N> class ForeverStack
{
public:
ForeverStack ()
- // FIXME: Is that valid? Do we use the root? If yes, we should give the
- // crate's node id to ForeverStack's constructor
: root (Node (Rib (Rib::Kind::Normal), UNKNOWN_NODEID)),
+ lang_prelude (Node (Rib (Rib::Kind::Prelude), UNKNOWN_NODEID, root)),
+ extern_prelude (Node (Rib (Rib::Kind::Prelude), UNKNOWN_NODEID)),
cursor_reference (root)
{
rust_assert (root.is_root ());
rust_assert (root.is_leaf ());
+
+ // TODO: Should we be using the forever stack root as the crate scope?
+ // TODO: Is this how we should be getting the crate node id?
+ auto &mappings = Analysis::Mappings::get ();
+ root.id = *mappings.crate_num_to_nodeid (mappings.get_current_crate ());
}
/**
@@ -416,7 +572,7 @@ public:
* @param path An optional path if the Rib was created due to a "named"
* lexical scope, like a module's.
*/
- void push (Rib rib, NodeId id, tl::optional<Identifier> path = {});
+ void push (Rib::Kind rib_kind, NodeId id, tl::optional<Identifier> path = {});
/**
* Pop the innermost Rib from the stack
@@ -437,6 +593,9 @@ public:
*/
tl::expected<NodeId, DuplicateNameError> insert (Identifier name, NodeId id);
+ tl::expected<NodeId, DuplicateNameError> insert_variant (Identifier name,
+ NodeId id);
+
/**
* Insert a new shadowable definition in the innermost `Rib` in this stack
*
@@ -453,6 +612,22 @@ public:
NodeId id);
/**
+ * Insert a new glob-originated definition in the innermost `Rib` in this
+ * stack
+ *
+ * @param name The name of the definition
+ * @param id Its NodeId
+ *
+ * @return `DuplicateNameError` if that node was already present in the Rib,
+ * the node's `NodeId` otherwise.
+ *
+ * @aborts if there are no `Rib`s inserted in the current map, this function
+ * aborts the program.
+ */
+ tl::expected<NodeId, DuplicateNameError> insert_globbed (Identifier name,
+ NodeId id);
+
+ /**
* Insert a new definition at the root of this stack
*
* @param name The name of the definition
@@ -484,6 +659,8 @@ public:
* the current map, an empty one otherwise.
*/
tl::optional<Rib::Definition> get (const Identifier &name);
+ tl::optional<Rib::Definition> get_lang_prelude (const Identifier &name);
+ tl::optional<Rib::Definition> get_lang_prelude (const std::string &name);
/**
* Resolve a path to its definition in the current `ForeverStack`
@@ -494,15 +671,25 @@ public:
* current map, an empty one otherwise.
*/
template <typename S>
- tl::optional<Rib::Definition> resolve_path (const std::vector<S> &segments);
+ tl::optional<Rib::Definition> resolve_path (
+ const std::vector<S> &segments, bool has_opening_scope_resolution,
+ std::function<void (const S &, NodeId)> insert_segment_resolution,
+ std::vector<Error> &collect_errors);
// FIXME: Documentation
- tl::optional<Resolver::CanonicalPath> to_canonical_path (NodeId id);
+ tl::optional<Resolver::CanonicalPath> to_canonical_path (NodeId id) const;
// FIXME: Documentation
tl::optional<Rib &> to_rib (NodeId rib_id);
+ tl::optional<const Rib &> to_rib (NodeId rib_id) const;
- std::string as_debug_string ();
+ std::string as_debug_string () const;
+
+ /**
+ * Used to check if a module is a descendant of another module
+ * Intended for use in the privacy checker
+ */
+ bool is_module_descendant (NodeId parent, NodeId child) const;
private:
/**
@@ -539,6 +726,7 @@ private:
{}
bool is_root () const;
+ bool is_prelude () const;
bool is_leaf () const;
void insert_child (Link link, Node child);
@@ -563,21 +751,36 @@ private:
/* Reverse iterate on `Node`s from the cursor, in an outwards fashion */
void reverse_iter (std::function<KeepGoing (Node &)> lambda);
+ void reverse_iter (std::function<KeepGoing (const Node &)> lambda) const;
/* Reverse iterate on `Node`s from a specified one, in an outwards fashion */
void reverse_iter (Node &start, std::function<KeepGoing (Node &)> lambda);
+ void reverse_iter (const Node &start,
+ std::function<KeepGoing (const Node &)> lambda) const;
Node &cursor ();
const Node &cursor () const;
void update_cursor (Node &new_cursor);
+ /* The forever stack's actual nodes */
Node root;
+ /*
+ * A special prelude node used currently for resolving language builtins
+ * It has the root node as a parent, and acts as a "special case" for name
+ * resolution
+ */
+ Node lang_prelude;
+ /*
+ * The extern prelude, used for resolving external crates
+ */
+ Node extern_prelude;
+
std::reference_wrapper<Node> cursor_reference;
void stream_rib (std::stringstream &stream, const Rib &rib,
- const std::string &next, const std::string &next_next);
+ const std::string &next, const std::string &next_next) const;
void stream_node (std::stringstream &stream, unsigned indentation,
- const Node &node);
+ const Node &node) const;
/* Helper types and functions for `resolve_path` */
@@ -587,13 +790,22 @@ private:
Node &find_closest_module (Node &starting_point);
template <typename S>
- tl::optional<SegIterator<S>>
- find_starting_point (const std::vector<S> &segments, Node &starting_point);
+ tl::optional<SegIterator<S>> find_starting_point (
+ const std::vector<S> &segments,
+ std::reference_wrapper<Node> &starting_point,
+ std::function<void (const S &, NodeId)> insert_segment_resolution,
+ std::vector<Error> &collect_errors);
template <typename S>
- tl::optional<Node &> resolve_segments (Node &starting_point,
- const std::vector<S> &segments,
- SegIterator<S> iterator);
+ tl::optional<Node &> resolve_segments (
+ Node &starting_point, const std::vector<S> &segments,
+ SegIterator<S> iterator,
+ std::function<void (const S &, NodeId)> insert_segment_resolution,
+ std::vector<Error> &collect_errors);
+
+ tl::optional<Rib::Definition> resolve_final_segment (Node &final_node,
+ std::string &seg_name,
+ bool is_lower_self);
/* Helper functions for forward resolution (to_canonical_path, to_rib...) */
struct DfsResult
@@ -601,11 +813,39 @@ private:
Node &first;
std::string second;
};
+ struct ConstDfsResult
+ {
+ const Node &first;
+ std::string second;
+ };
// FIXME: Documentation
tl::optional<DfsResult> dfs (Node &starting_point, NodeId to_find);
+ tl::optional<ConstDfsResult> dfs (const Node &starting_point,
+ NodeId to_find) const;
// FIXME: Documentation
tl::optional<Rib &> dfs_rib (Node &starting_point, NodeId to_find);
+ tl::optional<const Rib &> dfs_rib (const Node &starting_point,
+ NodeId to_find) const;
+ // FIXME: Documentation
+ tl::optional<Node &> dfs_node (Node &starting_point, NodeId to_find);
+ tl::optional<const Node &> dfs_node (const Node &starting_point,
+ NodeId to_find) const;
+
+public:
+ bool forward_declared (NodeId definition, NodeId usage)
+ {
+ if (peek ().kind != Rib::Kind::ForwardTypeParamBan)
+ return false;
+
+ const auto &definition_rib = dfs_rib (cursor (), definition);
+
+ if (!definition_rib)
+ return false;
+
+ return (definition_rib
+ && definition_rib.value ().kind == Rib::Kind::ForwardTypeParamBan);
+ }
};
} // namespace Resolver2_0
diff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx
index a7d46ce..069111e 100644
--- a/gcc/rust/resolve/rust-forever-stack.hxx
+++ b/gcc/rust/resolve/rust-forever-stack.hxx
@@ -20,7 +20,9 @@
#include "rust-ast.h"
#include "rust-diagnostics.h"
#include "rust-forever-stack.h"
+#include "rust-edition.h"
#include "rust-rib.h"
+#include "rust-unwrap-segment.h"
#include "optional.h"
namespace Rust {
@@ -35,6 +37,13 @@ ForeverStack<N>::Node::is_root () const
template <Namespace N>
bool
+ForeverStack<N>::Node::is_prelude () const
+{
+ return rib.kind == Rib::Kind::Prelude;
+}
+
+template <Namespace N>
+bool
ForeverStack<N>::Node::is_leaf () const
{
return children.empty ();
@@ -52,15 +61,26 @@ ForeverStack<N>::Node::insert_child (Link link, Node child)
template <Namespace N>
void
-ForeverStack<N>::push (Rib rib, NodeId id, tl::optional<Identifier> path)
+ForeverStack<N>::push (Rib::Kind rib_kind, NodeId id,
+ tl::optional<Identifier> path)
{
- push_inner (rib, Link (id, path));
+ push_inner (rib_kind, Link (id, path));
}
template <Namespace N>
void
ForeverStack<N>::push_inner (Rib rib, Link link)
{
+ if (rib.kind == Rib::Kind::Prelude)
+ {
+ // If you push_inner into the prelude from outside the root, you will pop
+ // back into the root, which could screw up a traversal.
+ rust_assert (&cursor_reference.get () == &root);
+ // Prelude doesn't have an access path
+ rust_assert (!link.path);
+ update_cursor (this->lang_prelude);
+ return;
+ }
// If the link does not exist, we create it and emplace a new `Node` with the
// current node as its parent. `unordered_map::emplace` returns a pair with
// the iterator and a boolean. If the value already exists, the iterator
@@ -133,6 +153,16 @@ ForeverStack<N>::insert_shadowable (Identifier name, NodeId node)
template <Namespace N>
tl::expected<NodeId, DuplicateNameError>
+ForeverStack<N>::insert_globbed (Identifier name, NodeId node)
+{
+ auto &innermost_rib = peek ();
+
+ return insert_inner (innermost_rib, name.as_string (),
+ Rib::Definition::Globbed (node));
+}
+
+template <Namespace N>
+tl::expected<NodeId, DuplicateNameError>
ForeverStack<N>::insert_at_root (Identifier name, NodeId node)
{
auto &root_rib = root.rib;
@@ -161,6 +191,14 @@ ForeverStack<Namespace::Labels>::insert (Identifier name, NodeId node)
Rib::Definition::Shadowable (node));
}
+template <>
+inline tl::expected<NodeId, DuplicateNameError>
+ForeverStack<Namespace::Types>::insert_variant (Identifier name, NodeId node)
+{
+ return insert_inner (peek (), name.as_string (),
+ Rib::Definition::NonShadowable (node, true));
+}
+
template <Namespace N>
Rib &
ForeverStack<N>::peek ()
@@ -184,6 +222,14 @@ ForeverStack<N>::reverse_iter (std::function<KeepGoing (Node &)> lambda)
template <Namespace N>
void
+ForeverStack<N>::reverse_iter (
+ std::function<KeepGoing (const Node &)> lambda) const
+{
+ return reverse_iter (cursor (), lambda);
+}
+
+template <Namespace N>
+void
ForeverStack<N>::reverse_iter (Node &start,
std::function<KeepGoing (Node &)> lambda)
{
@@ -203,6 +249,26 @@ ForeverStack<N>::reverse_iter (Node &start,
}
template <Namespace N>
+void
+ForeverStack<N>::reverse_iter (
+ const Node &start, std::function<KeepGoing (const Node &)> lambda) const
+{
+ auto *tmp = &start;
+
+ while (true)
+ {
+ auto keep_going = lambda (*tmp);
+ if (keep_going == KeepGoing::No)
+ return;
+
+ if (tmp->is_root ())
+ return;
+
+ tmp = &tmp->parent.value ();
+ }
+}
+
+template <Namespace N>
typename ForeverStack<N>::Node &
ForeverStack<N>::cursor ()
{
@@ -235,10 +301,12 @@ ForeverStack<N>::get (const Identifier &name)
return candidate.map_or (
[&resolved_definition] (Rib::Definition found) {
- // for most namespaces, we do not need to care about various ribs - they
- // are available from all contexts if defined in the current scope, or
- // an outermore one. so if we do have a candidate, we can return it
- // directly and stop iterating
+ if (found.is_variant ())
+ return KeepGoing::Yes;
+ // for most namespaces, we do not need to care about various ribs -
+ // they are available from all contexts if defined in the current
+ // scope, or an outermore one. so if we do have a candidate, we can
+ // return it directly and stop iterating
resolved_definition = found;
return KeepGoing::No;
@@ -250,6 +318,20 @@ ForeverStack<N>::get (const Identifier &name)
return resolved_definition;
}
+template <Namespace N>
+tl::optional<Rib::Definition>
+ForeverStack<N>::get_lang_prelude (const Identifier &name)
+{
+ return lang_prelude.rib.get (name.as_string ());
+}
+
+template <Namespace N>
+tl::optional<Rib::Definition>
+ForeverStack<N>::get_lang_prelude (const std::string &name)
+{
+ return lang_prelude.rib.get (name);
+}
+
template <>
tl::optional<Rib::Definition> inline ForeverStack<Namespace::Labels>::get (
const Identifier &name)
@@ -316,12 +398,13 @@ ForeverStack<N>::find_closest_module (Node &starting_point)
* segments */
template <typename S>
static inline bool
-check_leading_kw_at_start (const S &segment, bool condition)
+check_leading_kw_at_start (std::vector<Error> &collect_errors, const S &segment,
+ bool condition)
{
if (condition)
- rust_error_at (
+ collect_errors.emplace_back (
segment.get_locus (), ErrorCode::E0433,
- "leading path segment %qs can only be used at the beginning of a path",
+ "%qs in paths can only be used in start position",
segment.as_string ().c_str ());
return condition;
@@ -335,52 +418,61 @@ check_leading_kw_at_start (const S &segment, bool condition)
template <Namespace N>
template <typename S>
tl::optional<typename std::vector<S>::const_iterator>
-ForeverStack<N>::find_starting_point (const std::vector<S> &segments,
- Node &starting_point)
+ForeverStack<N>::find_starting_point (
+ const std::vector<S> &segments, std::reference_wrapper<Node> &starting_point,
+ std::function<void (const S &, NodeId)> insert_segment_resolution,
+ std::vector<Error> &collect_errors)
{
auto iterator = segments.begin ();
- // If we need to do path segment resolution, then we start
- // at the closest module. In order to resolve something like `foo::bar!()`, we
- // need to get back to the surrounding module, and look for a child module
- // named `foo`.
- if (segments.size () > 1)
- starting_point = find_closest_module (starting_point);
-
for (; !is_last (iterator, segments); iterator++)
{
- auto &seg = *iterator;
- auto is_self_or_crate
+ auto &outer_seg = *iterator;
+
+ if (unwrap_segment_get_lang_item (outer_seg).has_value ())
+ break;
+
+ auto &seg = unwrap_type_segment (outer_seg);
+ bool is_self_or_crate
= seg.is_crate_path_seg () || seg.is_lower_self_seg ();
// if we're after the first path segment and meet `self` or `crate`, it's
// an error - we should only be seeing `super` keywords at this point
- if (check_leading_kw_at_start (seg, !is_start (iterator, segments)
- && is_self_or_crate))
+ if (check_leading_kw_at_start (collect_errors, seg,
+ !is_start (iterator, segments)
+ && is_self_or_crate))
return tl::nullopt;
if (seg.is_crate_path_seg ())
{
starting_point = root;
+ insert_segment_resolution (outer_seg, starting_point.get ().id);
iterator++;
break;
}
if (seg.is_lower_self_seg ())
{
- // do nothing and exit
+ // insert segment resolution and exit
+ starting_point = find_closest_module (starting_point);
+ insert_segment_resolution (outer_seg, starting_point.get ().id);
iterator++;
break;
}
if (seg.is_super_path_seg ())
{
- if (starting_point.is_root ())
+ starting_point = find_closest_module (starting_point);
+ if (starting_point.get ().is_root ())
{
- rust_error_at (seg.get_locus (), ErrorCode::E0433,
- "too many leading %<super%> keywords");
+ collect_errors.emplace_back (
+ seg.get_locus (), ErrorCode::E0433,
+ "too many leading %<super%> keywords");
return tl::nullopt;
}
- starting_point = find_closest_module (starting_point.parent.value ());
+ starting_point
+ = find_closest_module (starting_point.get ().parent.value ());
+
+ insert_segment_resolution (outer_seg, starting_point.get ().id);
continue;
}
@@ -398,73 +490,223 @@ template <typename S>
tl::optional<typename ForeverStack<N>::Node &>
ForeverStack<N>::resolve_segments (
Node &starting_point, const std::vector<S> &segments,
- typename std::vector<S>::const_iterator iterator)
+ typename std::vector<S>::const_iterator iterator,
+ std::function<void (const S &, NodeId)> insert_segment_resolution,
+ std::vector<Error> &collect_errors)
{
- auto *current_node = &starting_point;
+ Node *current_node = &starting_point;
for (; !is_last (iterator, segments); iterator++)
{
- auto &seg = *iterator;
- auto str = seg.as_string ();
+ auto &outer_seg = *iterator;
+
+ if (auto lang_item = unwrap_segment_get_lang_item (outer_seg))
+ {
+ NodeId seg_id = Analysis::Mappings::get ().get_lang_item_node (
+ lang_item.value ());
+ current_node = &dfs_node (root, seg_id).value ();
+
+ insert_segment_resolution (outer_seg, seg_id);
+ continue;
+ }
+
+ auto &seg = unwrap_type_segment (outer_seg);
+ std::string str = seg.as_string ();
rust_debug ("[ARTHUR]: resolving segment part: %s", str.c_str ());
// check that we don't encounter *any* leading keywords afterwards
- if (check_leading_kw_at_start (seg, seg.is_crate_path_seg ()
- || seg.is_super_path_seg ()
- || seg.is_lower_self_seg ()))
+ if (check_leading_kw_at_start (collect_errors, seg,
+ seg.is_crate_path_seg ()
+ || seg.is_super_path_seg ()
+ || seg.is_lower_self_seg ()))
return tl::nullopt;
tl::optional<typename ForeverStack<N>::Node &> child = tl::nullopt;
- for (auto &kv : current_node->children)
+ /*
+ * On every iteration this loop either
+ *
+ * 1. terminates
+ *
+ * 2. decreases the depth of the node pointed to by current_node until
+ * current_node reaches the root
+ *
+ * 3. If the root node is reached, and we were not able to resolve the
+ * segment, we search the prelude rib for the segment, by setting
+ * current_node to point to the prelude, and toggling the
+ * searched_prelude boolean to true. If current_node is the prelude
+ * rib, and searched_prelude is true, we will exit.
+ *
+ * This ensures termination.
+ *
+ */
+ bool searched_prelude = false;
+ while (true)
{
- auto &link = kv.first;
+ // may set the value of child
+ for (auto &kv : current_node->children)
+ {
+ auto &link = kv.first;
+
+ if (link.path.map_or (
+ [&str] (Identifier path) {
+ auto &path_str = path.as_string ();
+ return str == path_str;
+ },
+ false))
+ {
+ child = kv.second;
+ break;
+ }
+ }
- if (link.path.map_or (
- [&str] (Identifier path) {
- auto &path_str = path.as_string ();
- return str == path_str;
- },
- false))
+ if (child.has_value ())
{
- child = kv.second;
break;
}
- }
- if (!child.has_value ())
- {
- rust_error_at (seg.get_locus (), ErrorCode::E0433,
- "failed to resolve path segment %qs", str.c_str ());
- return tl::nullopt;
+ if (N == Namespace::Types)
+ {
+ auto rib_lookup = current_node->rib.get (seg.as_string ());
+ if (rib_lookup && !rib_lookup->is_ambiguous ())
+ {
+ insert_segment_resolution (outer_seg,
+ rib_lookup->get_node_id ());
+ return tl::nullopt;
+ }
+ }
+
+ if (current_node->is_root () && !searched_prelude)
+ {
+ searched_prelude = true;
+ current_node = &lang_prelude;
+ continue;
+ }
+
+ if (!is_start (iterator, segments)
+ || current_node->rib.kind == Rib::Kind::Module
+ || current_node->is_prelude ())
+ {
+ return tl::nullopt;
+ }
+
+ current_node = &current_node->parent.value ();
}
+ // if child didn't contain a value
+ // the while loop above should have return'd or kept looping
current_node = &child.value ();
+ insert_segment_resolution (outer_seg, current_node->id);
}
return *current_node;
}
+template <>
+inline tl::optional<Rib::Definition>
+ForeverStack<Namespace::Types>::resolve_final_segment (Node &final_node,
+ std::string &seg_name,
+ bool is_lower_self)
+{
+ if (is_lower_self)
+ return Rib::Definition::NonShadowable (final_node.id);
+ else
+ return final_node.rib.get (seg_name);
+}
+
+template <Namespace N>
+tl::optional<Rib::Definition>
+ForeverStack<N>::resolve_final_segment (Node &final_node, std::string &seg_name,
+ bool is_lower_self)
+{
+ return final_node.rib.get (seg_name);
+}
+
template <Namespace N>
template <typename S>
tl::optional<Rib::Definition>
-ForeverStack<N>::resolve_path (const std::vector<S> &segments)
+ForeverStack<N>::resolve_path (
+ const std::vector<S> &segments, bool has_opening_scope_resolution,
+ std::function<void (const S &, NodeId)> insert_segment_resolution,
+ std::vector<Error> &collect_errors)
{
// TODO: What to do if segments.empty() ?
+ // handle paths with opening scopes
+ std::function<void (void)> cleanup_current = [] () {};
+ if (has_opening_scope_resolution)
+ {
+ Node *last_current = &cursor_reference.get ();
+ if (get_rust_edition () == Edition::E2015)
+ cursor_reference = root;
+ else
+ cursor_reference = extern_prelude;
+ cleanup_current
+ = [this, last_current] () { cursor_reference = *last_current; };
+ }
+
// if there's only one segment, we just use `get`
if (segments.size () == 1)
- return get (segments.back ().as_string ());
+ {
+ auto &seg = segments.front ();
+ if (auto lang_item = unwrap_segment_get_lang_item (seg))
+ {
+ NodeId seg_id = Analysis::Mappings::get ().get_lang_item_node (
+ lang_item.value ());
- auto starting_point = cursor ();
+ insert_segment_resolution (seg, seg_id);
+ cleanup_current ();
+ // TODO: does NonShadowable matter?
+ return Rib::Definition::NonShadowable (seg_id);
+ }
- return find_starting_point (segments, starting_point)
- .and_then ([this, &segments, &starting_point] (
- typename std::vector<S>::const_iterator iterator) {
- return resolve_segments (starting_point, segments, iterator);
- })
- .and_then ([&segments] (Node final_node) {
- return final_node.rib.get (segments.back ().as_string ());
- });
+ tl::optional<Rib::Definition> res
+ = get (unwrap_type_segment (segments.back ()).as_string ());
+
+ if (!res)
+ res = get_lang_prelude (
+ unwrap_type_segment (segments.back ()).as_string ());
+
+ if (res && !res->is_ambiguous ())
+ insert_segment_resolution (segments.back (), res->get_node_id ());
+ cleanup_current ();
+ return res;
+ }
+
+ std::reference_wrapper<Node> starting_point = cursor ();
+
+ auto res
+ = find_starting_point (segments, starting_point, insert_segment_resolution,
+ collect_errors)
+ .and_then (
+ [this, &segments, &starting_point, &insert_segment_resolution,
+ &collect_errors] (typename std::vector<S>::const_iterator iterator) {
+ return resolve_segments (starting_point.get (), segments, iterator,
+ insert_segment_resolution, collect_errors);
+ })
+ .and_then ([this, &segments, &insert_segment_resolution] (
+ Node &final_node) -> tl::optional<Rib::Definition> {
+ // leave resolution within impl blocks to type checker
+ if (final_node.rib.kind == Rib::Kind::TraitOrImpl)
+ return tl::nullopt;
+
+ auto &seg = unwrap_type_segment (segments.back ());
+ std::string seg_name = seg.as_string ();
+
+ // assuming this can't be a lang item segment
+ tl::optional<Rib::Definition> res
+ = resolve_final_segment (final_node, seg_name,
+ seg.is_lower_self_seg ());
+ // Ok we didn't find it in the rib, Lets try the prelude...
+ if (!res)
+ res = get_lang_prelude (seg_name);
+
+ if (res && !res->is_ambiguous ())
+ insert_segment_resolution (segments.back (), res->get_node_id ());
+
+ return res;
+ });
+ cleanup_current ();
+ return res;
}
template <Namespace N>
@@ -474,9 +716,48 @@ ForeverStack<N>::dfs (ForeverStack<N>::Node &starting_point, NodeId to_find)
auto values = starting_point.rib.get_values ();
for (auto &kv : values)
- for (auto id : kv.second.ids)
- if (id == to_find)
- return {{starting_point, kv.first}};
+ {
+ for (auto id : kv.second.ids_shadowable)
+ if (id == to_find)
+ return {{starting_point, kv.first}};
+ for (auto id : kv.second.ids_non_shadowable)
+ if (id == to_find)
+ return {{starting_point, kv.first}};
+ for (auto id : kv.second.ids_globbed)
+ if (id == to_find)
+ return {{starting_point, kv.first}};
+ }
+
+ for (auto &child : starting_point.children)
+ {
+ auto candidate = dfs (child.second, to_find);
+
+ if (candidate.has_value ())
+ return candidate;
+ }
+
+ return tl::nullopt;
+}
+
+template <Namespace N>
+tl::optional<typename ForeverStack<N>::ConstDfsResult>
+ForeverStack<N>::dfs (const ForeverStack<N>::Node &starting_point,
+ NodeId to_find) const
+{
+ auto values = starting_point.rib.get_values ();
+
+ for (auto &kv : values)
+ {
+ for (auto id : kv.second.ids_shadowable)
+ if (id == to_find)
+ return {{starting_point, kv.first}};
+ for (auto id : kv.second.ids_non_shadowable)
+ if (id == to_find)
+ return {{starting_point, kv.first}};
+ for (auto id : kv.second.ids_globbed)
+ if (id == to_find)
+ return {{starting_point, kv.first}};
+ }
for (auto &child : starting_point.children)
{
@@ -491,20 +772,20 @@ ForeverStack<N>::dfs (ForeverStack<N>::Node &starting_point, NodeId to_find)
template <Namespace N>
tl::optional<Resolver::CanonicalPath>
-ForeverStack<N>::to_canonical_path (NodeId id)
+ForeverStack<N>::to_canonical_path (NodeId id) const
{
// find the id in the current forever stack, starting from the root,
// performing either a BFS or DFS once the Node containing the ID is found, go
// back up to the root (parent().parent().parent()...) accumulate link
// segments reverse them that's your canonical path
- return dfs (root, id).map ([this, id] (DfsResult tuple) {
+ return dfs (root, id).map ([this, id] (ConstDfsResult tuple) {
auto containing_node = tuple.first;
auto name = tuple.second;
auto segments = std::vector<Resolver::CanonicalPath> ();
- reverse_iter (containing_node, [&segments] (Node &current) {
+ reverse_iter (containing_node, [&segments] (const Node &current) {
if (current.is_root ())
return KeepGoing::No;
@@ -516,7 +797,7 @@ ForeverStack<N>::to_canonical_path (NodeId id)
auto &link = kv.first;
auto &child = kv.second;
- if (link.id == child.id)
+ if (current.id == child.id)
{
outer_link = &link;
break;
@@ -534,7 +815,12 @@ ForeverStack<N>::to_canonical_path (NodeId id)
return KeepGoing::Yes;
});
- auto path = Resolver::CanonicalPath::create_empty ();
+ auto &mappings = Analysis::Mappings::get ();
+ CrateNum crate_num = mappings.lookup_crate_num (root.id).value ();
+ auto path = Resolver::CanonicalPath::new_seg (
+ root.id, mappings.get_crate_name (crate_num).value ());
+ path.set_crate_num (crate_num);
+
for (const auto &segment : segments)
path = path.append (segment);
@@ -549,12 +835,50 @@ template <Namespace N>
tl::optional<Rib &>
ForeverStack<N>::dfs_rib (ForeverStack<N>::Node &starting_point, NodeId to_find)
{
+ return dfs_node (starting_point, to_find).map ([] (Node &x) -> Rib & {
+ return x.rib;
+ });
+}
+
+template <Namespace N>
+tl::optional<const Rib &>
+ForeverStack<N>::dfs_rib (const ForeverStack<N>::Node &starting_point,
+ NodeId to_find) const
+{
+ return dfs_node (starting_point, to_find)
+ .map ([] (const Node &x) -> const Rib & { return x.rib; });
+}
+
+template <Namespace N>
+tl::optional<typename ForeverStack<N>::Node &>
+ForeverStack<N>::dfs_node (ForeverStack<N>::Node &starting_point,
+ NodeId to_find)
+{
+ if (starting_point.id == to_find)
+ return starting_point;
+
+ for (auto &child : starting_point.children)
+ {
+ auto candidate = dfs_node (child.second, to_find);
+
+ if (candidate.has_value ())
+ return candidate;
+ }
+
+ return tl::nullopt;
+}
+
+template <Namespace N>
+tl::optional<const typename ForeverStack<N>::Node &>
+ForeverStack<N>::dfs_node (const ForeverStack<N>::Node &starting_point,
+ NodeId to_find) const
+{
if (starting_point.id == to_find)
- return starting_point.rib;
+ return starting_point;
for (auto &child : starting_point.children)
{
- auto candidate = dfs_rib (child.second, to_find);
+ auto candidate = dfs_node (child.second, to_find);
if (candidate.has_value ())
return candidate;
@@ -571,18 +895,29 @@ ForeverStack<N>::to_rib (NodeId rib_id)
}
template <Namespace N>
+tl::optional<const Rib &>
+ForeverStack<N>::to_rib (NodeId rib_id) const
+{
+ return dfs_rib (root, rib_id);
+}
+
+template <Namespace N>
void
ForeverStack<N>::stream_rib (std::stringstream &stream, const Rib &rib,
const std::string &next,
- const std::string &next_next)
+ const std::string &next_next) const
{
+ std::string rib_kind = Rib::kind_to_string (rib.kind);
+ stream << next << "rib [" << rib_kind << "]: {";
if (rib.get_values ().empty ())
{
- stream << next << "rib: {},\n";
+ stream << "}\n";
return;
}
-
- stream << next << "rib: {\n";
+ else
+ {
+ stream << "\n";
+ }
for (const auto &kv : rib.get_values ())
stream << next_next << kv.first << ": " << kv.second.to_string () << "\n";
@@ -593,7 +928,7 @@ ForeverStack<N>::stream_rib (std::stringstream &stream, const Rib &rib,
template <Namespace N>
void
ForeverStack<N>::stream_node (std::stringstream &stream, unsigned indentation,
- const ForeverStack<N>::Node &node)
+ const ForeverStack<N>::Node &node) const
{
auto indent = std::string (indentation, ' ');
auto next = std::string (indentation + 4, ' ');
@@ -625,7 +960,7 @@ ForeverStack<N>::stream_node (std::stringstream &stream, unsigned indentation,
template <Namespace N>
std::string
-ForeverStack<N>::as_debug_string ()
+ForeverStack<N>::as_debug_string () const
{
std::stringstream stream;
@@ -634,6 +969,13 @@ ForeverStack<N>::as_debug_string ()
return stream.str ();
}
+template <Namespace N>
+bool
+ForeverStack<N>::is_module_descendant (NodeId parent, NodeId child) const
+{
+ return dfs_node (dfs_node (root, parent).value (), child).has_value ();
+}
+
// FIXME: Can we add selftests?
} // namespace Resolver2_0
diff --git a/gcc/rust/resolve/rust-ice-finalizer.cc b/gcc/rust/resolve/rust-ice-finalizer.cc
new file mode 100644
index 0000000..bd4763f
--- /dev/null
+++ b/gcc/rust/resolve/rust-ice-finalizer.cc
@@ -0,0 +1,36 @@
+// Copyright (C) 2020-2024 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ice-finalizer.h"
+
+namespace Rust {
+namespace Resolver {
+
+void ATTRIBUTE_NORETURN
+funny_ice_text_finalizer (diagnostic_text_output_format &text_output,
+ const diagnostic_info *diagnostic,
+ diagnostic_t diag_kind)
+{
+ gcc_assert (diag_kind == DK_ICE_NOBT);
+ default_diagnostic_text_finalizer (text_output, diagnostic, diag_kind);
+ fnotice (stderr, "You have broken GCC Rust. This is a feature.\n");
+ exit (ICE_EXIT_CODE);
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/resolve/rust-ice-finalizer.h b/gcc/rust/resolve/rust-ice-finalizer.h
new file mode 100644
index 0000000..85ab88f
--- /dev/null
+++ b/gcc/rust/resolve/rust-ice-finalizer.h
@@ -0,0 +1,65 @@
+// Copyright (C) 2020-2024 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_ICE_FINALIZER_H
+#define RUST_ICE_FINALIZER_H
+
+#include "rust-linemap.h"
+#include "diagnostic.h"
+
+namespace Rust {
+namespace Resolver {
+
+/* The "break rust" Easter egg.
+
+ Backstory: once upon a time, there used to be a bug in rustc: it would ICE
+ during typechecking on a 'break' with an expression outside of a loop. The
+ issue has been reported [0] and fixed [1], but in recognition of this, as a
+ special Easter egg, "break rust" was made to intentionally cause an ICE.
+
+ [0]: https://github.com/rust-lang/rust/issues/43162
+ [1]: https://github.com/rust-lang/rust/pull/43745
+
+ This was made in a way that does not break valid programs: namely, it only
+ happens when the 'break' is outside of a loop (so invalid anyway).
+
+ GCC Rust supports this essential feature as well, but in a slightly
+ different way. Instead of delaying the error until type checking, we emit
+ it here in the resolution phase. We, too, only do this to programs that
+ are already invalid: we only emit our funny ICE if the name "rust" (which
+ must be immediately inside a break-with-a-value expression) fails to
+ resolve. Note that "break (rust)" does not trigger our ICE, only using
+ "break rust" directly does, and only if there's no "rust" in scope. We do
+ this in the same way regardless of whether the "break" is outside of a loop
+ or inside one.
+
+ As a GNU extension, we also support "break gcc", much to the same effect,
+ subject to the same rules. */
+
+/* The finalizer for our funny ICE. This prints a custom message instead of
+ the default bug reporting instructions, as there is no bug to report. */
+
+void ATTRIBUTE_NORETURN
+funny_ice_text_finalizer (diagnostic_text_output_format &text_output,
+ const diagnostic_info *diagnostic,
+ diagnostic_t diag_kind);
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif /* ! RUST_ICE_FINALIZER_H */
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 9ac0945..6ec0422 100644
--- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
@@ -18,13 +18,17 @@
#include "optional.h"
#include "rust-ast-full.h"
+#include "rust-diagnostics.h"
#include "rust-hir-map.h"
#include "rust-late-name-resolver-2.0.h"
#include "rust-default-resolver.h"
#include "rust-name-resolution-context.h"
#include "rust-path.h"
+#include "rust-system.h"
#include "rust-tyty.h"
#include "rust-hir-type-check.h"
+#include "rust-ice-finalizer.h"
+#include "rust-ast.h"
namespace Rust {
namespace Resolver2_0 {
@@ -87,19 +91,21 @@ Late::setup_builtin_types ()
// insert it in the type context...
};
- for (const auto &builtin : builtins)
- {
- // we should be able to use `insert_at_root` or `insert` here, since we're
- // at the root :) hopefully!
- auto ok = ctx.types.insert (builtin.name, builtin.node_id);
- rust_assert (ok);
+ // There's a special Rib for putting prelude items, since prelude items need
+ // to satisfy certain special rules.
+ ctx.scoped (Rib::Kind::Prelude, 0, [this, &ty_ctx] (void) -> void {
+ for (const auto &builtin : builtins)
+ {
+ auto ok = ctx.types.insert (builtin.name, builtin.node_id);
+ rust_assert (ok);
- ctx.mappings.insert_node_to_hir (builtin.node_id, builtin.hir_id);
- ty_ctx.insert_builtin (builtin.hir_id, builtin.node_id, builtin.type);
- }
+ ctx.mappings.insert_node_to_hir (builtin.node_id, builtin.hir_id);
+ ty_ctx.insert_builtin (builtin.hir_id, builtin.node_id, builtin.type);
+ }
+ });
// ...here!
- auto *unit_type = TyTy::TupleType::get_unit_type (next_hir_id ());
+ auto *unit_type = TyTy::TupleType::get_unit_type ();
ty_ctx.insert_builtin (unit_type->get_ref (), next_node_id (), unit_type);
}
@@ -123,10 +129,72 @@ 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 ());
+ visit (expr.get_loop_label ());
+ visit (expr.get_loop_block ());
+}
+
+void
+Late::visit (AST::IfLetExpr &expr)
+{
+ visit_outer_attrs (expr);
+
+ ctx.bindings.enter (BindingSource::Let);
+
+ for (auto &pattern : expr.get_patterns ())
+ visit (pattern);
+
+ ctx.bindings.exit ();
+
+ visit (expr.get_value_expr ());
+ visit (expr.get_if_block ());
+}
+
+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)
{
- // so we don't need that method
- DefaultResolver::visit (let);
+ DefaultASTVisitor::visit_outer_attrs (let);
+ if (let.has_type ())
+ visit (let.get_type ());
+ // visit expression before pattern
+ // 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 ());
// how do we deal with the fact that `let a = blipbloup` should look for a
// label and cannot go through function ribs, but `let a = blipbloup()` can?
@@ -151,10 +219,144 @@ Late::visit (AST::IdentifierPattern &identifier)
// 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?
- auto ok
- = ctx.values.insert (identifier.get_ident (), identifier.get_node_id ());
- rust_assert (ok);
+ if (ctx.bindings.peek ().is_and_bound (identifier.get_ident ()))
+ {
+ if (ctx.bindings.peek ().get_source () == BindingSource::Param)
+ rust_error_at (
+ identifier.get_locus (), ErrorCode::E0415,
+ "identifier %qs is bound more than once in the same parameter list",
+ identifier.as_string ().c_str ());
+ else
+ rust_error_at (
+ identifier.get_locus (), ErrorCode::E0416,
+ "identifier %qs is bound more than once in the same pattern",
+ identifier.as_string ().c_str ());
+ return;
+ }
+
+ ctx.bindings.peek ().insert_ident (identifier.get_ident ());
+
+ if (ctx.bindings.peek ().is_or_bound (identifier.get_ident ()))
+ {
+ // FIXME: map usage instead
+ std::ignore = ctx.values.insert_shadowable (identifier.get_ident (),
+ identifier.get_node_id ());
+ }
+ else
+ {
+ // 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 ());
+ }
+}
+
+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)
+{
+ // We do want to ignore duplicated data because some situations rely on it.
+ std::ignore = ctx.values.insert_shadowable (field.get_identifier (),
+ field.get_node_id ());
+}
+
+void
+Late::visit (AST::SelfParam &param)
+{
+ // handle similar to AST::IdentifierPattern
+
+ DefaultResolver::visit (param);
+ // FIXME: this location should be a bit off
+ // ex: would point to the begining of "mut self" instead of the "self"
+ std::ignore = ctx.values.insert (Identifier ("self", param.get_locus ()),
+ param.get_node_id ());
+}
+
+void
+Late::visit (AST::BreakExpr &expr)
+{
+ if (expr.has_label ())
+ resolve_label (expr.get_label_unchecked ().get_lifetime ());
+
+ if (expr.has_break_expr ())
+ {
+ auto &break_expr = expr.get_break_expr ();
+ if (break_expr.get_expr_kind () == AST::Expr::Kind::Identifier)
+ {
+ /* This is a break with an expression, and the expression is
+ just a single identifier. See if the identifier is either
+ "rust" or "gcc", in which case we have "break rust" or "break
+ gcc", and so may need to emit our funny error. We cannot yet
+ emit the error here though, because the identifier may still
+ be in scope, and ICE'ing on valid programs would not be very
+ funny. */
+ std::string ident
+ = static_cast<AST::IdentifierExpr &> (expr.get_break_expr ())
+ .as_string ();
+ if (ident == "rust" || ident == "gcc")
+ funny_error = true;
+ }
+ }
+
+ DefaultResolver::visit (expr);
+
+ funny_error = false;
+}
+
+void
+Late::visit (AST::LoopLabel &label)
+{
+ auto &lifetime = label.get_lifetime ();
+ ctx.labels.insert (Identifier (lifetime.as_string (), lifetime.get_locus ()),
+ lifetime.get_node_id ());
+}
+
+void
+Late::resolve_label (AST::Lifetime &lifetime)
+{
+ if (auto resolved = ctx.labels.get (lifetime.as_string ()))
+ {
+ if (resolved->get_node_id () != lifetime.get_node_id ())
+ ctx.map_usage (Usage (lifetime.get_node_id ()),
+ Definition (resolved->get_node_id ()));
+ }
+ else
+ rust_error_at (lifetime.get_locus (), ErrorCode::E0426,
+ "use of undeclared label %qs",
+ lifetime.as_string ().c_str ());
+}
+
+void
+Late::visit (AST::ContinueExpr &expr)
+{
+ if (expr.has_label ())
+ resolve_label (expr.get_label_unchecked ());
+
+ DefaultResolver::visit (expr);
}
void
@@ -163,55 +365,115 @@ Late::visit (AST::IdentifierExpr &expr)
// TODO: same thing as visit(PathInExpression) here?
tl::optional<Rib::Definition> resolved = tl::nullopt;
- auto label = ctx.labels.get (expr.get_ident ());
- auto value = ctx.values.get (expr.get_ident ());
-
- if (label)
+ if (auto value = ctx.values.get (expr.get_ident ()))
+ {
+ resolved = value;
+ }
+ else if (auto type = ctx.types.get (expr.get_ident ()))
{
- resolved = label;
+ resolved = type;
}
- else if (value)
+ else if (funny_error)
{
- resolved = value;
+ diagnostic_text_finalizer (global_dc) = Resolver::funny_ice_text_finalizer;
+ emit_diagnostic (DK_ICE_NOBT, expr.get_locus (), -1,
+ "are you trying to break %s? how dare you?",
+ expr.as_string ().c_str ());
}
else
{
- rust_error_at (expr.get_locus (),
- "could not resolve identifier expression: %qs",
- expr.get_ident ().as_string ().c_str ());
+ if (auto type = ctx.types.get_lang_prelude (expr.get_ident ()))
+ {
+ resolved = type;
+ }
+ else
+ {
+ rust_error_at (expr.get_locus (), ErrorCode::E0425,
+ "cannot find value %qs in this scope",
+ expr.get_ident ().as_string ().c_str ());
+ return;
+ }
+ }
+
+ if (resolved->is_ambiguous ())
+ {
+ rust_error_at (expr.get_locus (), ErrorCode::E0659, "%qs is ambiguous",
+ expr.as_string ().c_str ());
return;
}
ctx.map_usage (Usage (expr.get_node_id ()),
Definition (resolved->get_node_id ()));
- // in the old resolver, resolutions are kept in the resolver, not the mappings
- // :/ how do we deal with that?
- // ctx.mappings.insert_resolved_name(expr, resolved);
-
// For empty types, do we perform a lookup in ctx.types or should the
// toplevel instead insert a name in ctx.values? (like it currently does)
}
void
+Late::visit (AST::StructExprFieldIdentifier &expr)
+{
+ tl::optional<Rib::Definition> resolved = tl::nullopt;
+
+ if (auto value = ctx.values.get (expr.get_field_name ()))
+ {
+ resolved = value;
+ }
+ // seems like we don't need a type namespace lookup
+ else
+ {
+ rust_error_at (expr.get_locus (), "could not resolve struct field: %qs",
+ expr.get_field_name ().as_string ().c_str ());
+ return;
+ }
+
+ if (resolved->is_ambiguous ())
+ {
+ rust_error_at (expr.get_locus (), ErrorCode::E0659, "%qs is ambiguous",
+ expr.as_string ().c_str ());
+ return;
+ }
+
+ ctx.map_usage (Usage (expr.get_node_id ()),
+ Definition (resolved->get_node_id ()));
+}
+
+void
Late::visit (AST::PathInExpression &expr)
{
// TODO: How do we have a nice error with `can't capture dynamic environment
// in a function item` error here?
// do we emit it in `get<Namespace::Labels>`?
- auto value = ctx.values.resolve_path (expr.get_segments ());
- if (!value.has_value ())
- rust_unreachable (); // Should have been resolved earlier
+ DefaultResolver::visit (expr);
- if (value->is_ambiguous ())
+ if (expr.is_lang_item ())
+ {
+ ctx.map_usage (Usage (expr.get_node_id ()),
+ Definition (Analysis::Mappings::get ().get_lang_item_node (
+ expr.get_lang_item ())));
+ return;
+ }
+
+ auto resolved = ctx.resolve_path (expr, Namespace::Values, Namespace::Types);
+
+ if (!resolved)
+ {
+ if (!ctx.lookup (expr.get_segments ().front ().get_node_id ()))
+ rust_error_at (expr.get_locus (), ErrorCode::E0433,
+ "Cannot find path %qs in this scope",
+ expr.as_simple_path ().as_string ().c_str ());
+ return;
+ }
+
+ if (resolved->is_ambiguous ())
{
rust_error_at (expr.get_locus (), ErrorCode::E0659, "%qs is ambiguous",
expr.as_string ().c_str ());
return;
}
+
ctx.map_usage (Usage (expr.get_node_id ()),
- Definition (value->get_node_id ()));
+ Definition (resolved->get_node_id ()));
}
void
@@ -222,31 +484,180 @@ Late::visit (AST::TypePath &type)
// maybe we can overload `resolve_path<Namespace::Types>` to only do
// typepath-like path resolution? that sounds good
- auto resolved = ctx.types.get (type.get_segments ().back ()->as_string ());
+ DefaultResolver::visit (type);
+
+ // this *should* mostly work
+ // TODO: make sure typepath-like path resolution (?) is working
+ auto resolved = ctx.resolve_path (type, Namespace::Types);
+
+ 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 ());
+ return;
+ }
+
+ if (resolved->is_ambiguous ())
+ {
+ rust_error_at (type.get_locus (), ErrorCode::E0659, "%qs is ambiguous",
+ type.as_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::Trait &trait)
+{
+ // kind of weird how this is done
+ // names are resolved to the node id of trait.get_implicit_self ()
+ // which is then resolved to the node id of trait
+ // we set up the latter mapping here
+ ctx.map_usage (Usage (trait.get_implicit_self ().get_node_id ()),
+ Definition (trait.get_node_id ()));
+
+ DefaultResolver::visit (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);
+ visit_inner_attrs (s);
+ DefaultResolver::visit (s.get_struct_name ());
+
+ auto resolved = ctx.resolve_path (s.get_struct_name (), Namespace::Types);
+
+ ctx.map_usage (Usage (s.get_struct_name ().get_node_id ()),
+ Definition (resolved->get_node_id ()));
+}
+
+void
Late::visit (AST::StructExprStructBase &s)
{
- auto resolved = ctx.types.get (s.get_struct_name ().as_string ());
+ visit_outer_attrs (s);
+ visit_inner_attrs (s);
+ DefaultResolver::visit (s.get_struct_name ());
+ visit (s.get_struct_base ());
+
+ auto resolved = ctx.resolve_path (s.get_struct_name (), Namespace::Types);
ctx.map_usage (Usage (s.get_struct_name ().get_node_id ()),
Definition (resolved->get_node_id ()));
- DefaultResolver::visit (s);
}
void
Late::visit (AST::StructExprStructFields &s)
{
- auto resolved = ctx.types.get (s.get_struct_name ().as_string ());
+ visit_outer_attrs (s);
+ visit_inner_attrs (s);
+ DefaultResolver::visit (s.get_struct_name ());
+ if (s.has_struct_base ())
+ visit (s.get_struct_base ());
+ for (auto &field : s.get_fields ())
+ visit (field);
+
+ auto resolved = ctx.resolve_path (s.get_struct_name (), Namespace::Types);
ctx.map_usage (Usage (s.get_struct_name ().get_node_id ()),
Definition (resolved->get_node_id ()));
+}
+
+// needed because Late::visit (AST::GenericArg &) is non-virtual
+void
+Late::visit (AST::GenericArgs &args)
+{
+ for (auto &lifetime : args.get_lifetime_args ())
+ visit (lifetime);
+
+ for (auto &generic : args.get_generic_args ())
+ visit (generic);
+
+ for (auto &binding : args.get_binding_args ())
+ visit (binding);
+}
+
+void
+Late::visit (AST::GenericArg &arg)
+{
+ if (arg.get_kind () == AST::GenericArg::Kind::Either)
+ {
+ // prefer type parameter to const parameter on ambiguity
+ auto type = ctx.types.get (arg.get_path ());
+ auto value = ctx.values.get (arg.get_path ());
+
+ if (!type.has_value () && value.has_value ())
+ arg = arg.disambiguate_to_const ();
+ else
+ arg = arg.disambiguate_to_type ();
+ }
+
+ 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)
+{
+ add_captures (closure, ctx);
+
+ visit_outer_attrs (closure);
+
+ ctx.bindings.enter (BindingSource::Param);
+
+ for (auto &param : closure.get_params ())
+ visit (param);
+
+ ctx.bindings.exit ();
+
+ visit (closure.get_definition_expr ());
+}
+
+void
+Late::visit (AST::ClosureExprInnerTyped &closure)
+{
+ add_captures (closure, ctx);
+
+ visit_outer_attrs (closure);
+
+ ctx.bindings.enter (BindingSource::Param);
+
+ for (auto &param : closure.get_params ())
+ visit (param);
+
+ ctx.bindings.exit ();
- DefaultResolver::visit (s);
+ visit (closure.get_return_type ());
+ visit (closure.get_definition_block ());
}
} // namespace Resolver2_0
diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.h b/gcc/rust/resolve/rust-late-name-resolver-2.0.h
index b44b2d9..171d9bf 100644
--- a/gcc/rust/resolve/rust-late-name-resolver-2.0.h
+++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.h
@@ -21,6 +21,7 @@
#include "rust-ast-full.h"
#include "rust-default-resolver.h"
+#include "rust-expr.h"
namespace Rust {
namespace Resolver2_0 {
@@ -36,22 +37,46 @@ public:
void new_label (Identifier name, NodeId id);
+ // Specialized visit bits
+ void visit_function_params (AST::Function &function) override;
+
// some more label declarations
void visit (AST::LetStmt &) override;
// TODO: Do we need this?
// void visit (AST::Method &) override;
void visit (AST::IdentifierPattern &) override;
+ void visit (AST::StructPatternFieldIdent &) override;
+ void visit (AST::AltPattern &) override;
+ void visit (AST::SelfParam &) override;
+ void visit (AST::MatchArm &) override;
+ void visit (AST::ForLoopExpr &) override;
+ void visit (AST::IfLetExpr &) override;
// resolutions
void visit (AST::IdentifierExpr &) override;
+ void visit (AST::StructExprFieldIdentifier &) override;
+ void visit (AST::BreakExpr &) override;
+ void visit (AST::ContinueExpr &) override;
+ void visit (AST::LoopLabel &) override;
void visit (AST::PathInExpression &) override;
void visit (AST::TypePath &) override;
+ void visit (AST::Trait &) override;
+ void visit (AST::StructExprStruct &) override;
void visit (AST::StructExprStructBase &) override;
void visit (AST::StructExprStructFields &) override;
+ void visit (AST::StructStruct &) override;
+ void visit (AST::GenericArgs &) override;
+ void visit (AST::GenericArg &);
+ void visit (AST::ClosureExprInner &) override;
+ void visit (AST::ClosureExprInnerTyped &) override;
private:
+ void resolve_label (AST::Lifetime &lifetime);
+
/* Setup Rust's builtin types (u8, i32, !...) in the resolver */
void setup_builtin_types ();
+
+ bool funny_error;
};
// TODO: Add missing mappings and data structures
diff --git a/gcc/rust/resolve/rust-name-resolution-context.cc b/gcc/rust/resolve/rust-name-resolution-context.cc
index d964684..f098e48 100644
--- a/gcc/rust/resolve/rust-name-resolution-context.cc
+++ b/gcc/rust/resolve/rust-name-resolution-context.cc
@@ -23,6 +23,65 @@
namespace Rust {
namespace Resolver2_0 {
+BindingLayer::BindingLayer (BindingSource source) : source (source)
+{
+ push (Binding::Kind::Product);
+}
+
+bool
+BindingLayer::bind_test (Identifier ident, Binding::Kind kind)
+{
+ for (auto &bind : bindings)
+ {
+ if (bind.set.find (ident) != bind.set.cend () && bind.kind == kind)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+BindingLayer::push (Binding::Kind kind)
+{
+ bindings.push_back (Binding (kind));
+}
+
+bool
+BindingLayer::is_and_bound (Identifier ident)
+{
+ return bind_test (ident, Binding::Kind::Product);
+}
+
+bool
+BindingLayer::is_or_bound (Identifier ident)
+{
+ return bind_test (ident, Binding::Kind::Or);
+}
+
+void
+BindingLayer::insert_ident (Identifier ident)
+{
+ bindings.back ().set.insert (ident);
+}
+
+void
+BindingLayer::merge ()
+{
+ auto last_binding = bindings.back ();
+ bindings.pop_back ();
+ for (auto &value : last_binding.set)
+ {
+ bindings.back ().set.insert (value);
+ }
+}
+
+BindingSource
+BindingLayer::get_source () const
+{
+ return source;
+}
+
NameResolutionContext::NameResolutionContext ()
: mappings (Analysis::Mappings::get ())
{}
@@ -46,6 +105,12 @@ NameResolutionContext::insert (Identifier name, NodeId id, Namespace ns)
}
tl::expected<NodeId, DuplicateNameError>
+NameResolutionContext::insert_variant (Identifier name, NodeId id)
+{
+ return types.insert_variant (name, id);
+}
+
+tl::expected<NodeId, DuplicateNameError>
NameResolutionContext::insert_shadowable (Identifier name, NodeId id,
Namespace ns)
{
@@ -64,6 +129,24 @@ NameResolutionContext::insert_shadowable (Identifier name, NodeId id,
}
}
+tl::expected<NodeId, DuplicateNameError>
+NameResolutionContext::insert_globbed (Identifier name, NodeId id, Namespace ns)
+{
+ switch (ns)
+ {
+ case Namespace::Values:
+ return values.insert_globbed (name, id);
+ case Namespace::Types:
+ return types.insert_globbed (name, id);
+ case Namespace::Macros:
+ return macros.insert_globbed (name, id);
+ case Namespace::Labels:
+ default:
+ // return labels.insert (name, id);
+ rust_unreachable ();
+ }
+}
+
void
NameResolutionContext::map_usage (Usage usage, Definition definition)
{
@@ -74,7 +157,7 @@ NameResolutionContext::map_usage (Usage usage, Definition definition)
}
tl::optional<NodeId>
-NameResolutionContext::lookup (NodeId usage)
+NameResolutionContext::lookup (NodeId usage) const
{
auto it = resolved_nodes.find (Usage (usage));
@@ -85,13 +168,14 @@ NameResolutionContext::lookup (NodeId usage)
}
void
-NameResolutionContext::scoped (Rib rib, NodeId id,
+NameResolutionContext::scoped (Rib::Kind rib_kind, NodeId id,
std::function<void (void)> lambda,
tl::optional<Identifier> path)
{
- values.push (rib, id, path);
- types.push (rib, id, path);
- macros.push (rib, id, path);
+ // NOTE: You must be at the root node when pushing the prelude rib.
+ values.push (rib_kind, id, path);
+ types.push (rib_kind, id, path);
+ macros.push (rib_kind, id, path);
// labels.push (rib, id);
lambda ();
@@ -103,17 +187,21 @@ NameResolutionContext::scoped (Rib rib, NodeId id,
}
void
-NameResolutionContext::scoped (Rib rib, Namespace ns, NodeId scope_id,
+NameResolutionContext::scoped (Rib::Kind rib_kind, Namespace ns,
+ NodeId scope_id,
std::function<void (void)> lambda,
tl::optional<Identifier> path)
{
+ // This could work... I'm not sure why you would want to do this though.
+ rust_assert (rib_kind != Rib::Kind::Prelude);
+
switch (ns)
{
case Namespace::Values:
- values.push (rib, scope_id, path);
+ values.push (rib_kind, scope_id, path);
break;
case Namespace::Types:
- types.push (rib, scope_id, path);
+ types.push (rib_kind, scope_id, path);
break;
case Namespace::Labels:
case Namespace::Macros:
diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h
index 3605392..19ba750 100644
--- a/gcc/rust/resolve/rust-name-resolution-context.h
+++ b/gcc/rust/resolve/rust-name-resolution-context.h
@@ -22,6 +22,8 @@
#include "optional.h"
#include "rust-forever-stack.h"
#include "rust-hir-map.h"
+#include "rust-rib.h"
+#include "rust-stacked-contexts.h"
namespace Rust {
namespace Resolver2_0 {
@@ -155,6 +157,62 @@ public:
NodeId id;
};
+struct Binding
+{
+ enum class Kind
+ {
+ Product,
+ Or,
+ } kind;
+
+ std::unordered_set<Identifier> set;
+
+ Binding (Binding::Kind kind) : kind (kind) {}
+};
+
+/**
+ * Used to identify the source of a binding, and emit the correct error message.
+ */
+enum class BindingSource
+{
+ Match,
+ Let,
+ For,
+ /* Closure param or function param */
+ Param
+};
+
+class BindingLayer
+{
+ BindingSource source;
+ std::vector<Binding> bindings;
+
+ bool bind_test (Identifier ident, Binding::Kind kind);
+
+public:
+ void push (Binding::Kind kind);
+
+ BindingLayer (BindingSource source);
+
+ /**
+ * Identifies if the identifier has been used in a product binding context.
+ * eg. `let (a, a) = test();`
+ */
+ bool is_and_bound (Identifier ident);
+
+ /**
+ * Identifies if the identifier has been used in a or context.
+ * eg. `let (a, 1) | (a, 2) = test()`
+ */
+ bool is_or_bound (Identifier ident);
+
+ void insert_ident (Identifier ident);
+
+ void merge ();
+
+ BindingSource get_source () const;
+};
+
// Now our resolver, which keeps track of all the `ForeverStack`s we could want
class NameResolutionContext
{
@@ -171,9 +229,15 @@ public:
tl::expected<NodeId, DuplicateNameError> insert (Identifier name, NodeId id,
Namespace ns);
+ tl::expected<NodeId, DuplicateNameError> insert_variant (Identifier name,
+ NodeId id);
+
tl::expected<NodeId, DuplicateNameError>
insert_shadowable (Identifier name, NodeId id, Namespace ns);
+ tl::expected<NodeId, DuplicateNameError>
+ insert_globbed (Identifier name, NodeId id, Namespace ns);
+
/**
* Run a lambda in a "scoped" context, meaning that a new `Rib` will be pushed
* before executing the lambda and then popped. This is useful for all kinds
@@ -181,8 +245,8 @@ public:
* function. This variant of the function enters a new scope in *all*
* namespaces, while the second variant enters a scope in *one* namespace.
*
- * @param rib New `Rib` to create when entering this scope. A function `Rib`,
- * or an item `Rib`... etc
+ * @param rib_kind New `Rib` to create when entering this scope. A function
+ * `Rib`, or an item `Rib`... etc
* @param scope_id node ID of the scope we are entering, e.g the block's
* `NodeId`.
* @param lambda Function to run within that scope
@@ -192,9 +256,10 @@ public:
*/
// FIXME: Do we want to handle something in particular for expected within the
// scoped lambda?
- void scoped (Rib rib, NodeId scope_id, std::function<void (void)> lambda,
+ void scoped (Rib::Kind rib_kind, NodeId scope_id,
+ std::function<void (void)> lambda,
tl::optional<Identifier> path = {});
- void scoped (Rib rib, Namespace ns, NodeId scope_id,
+ void scoped (Rib::Kind rib_kind, Namespace ns, NodeId scope_id,
std::function<void (void)> lambda,
tl::optional<Identifier> path = {});
@@ -204,12 +269,127 @@ public:
ForeverStack<Namespace::Labels> labels;
Analysis::Mappings &mappings;
+ StackedContexts<BindingLayer> bindings;
// TODO: Rename
// TODO: Use newtype pattern for Usage and Definition
void map_usage (Usage usage, Definition definition);
- tl::optional<NodeId> lookup (NodeId usage);
+ tl::optional<NodeId> lookup (NodeId usage) const;
+
+ template <typename S>
+ tl::optional<Rib::Definition>
+ resolve_path (const std::vector<S> &segments,
+ bool has_opening_scope_resolution,
+ std::vector<Error> &collect_errors, Namespace ns)
+ {
+ std::function<void (const S &, NodeId)> insert_segment_resolution
+ = [this] (const S &seg, NodeId id) {
+ auto seg_id = unwrap_segment_node_id (seg);
+ if (resolved_nodes.find (Usage (seg_id)) == resolved_nodes.end ())
+ map_usage (Usage (seg_id), Definition (id));
+ };
+ switch (ns)
+ {
+ case Namespace::Values:
+ return values.resolve_path (segments, has_opening_scope_resolution,
+ insert_segment_resolution, collect_errors);
+ case Namespace::Types:
+ return types.resolve_path (segments, has_opening_scope_resolution,
+ insert_segment_resolution, collect_errors);
+ case Namespace::Macros:
+ return macros.resolve_path (segments, has_opening_scope_resolution,
+ insert_segment_resolution, collect_errors);
+ case Namespace::Labels:
+ return labels.resolve_path (segments, has_opening_scope_resolution,
+ insert_segment_resolution, collect_errors);
+ default:
+ rust_unreachable ();
+ }
+ }
+
+ template <typename S, typename... Args>
+ tl::optional<Rib::Definition>
+ resolve_path (const std::vector<S> &segments,
+ bool has_opening_scope_resolution,
+ tl::optional<std::vector<Error> &> collect_errors,
+ Namespace ns_first, Args... ns_args)
+ {
+ std::initializer_list<Namespace> namespaces = {ns_first, ns_args...};
+
+ for (auto ns : namespaces)
+ {
+ std::vector<Error> collect_errors_inner;
+ if (auto ret = resolve_path (segments, has_opening_scope_resolution,
+ collect_errors_inner, ns))
+ return ret;
+ if (!collect_errors_inner.empty ())
+ {
+ if (collect_errors.has_value ())
+ {
+ std::move (collect_errors_inner.begin (),
+ collect_errors_inner.end (),
+ std::back_inserter (collect_errors.value ()));
+ }
+ else
+ {
+ for (auto &e : collect_errors_inner)
+ e.emit ();
+ }
+ return tl::nullopt;
+ }
+ }
+
+ return tl::nullopt;
+ }
+
+ template <typename... Args>
+ tl::optional<Rib::Definition>
+ resolve_path (const AST::SimplePath &path,
+ tl::optional<std::vector<Error> &> collect_errors,
+ Namespace ns_first, Args... ns_args)
+ {
+ return resolve_path (path.get_segments (),
+ path.has_opening_scope_resolution (), collect_errors,
+ ns_first, ns_args...);
+ }
+
+ template <typename... Args>
+ tl::optional<Rib::Definition>
+ resolve_path (const AST::PathInExpression &path,
+ tl::optional<std::vector<Error> &> collect_errors,
+ Namespace ns_first, Args... ns_args)
+ {
+ return resolve_path (path.get_segments (), path.opening_scope_resolution (),
+ collect_errors, ns_first, ns_args...);
+ }
+
+ template <typename... Args>
+ tl::optional<Rib::Definition>
+ resolve_path (const AST::TypePath &path,
+ tl::optional<std::vector<Error> &> collect_errors,
+ Namespace ns_first, Args... ns_args)
+ {
+ return resolve_path (path.get_segments (),
+ path.has_opening_scope_resolution_op (),
+ collect_errors, ns_first, ns_args...);
+ }
+
+ template <typename P, typename... Args>
+ tl::optional<Rib::Definition> resolve_path (const P &path, Namespace ns_first,
+ Args... ns_args)
+ {
+ return resolve_path (path, tl::nullopt, ns_first, ns_args...);
+ }
+
+ template <typename P, typename... Args>
+ tl::optional<Rib::Definition>
+ resolve_path (const P &path_segments, bool has_opening_scope_resolution,
+ Namespace ns_first, Args... ns_args)
+ {
+ return resolve_path (path_segments, has_opening_scope_resolution,
+ tl::nullopt, ns_first, ns_args...);
+ }
private:
/* Map of "usage" nodes which have been resolved to a "definition" node */
diff --git a/gcc/rust/resolve/rust-name-resolver.cc b/gcc/rust/resolve/rust-name-resolver.cc
index ee52e5c..dddaa07 100644
--- a/gcc/rust/resolve/rust-name-resolver.cc
+++ b/gcc/rust/resolve/rust-name-resolver.cc
@@ -19,6 +19,9 @@
#include "rust-name-resolver.h"
#include "rust-ast-full.h"
+// for flag_name_resolution_2_0
+#include "options.h"
+
namespace Rust {
namespace Resolver {
@@ -429,11 +432,13 @@ Resolver::generate_builtins ()
setup_builtin ("isize", isize);
setup_builtin ("char", char_tyty);
setup_builtin ("str", str);
- setup_builtin ("!", never);
+
+ // never type
+ NodeId never_node_id = setup_builtin ("!", never);
+ set_never_type_node_id (never_node_id);
// unit type ()
- TyTy::TupleType *unit_tyty
- = TyTy::TupleType::get_unit_type (mappings.get_next_hir_id ());
+ TyTy::TupleType *unit_tyty = TyTy::TupleType::get_unit_type ();
std::vector<std::unique_ptr<AST::Type> > elems;
AST::TupleType *unit_type
= new AST::TupleType (std::move (elems), BUILTINS_LOCATION);
@@ -443,7 +448,7 @@ Resolver::generate_builtins ()
set_unit_type_node_id (unit_type->get_node_id ());
}
-void
+NodeId
Resolver::setup_builtin (const std::string &name, TyTy::BaseType *tyty)
{
AST::PathIdentSegment seg (name, BUILTINS_LOCATION);
@@ -459,11 +464,16 @@ Resolver::setup_builtin (const std::string &name, TyTy::BaseType *tyty)
mappings.insert_canonical_path (
builtin_type->get_node_id (),
CanonicalPath::new_seg (builtin_type->get_node_id (), name));
+
+ return builtin_type->get_node_id ();
}
void
Resolver::insert_resolved_name (NodeId refId, NodeId defId)
{
+ rust_assert (!flag_name_resolution_2_0);
+ rust_assert (resolved_names.find (refId) == resolved_names.end ());
+
resolved_names[refId] = defId;
get_name_scope ().append_reference_for_def (refId, defId);
insert_captured_item (defId);
@@ -472,6 +482,7 @@ Resolver::insert_resolved_name (NodeId refId, NodeId defId)
bool
Resolver::lookup_resolved_name (NodeId refId, NodeId *defId)
{
+ rust_assert (!flag_name_resolution_2_0);
auto it = resolved_names.find (refId);
if (it == resolved_names.end ())
return false;
@@ -483,8 +494,8 @@ Resolver::lookup_resolved_name (NodeId refId, NodeId *defId)
void
Resolver::insert_resolved_type (NodeId refId, NodeId defId)
{
- // auto it = resolved_types.find (refId);
- // rust_assert (it == resolved_types.end ());
+ rust_assert (!flag_name_resolution_2_0);
+ rust_assert (resolved_types.find (refId) == resolved_types.end ());
resolved_types[refId] = defId;
get_type_scope ().append_reference_for_def (refId, defId);
@@ -493,6 +504,7 @@ Resolver::insert_resolved_type (NodeId refId, NodeId defId)
bool
Resolver::lookup_resolved_type (NodeId refId, NodeId *defId)
{
+ rust_assert (!flag_name_resolution_2_0);
auto it = resolved_types.find (refId);
if (it == resolved_types.end ())
return false;
@@ -504,6 +516,7 @@ Resolver::lookup_resolved_type (NodeId refId, NodeId *defId)
void
Resolver::insert_resolved_label (NodeId refId, NodeId defId)
{
+ rust_assert (!flag_name_resolution_2_0);
auto it = resolved_labels.find (refId);
rust_assert (it == resolved_labels.end ());
@@ -514,6 +527,7 @@ Resolver::insert_resolved_label (NodeId refId, NodeId defId)
bool
Resolver::lookup_resolved_label (NodeId refId, NodeId *defId)
{
+ rust_assert (!flag_name_resolution_2_0);
auto it = resolved_labels.find (refId);
if (it == resolved_labels.end ())
return false;
@@ -525,6 +539,7 @@ Resolver::lookup_resolved_label (NodeId refId, NodeId *defId)
void
Resolver::insert_resolved_macro (NodeId refId, NodeId defId)
{
+ rust_assert (!flag_name_resolution_2_0);
auto it = resolved_macros.find (refId);
rust_assert (it == resolved_macros.end ());
@@ -535,6 +550,7 @@ Resolver::insert_resolved_macro (NodeId refId, NodeId defId)
bool
Resolver::lookup_resolved_macro (NodeId refId, NodeId *defId)
{
+ rust_assert (!flag_name_resolution_2_0);
auto it = resolved_macros.find (refId);
if (it == resolved_macros.end ())
return false;
@@ -546,6 +562,7 @@ Resolver::lookup_resolved_macro (NodeId refId, NodeId *defId)
void
Resolver::insert_resolved_misc (NodeId refId, NodeId defId)
{
+ rust_assert (!flag_name_resolution_2_0);
auto it = misc_resolved_items.find (refId);
rust_assert (it == misc_resolved_items.end ());
@@ -555,6 +572,7 @@ Resolver::insert_resolved_misc (NodeId refId, NodeId defId)
bool
Resolver::lookup_resolved_misc (NodeId refId, NodeId *defId)
{
+ rust_assert (!flag_name_resolution_2_0);
auto it = misc_resolved_items.find (refId);
if (it == misc_resolved_items.end ())
return false;
@@ -657,6 +675,8 @@ Resolver::decl_needs_capture (NodeId decl_rib_node_id,
const std::set<NodeId> &
Resolver::get_captures (NodeId id) const
{
+ rust_assert (!flag_name_resolution_2_0);
+
auto it = closures_capture_mappings.find (id);
rust_assert (it != closures_capture_mappings.end ());
return it->second;
diff --git a/gcc/rust/resolve/rust-name-resolver.h b/gcc/rust/resolve/rust-name-resolver.h
index c34002e..a3b34a9 100644
--- a/gcc/rust/resolve/rust-name-resolver.h
+++ b/gcc/rust/resolve/rust-name-resolver.h
@@ -163,9 +163,13 @@ public:
Scope &get_macro_scope () { return macro_scope; }
NodeId get_global_type_node_id () { return global_type_node_id; }
+
void set_unit_type_node_id (NodeId id) { unit_ty_node_id = id; }
NodeId get_unit_type_node_id () { return unit_ty_node_id; }
+ void set_never_type_node_id (NodeId id) { never_ty_node_id = id; }
+ NodeId get_never_type_node_id () { return never_ty_node_id; }
+
void push_new_module_scope (NodeId module_id)
{
current_module_stack.push_back (module_id);
@@ -200,6 +204,41 @@ public:
void insert_captured_item (NodeId id);
const std::set<NodeId> &get_captures (NodeId id) const;
+ std::string as_debug_string () const
+ {
+ std::stringstream ss;
+
+ ss << "Names:\n";
+ for (auto &n : name_ribs)
+ {
+ ss << "\tNodeID: " << n.first << " Rib: " << n.second->debug_str ()
+ << "\n";
+ }
+ ss << "Types:\n";
+ for (auto &n : type_ribs)
+ {
+ ss << "\tNodeID: " << n.first << " Rib: " << n.second->debug_str ()
+ << "\n";
+ }
+ ss << "Macros:\n";
+
+ for (auto &n : macro_ribs)
+ {
+ ss << "\tNodeID: " << n.first << " Rib: " << n.second->debug_str ()
+ << "\n";
+ }
+
+ ss << "Labels:\n";
+
+ for (auto &n : label_ribs)
+ {
+ ss << "\tNodeID: " << n.first << " Rib: " << n.second->debug_str ()
+ << "\n";
+ }
+
+ return ss.str ();
+ }
+
protected:
bool decl_needs_capture (NodeId decl_rib_node_id, NodeId closure_rib_node_id,
const Scope &scope);
@@ -208,7 +247,7 @@ private:
Resolver ();
void generate_builtins ();
- void setup_builtin (const std::string &name, TyTy::BaseType *tyty);
+ NodeId setup_builtin (const std::string &name, TyTy::BaseType *tyty);
Analysis::Mappings &mappings;
TypeCheckContext *tyctx;
@@ -222,6 +261,7 @@ private:
NodeId global_type_node_id;
NodeId unit_ty_node_id;
+ NodeId never_ty_node_id;
// map a AST Node to a Rib
std::map<NodeId, Rib *> name_ribs;
diff --git a/gcc/rust/resolve/rust-rib.cc b/gcc/rust/resolve/rust-rib.cc
index 0a8fce3..690bde9 100644
--- a/gcc/rust/resolve/rust-rib.cc
+++ b/gcc/rust/resolve/rust-rib.cc
@@ -22,41 +22,81 @@
namespace Rust {
namespace Resolver2_0 {
-Rib::Definition::Definition (NodeId id, bool shadowable)
- : ids ({id}), shadowable (shadowable)
-{}
+Rib::Definition::Definition (NodeId id, Mode mode, bool enum_variant)
+ : enum_variant (enum_variant)
+{
+ switch (mode)
+ {
+ case Mode::SHADOWABLE:
+ ids_shadowable.push_back (id);
+ return;
+ case Mode::NON_SHADOWABLE:
+ ids_non_shadowable.push_back (id);
+ return;
+ case Mode::GLOBBED:
+ ids_globbed.push_back (id);
+ return;
+ default:
+ gcc_unreachable ();
+ }
+}
bool
Rib::Definition::is_ambiguous () const
{
- return shadowable && ids.size () > 1;
+ if (!ids_shadowable.empty ())
+ return false;
+ else if (!ids_non_shadowable.empty ())
+ return ids_non_shadowable.size () > 1;
+ else
+ return ids_globbed.size () > 1;
+}
+
+bool
+Rib::Definition::is_variant () const
+{
+ return enum_variant;
}
std::string
Rib::Definition::to_string () const
{
std::stringstream out;
- out << (shadowable ? "(S)" : "(NS)") << "[";
- std::string sep;
- for (auto id : ids)
+ const char *headers[3] = {"(S)[", "] (NS)[", "] (G)["};
+ const std::vector<NodeId> *id_lists[3]
+ = {&ids_shadowable, &ids_non_shadowable, &ids_globbed};
+ for (int i = 0; i < 3; i++)
{
- out << sep << id;
- sep = ",";
+ out << headers[i];
+ std::string sep;
+ for (auto id : *id_lists[i])
+ {
+ out << sep << id;
+ sep = ",";
+ }
}
out << "]";
+ if (enum_variant)
+ out << "(enum variant)";
return out.str ();
}
Rib::Definition
Rib::Definition::Shadowable (NodeId id)
{
- return Definition (id, true);
+ return Definition (id, Mode::SHADOWABLE, false);
}
Rib::Definition
-Rib::Definition::NonShadowable (NodeId id)
+Rib::Definition::NonShadowable (NodeId id, bool enum_variant)
{
- return Definition (id, false);
+ return Definition (id, Mode::NON_SHADOWABLE, enum_variant);
+}
+
+Rib::Definition
+Rib::Definition::Globbed (NodeId id)
+{
+ return Definition (id, Mode::GLOBBED, false);
}
DuplicateNameError::DuplicateNameError (std::string name, NodeId existing)
@@ -85,29 +125,53 @@ Rib::insert (std::string name, Definition def)
/* No old value */
values[name] = def;
}
- else if (it->second.shadowable && def.shadowable)
- { /* Both shadowable */
+ else if (it->second.ids_non_shadowable.empty ()
+ || def.ids_non_shadowable.empty ())
+ { /* No non-shadowable conflict */
auto &current = values[name];
- for (auto id : def.ids)
+ for (auto id : def.ids_non_shadowable)
{
- if (std::find (current.ids.cbegin (), current.ids.cend (), id)
- == current.ids.cend ())
- {
- current.ids.push_back (id);
- }
+ if (std::find (current.ids_non_shadowable.cbegin (),
+ current.ids_non_shadowable.cend (), id)
+ == current.ids_non_shadowable.cend ())
+ current.ids_non_shadowable.push_back (id);
+ else
+ // TODO: should this produce an error?
+ return tl::make_unexpected (DuplicateNameError (name, id));
+ }
+ for (auto id : def.ids_shadowable)
+ {
+ if (std::find (current.ids_shadowable.cbegin (),
+ current.ids_shadowable.cend (), id)
+ == current.ids_shadowable.cend ())
+ current.ids_shadowable.push_back (id);
+ else
+ // TODO: should this produce an error?
+ return tl::make_unexpected (DuplicateNameError (name, id));
+ }
+ for (auto id : def.ids_globbed)
+ {
+ if (std::find (current.ids_globbed.cbegin (),
+ current.ids_globbed.cend (), id)
+ == current.ids_globbed.cend ())
+ current.ids_globbed.push_back (id);
+ else
+ // TODO: should this produce an error?
+ return tl::make_unexpected (DuplicateNameError (name, id));
}
}
- else if (it->second.shadowable)
- { /* Only old shadowable : replace value */
- values[name] = def;
- }
- else /* Neither are shadowable */
+ else /* Multiple non-shadowable */
{
return tl::make_unexpected (
- DuplicateNameError (name, it->second.ids.back ()));
+ DuplicateNameError (name, it->second.ids_non_shadowable.back ()));
}
- return def.ids.back ();
+ if (!def.ids_shadowable.empty ())
+ return def.ids_shadowable.back ();
+ else if (!def.ids_non_shadowable.empty ())
+ return def.ids_non_shadowable.back ();
+ rust_assert (!def.ids_globbed.empty ());
+ return def.ids_globbed.back ();
}
tl::optional<Rib::Definition>
diff --git a/gcc/rust/resolve/rust-rib.h b/gcc/rust/resolve/rust-rib.h
index 3228a3c..c498328 100644
--- a/gcc/rust/resolve/rust-rib.h
+++ b/gcc/rust/resolve/rust-rib.h
@@ -111,29 +111,61 @@ public:
class Definition
{
public:
- static Definition NonShadowable (NodeId id);
+ static Definition NonShadowable (NodeId id, bool enum_variant = false);
static Definition Shadowable (NodeId id);
-
- std::vector<NodeId> ids;
- bool shadowable;
+ static Definition Globbed (NodeId id);
+
+ // checked shadowable -> non_shadowable -> globbed
+ // we have shadowable *and* globbed in order to control
+ // resolution priority
+ // we *could* use a single vector with 2 indices here
+ // but it's probably not worth it for now
+ std::vector<NodeId> ids_shadowable;
+ std::vector<NodeId> ids_non_shadowable;
+ std::vector<NodeId> ids_globbed;
+
+ // Enum variant should be skipped when dealing with inner definition.
+ // struct E2;
+ //
+ // enum MyEnum<T> /* <-- Should be kept */{
+ // E2 /* <-- Should be skipped */ (E2);
+ // }
+ bool enum_variant;
Definition () = default;
Definition &operator= (const Definition &) = default;
Definition (Definition const &) = default;
+ bool is_variant () const;
+
bool is_ambiguous () const;
- NodeId get_node_id ()
+ NodeId get_node_id () const
{
+ if (!ids_shadowable.empty ())
+ return ids_shadowable.back ();
+
rust_assert (!is_ambiguous ());
- return ids[0];
+
+ if (!ids_non_shadowable.empty ())
+ return ids_non_shadowable.back ();
+
+ rust_assert (!ids_globbed.empty ());
+ return ids_globbed.back ();
}
std::string to_string () const;
private:
- Definition (NodeId id, bool shadowable);
+ enum class Mode
+ {
+ SHADOWABLE,
+ NON_SHADOWABLE,
+ GLOBBED
+ };
+
+ Definition (NodeId id, Mode mode, bool enum_variant);
};
enum class Kind
@@ -151,8 +183,42 @@ public:
ForwardTypeParamBan,
/* Const generic, as in the following example: fn foo<T, const X: T>() {} */
ConstParamType,
+ /* Prelude rib, used for both the language prelude (i32,usize,etc) and the
+ * (future) {std,core}::prelude::* import. A regular rib with the
+ * restriction that you cannot `use` items from the Prelude
+ */
+ Prelude,
} kind;
+ static std::string kind_to_string (Rib::Kind kind)
+ {
+ switch (kind)
+ {
+ case Rib::Kind::Normal:
+ return "Normal";
+ case Rib::Kind::Module:
+ return "Module";
+ case Rib::Kind::Function:
+ return "Function";
+ case Rib::Kind::ConstantItem:
+ return "ConstantItem";
+ case Rib::Kind::TraitOrImpl:
+ return "TraitOrImpl";
+ case Rib::Kind::Item:
+ return "Item";
+ case Rib::Kind::Closure:
+ return "Closure";
+ case Rib::Kind::MacroDefinition:
+ return "Macro definition";
+ case Rib::Kind::ForwardTypeParamBan:
+ return "Forward type param ban";
+ case Rib::Kind::ConstParamType:
+ return "Const Param Type";
+ default:
+ rust_unreachable ();
+ }
+ }
+
Rib (Kind kind);
Rib (Kind kind, std::string identifier, NodeId id);
Rib (Kind kind, std::unordered_map<std::string, NodeId> values);
diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
index 746b224..2f036fe 100644
--- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
@@ -26,109 +26,47 @@
namespace Rust {
namespace Resolver2_0 {
-void
-GlobbingVisitor::go (AST::Module *module)
-{
- for (auto &i : module->get_items ())
- visit (i);
-}
-
-void
-GlobbingVisitor::visit (AST::Module &module)
-{
- if (module.get_visibility ().is_public ())
- ctx.insert_shadowable (module.get_name (), module.get_node_id (),
- Namespace::Types);
-}
-
-void
-GlobbingVisitor::visit (AST::MacroRulesDefinition &macro)
-{
- if (macro.get_visibility ().is_public ())
- ctx.insert_shadowable (macro.get_rule_name (), macro.get_node_id (),
- Namespace::Macros);
-}
-
-void
-GlobbingVisitor::visit (AST::Function &function)
-{
- if (function.get_visibility ().is_public ())
- ctx.insert_shadowable (function.get_function_name (),
- function.get_node_id (), Namespace::Values);
-}
-
-void
-GlobbingVisitor::visit (AST::StaticItem &static_item)
-{
- if (static_item.get_visibility ().is_public ())
- ctx.insert_shadowable (static_item.get_identifier (),
- static_item.get_node_id (), Namespace::Values);
-}
+TopLevel::TopLevel (NameResolutionContext &resolver)
+ : DefaultResolver (resolver), dirty (false)
+{}
+template <typename T>
void
-GlobbingVisitor::visit (AST::StructStruct &struct_item)
+TopLevel::insert_enum_variant_or_error_out (const Identifier &identifier,
+ const T &node)
{
- if (struct_item.get_visibility ().is_public ())
- {
- ctx.insert_shadowable (struct_item.get_identifier (),
- struct_item.get_node_id (), Namespace::Types);
- if (struct_item.is_unit_struct ())
- ctx.insert_shadowable (struct_item.get_identifier (),
- struct_item.get_node_id (), Namespace::Values);
- }
+ insert_enum_variant_or_error_out (identifier, node.get_locus (),
+ node.get_node_id ());
}
void
-GlobbingVisitor::visit (AST::TupleStruct &tuple_struct)
+TopLevel::check_multiple_insertion_error (
+ tl::expected<NodeId, DuplicateNameError> result, const Identifier &identifier,
+ const location_t &locus, const NodeId node_id)
{
- if (tuple_struct.get_visibility ().is_public ())
+ if (result)
+ dirty = true;
+ else if (result.error ().existing != node_id)
{
- ctx.insert_shadowable (tuple_struct.get_identifier (),
- tuple_struct.get_node_id (), Namespace::Types);
+ rich_location rich_loc (line_table, locus);
+ rich_loc.add_range (node_locations[result.error ().existing]);
- ctx.insert_shadowable (tuple_struct.get_identifier (),
- tuple_struct.get_node_id (), Namespace::Values);
+ rust_error_at (rich_loc, ErrorCode::E0428, "%qs defined multiple times",
+ identifier.as_string ().c_str ());
}
}
-
void
-GlobbingVisitor::visit (AST::Enum &enum_item)
+TopLevel::insert_enum_variant_or_error_out (const Identifier &identifier,
+ const location_t &locus,
+ const NodeId node_id)
{
- if (enum_item.get_visibility ().is_public ())
- ctx.insert_shadowable (enum_item.get_identifier (),
- enum_item.get_node_id (), Namespace::Types);
-}
-
-void
-GlobbingVisitor::visit (AST::Union &union_item)
-{
- if (union_item.get_visibility ().is_public ())
- ctx.insert_shadowable (union_item.get_identifier (),
- union_item.get_node_id (), Namespace::Values);
-}
-
-void
-GlobbingVisitor::visit (AST::ConstantItem &const_item)
-{
- if (const_item.get_visibility ().is_public ())
- ctx.insert_shadowable (const_item.get_identifier (),
- const_item.get_node_id (), Namespace::Values);
-}
-
-void
-GlobbingVisitor::visit (AST::ExternCrate &crate)
-{}
+ // keep track of each node's location to provide useful errors
+ node_locations.emplace (node_id, locus);
-void
-GlobbingVisitor::visit (AST::UseDeclaration &use)
-{
- // Handle cycles ?
+ auto result = ctx.insert_variant (identifier, node_id);
+ check_multiple_insertion_error (result, identifier, locus, node_id);
}
-TopLevel::TopLevel (NameResolutionContext &resolver)
- : DefaultResolver (resolver)
-{}
-
template <typename T>
void
TopLevel::insert_or_error_out (const Identifier &identifier, const T &node,
@@ -146,15 +84,7 @@ TopLevel::insert_or_error_out (const Identifier &identifier,
node_locations.emplace (node_id, locus);
auto result = ctx.insert (identifier, node_id, ns);
-
- if (!result && result.error ().existing != node_id)
- {
- rich_location rich_loc (line_table, locus);
- rich_loc.add_range (node_locations[result.error ().existing]);
-
- rust_error_at (rich_loc, ErrorCode::E0428, "%qs defined multiple times",
- identifier.as_string ().c_str ());
- }
+ check_multiple_insertion_error (result, identifier, locus, node_id);
}
void
@@ -174,13 +104,28 @@ TopLevel::visit (AST::Module &module)
{
insert_or_error_out (module.get_name (), module, Namespace::Types);
- auto sub_visitor = [this, &module] () {
- for (auto &item : module.get_items ())
- item->accept_vis (*this);
- };
+ // Parse the module's items if they haven't been expanded and the file
+ // should be parsed (i.e isn't hidden behind an untrue or impossible cfg
+ // directive
+ // TODO: make sure this is right
+ // TODO: avoid loading items if cfg attributes are present?
+ // might not be needed if this runs after early resolution?
+ // This was copied from the old early resolver method
+ // 'accumulate_escaped_macros'
+ if (module.get_kind () == AST::Module::UNLOADED)
+ {
+ module.load_items ();
- ctx.scoped (Rib::Kind::Module, module.get_node_id (), sub_visitor,
- module.get_name ());
+ // If the module was previously unloaded, then we don't want to visit it
+ // this time around as the CfgStrip hasn't run on its inner items yet.
+ // Skip it for now, mark the visitor as dirty and try again
+
+ dirty = true;
+
+ return;
+ }
+
+ DefaultResolver::visit (module);
if (Analysis::Mappings::get ().lookup_ast_module (module.get_node_id ())
== tl::nullopt)
@@ -190,26 +135,50 @@ TopLevel::visit (AST::Module &module)
void
TopLevel::visit (AST::Trait &trait)
{
- // FIXME: This Self injection is dodgy. It even lead to issues with metadata
- // export in the past (#2349). We cannot tell appart injected parameters from
- // regular ones. Dumping generic parameters highlights this Self in metadata,
- // during debug or proc macro collection. This is clearly a hack.
- //
- // For now I'll keep it here in the new name resolver even if it should
- // probably not be there. We need to find another way to solve this.
- // Maybe an additional attribute to Trait ?
- //
- // From old resolver:
- //// we need to inject an implicit self TypeParam here
- //// FIXME: which location should be used for Rust::Identifier `Self`?
- AST::TypeParam *implicit_self
- = new AST::TypeParam ({"Self"}, trait.get_locus ());
- trait.insert_implict_self (
- std::unique_ptr<AST::GenericParam> (implicit_self));
+ insert_or_error_out (trait.get_identifier (), trait, Namespace::Types);
DefaultResolver::visit (trait);
}
+void
+TopLevel::visit (AST::InherentImpl &impl)
+{
+ auto inner_fn = [this, &impl] () {
+ insert_or_error_out (Identifier ("Self", impl.get_type ().get_locus ()),
+ impl.get_type (), Namespace::Types);
+
+ // We do want to visit with the default visitor instead of default resolver
+ // because we don't want to insert the scope twice.
+ AST::DefaultASTVisitor::visit (impl);
+ };
+
+ ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn);
+}
+
+void
+TopLevel::visit (AST::TraitImpl &impl)
+{
+ auto inner_fn = [this, &impl] () {
+ insert_or_error_out (Identifier ("Self", impl.get_type ().get_locus ()),
+ impl.get_type (), Namespace::Types);
+
+ // We do want to visit using the default visitor instead of default resolver
+ // because we don't want to insert the scope twice.
+ AST::DefaultASTVisitor::visit (impl);
+ };
+
+ ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn);
+}
+
+void
+TopLevel::visit (AST::TraitItemType &trait_item)
+{
+ insert_or_error_out (trait_item.get_identifier ().as_string (), trait_item,
+ Namespace::Types);
+
+ DefaultResolver::visit (trait_item);
+}
+
template <typename PROC_MACRO>
static void
insert_macros (std::vector<PROC_MACRO> &macros, NameResolutionContext &ctx)
@@ -231,7 +200,16 @@ void
TopLevel::visit (AST::ExternCrate &crate)
{
auto &mappings = Analysis::Mappings::get ();
- CrateNum num = *mappings.lookup_crate_name (crate.get_referenced_crate ());
+ auto num_opt = mappings.lookup_crate_name (crate.get_referenced_crate ());
+
+ if (!num_opt)
+ {
+ rust_error_at (crate.get_locus (), "unknown crate %qs",
+ crate.get_referenced_crate ().c_str ());
+ return;
+ }
+
+ CrateNum num = *num_opt;
auto attribute_macros = mappings.lookup_attribute_proc_macros (num);
@@ -323,34 +301,35 @@ TopLevel::visit (AST::Function &function)
}
void
-TopLevel::visit (AST::BlockExpr &expr)
+TopLevel::visit (AST::StaticItem &static_item)
{
- // extracting the lambda from the `scoped` call otherwise the code looks like
- // a hot turd thanks to our .clang-format
-
- auto sub_vis = [this, &expr] () {
- for (auto &stmt : expr.get_statements ())
- stmt->accept_vis (*this);
-
- if (expr.has_tail_expr ())
- expr.get_tail_expr ().accept_vis (*this);
- };
+ insert_or_error_out (static_item.get_identifier (), static_item,
+ Namespace::Values);
- ctx.scoped (Rib::Kind::Normal, expr.get_node_id (), sub_vis);
+ DefaultResolver::visit (static_item);
}
void
-TopLevel::visit (AST::StaticItem &static_item)
+TopLevel::visit (AST::ExternalStaticItem &static_item)
{
- auto sub_vis
- = [this, &static_item] () { static_item.get_expr ().accept_vis (*this); };
+ insert_or_error_out (static_item.get_identifier ().as_string (), static_item,
+ Namespace::Values);
- ctx.scoped (Rib::Kind::Item, static_item.get_node_id (), sub_vis);
+ DefaultResolver::visit (static_item);
}
void
TopLevel::visit (AST::StructStruct &struct_item)
{
+ auto generic_vis = [this, &struct_item] () {
+ for (auto &g : struct_item.get_generic_params ())
+ {
+ g->accept_vis (*this);
+ }
+ };
+
+ ctx.scoped (Rib::Kind::Item, struct_item.get_node_id (), generic_vis);
+
insert_or_error_out (struct_item.get_struct_name (), struct_item,
Namespace::Types);
@@ -363,6 +342,23 @@ TopLevel::visit (AST::StructStruct &struct_item)
}
void
+TopLevel::visit (AST::TypeParam &type_param)
+{
+ insert_or_error_out (type_param.get_type_representation (), type_param,
+ Namespace::Types);
+
+ DefaultResolver::visit (type_param);
+}
+
+void
+TopLevel::visit (AST::ConstGenericParam &const_param)
+{
+ insert_or_error_out (const_param.get_name (), const_param, Namespace::Values);
+
+ DefaultResolver::visit (const_param);
+}
+
+void
TopLevel::visit (AST::TupleStruct &tuple_struct)
{
insert_or_error_out (tuple_struct.get_struct_name (), tuple_struct,
@@ -370,24 +366,26 @@ TopLevel::visit (AST::TupleStruct &tuple_struct)
insert_or_error_out (tuple_struct.get_struct_name (), tuple_struct,
Namespace::Values);
+
+ DefaultResolver::visit (tuple_struct);
}
void
TopLevel::visit (AST::EnumItem &variant)
{
- insert_or_error_out (variant.get_identifier (), variant, Namespace::Types);
+ insert_enum_variant_or_error_out (variant.get_identifier (), variant);
}
void
TopLevel::visit (AST::EnumItemTuple &variant)
{
- insert_or_error_out (variant.get_identifier (), variant, Namespace::Types);
+ insert_enum_variant_or_error_out (variant.get_identifier (), variant);
}
void
TopLevel::visit (AST::EnumItemStruct &variant)
{
- insert_or_error_out (variant.get_identifier (), variant, Namespace::Types);
+ insert_enum_variant_or_error_out (variant.get_identifier (), variant);
}
void
@@ -402,13 +400,7 @@ TopLevel::visit (AST::Enum &enum_item)
insert_or_error_out (enum_item.get_identifier (), enum_item,
Namespace::Types);
- auto field_vis = [this, &enum_item] () {
- for (auto &variant : enum_item.get_variants ())
- variant->accept_vis (*this);
- };
-
- ctx.scoped (Rib::Kind::Item /* FIXME: Is that correct? */,
- enum_item.get_node_id (), field_vis, enum_item.get_identifier ());
+ DefaultResolver::visit (enum_item);
}
void
@@ -416,6 +408,8 @@ TopLevel::visit (AST::Union &union_item)
{
insert_or_error_out (union_item.get_identifier (), union_item,
Namespace::Types);
+
+ DefaultResolver::visit (union_item);
}
void
@@ -427,181 +421,13 @@ TopLevel::visit (AST::ConstantItem &const_item)
DefaultResolver::visit (const_item);
}
-bool
-TopLevel::handle_use_glob (AST::SimplePath &glob)
-{
- auto resolved = ctx.types.resolve_path (glob.get_segments ());
- if (!resolved.has_value ())
- return false;
-
- auto result
- = Analysis::Mappings::get ().lookup_ast_module (resolved->get_node_id ());
-
- if (!result.has_value ())
- return false;
-
- GlobbingVisitor gvisitor (ctx);
- gvisitor.go (result.value ());
-
- return true;
-}
-
-bool
-TopLevel::handle_use_dec (AST::SimplePath &path)
-{
- auto locus = path.get_final_segment ().get_locus ();
- auto declared_name = path.get_final_segment ().as_string ();
-
- // in what namespace do we perform path resolution? All of them? see which one
- // matches? Error out on ambiguities?
- // so, apparently, for each one that matches, add it to the proper namespace
- // :(
-
- auto found = false;
-
- auto resolve_and_insert
- = [this, &found, &declared_name, locus] (Namespace ns,
- const AST::SimplePath &path) {
- tl::optional<Rib::Definition> resolved = tl::nullopt;
-
- // FIXME: resolve_path needs to return an `expected<NodeId, Error>` so
- // that we can improve it with hints or location or w/ever. and maybe
- // only emit it the first time.
- switch (ns)
- {
- case Namespace::Values:
- resolved = ctx.values.resolve_path (path.get_segments ());
- break;
- case Namespace::Types:
- resolved = ctx.types.resolve_path (path.get_segments ());
- break;
- case Namespace::Macros:
- resolved = ctx.macros.resolve_path (path.get_segments ());
- break;
- case Namespace::Labels:
- // TODO: Is that okay?
- rust_unreachable ();
- }
-
- // FIXME: Ugly
- (void) resolved.map ([this, &found, &declared_name, locus, ns,
- path] (Rib::Definition def) {
- found = true;
-
- // what do we do with the id?
- insert_or_error_out (declared_name, locus, def.get_node_id (), ns);
- auto result = node_forwarding.find (def.get_node_id ());
- if (result != node_forwarding.cend ()
- && result->second != path.get_node_id ())
- rust_error_at (path.get_locus (), "%qs defined multiple times",
- declared_name.c_str ());
- else // No previous thing has inserted this into our scope
- node_forwarding.insert ({def.get_node_id (), path.get_node_id ()});
-
- return def.get_node_id ();
- });
- };
-
- resolve_and_insert (Namespace::Values, path);
- resolve_and_insert (Namespace::Types, path);
- resolve_and_insert (Namespace::Macros, path);
-
- return found;
-}
-
-bool
-TopLevel::handle_rebind (std::pair<AST::SimplePath, AST::UseTreeRebind> &rebind)
+void
+TopLevel::visit (AST::TypeAlias &type_item)
{
- auto &path = rebind.first;
-
- location_t locus = UNKNOWN_LOCATION;
- std::string declared_name;
-
- switch (rebind.second.get_new_bind_type ())
- {
- case AST::UseTreeRebind::NewBindType::IDENTIFIER:
- declared_name = rebind.second.get_identifier ().as_string ();
- locus = rebind.second.get_identifier ().get_locus ();
- break;
- case AST::UseTreeRebind::NewBindType::NONE:
- declared_name = path.get_final_segment ().as_string ();
- locus = path.get_final_segment ().get_locus ();
- break;
- case AST::UseTreeRebind::NewBindType::WILDCARD:
- rust_unreachable ();
- break;
- }
-
- // in what namespace do we perform path resolution? All
- // of them? see which one matches? Error out on
- // ambiguities? so, apparently, for each one that
- // matches, add it to the proper namespace
- // :(
- auto found = false;
-
- auto resolve_and_insert = [this, &found, &declared_name,
- locus] (Namespace ns,
- const AST::SimplePath &path) {
- tl::optional<Rib::Definition> resolved = tl::nullopt;
- tl::optional<Rib::Definition> resolved_bind = tl::nullopt;
-
- std::vector<AST::SimplePathSegment> declaration_v
- = {AST::SimplePathSegment (declared_name, locus)};
- // FIXME: resolve_path needs to return an `expected<NodeId, Error>` so
- // that we can improve it with hints or location or w/ever. and maybe
- // only emit it the first time.
- switch (ns)
- {
- case Namespace::Values:
- resolved = ctx.values.resolve_path (path.get_segments ());
- resolved_bind = ctx.values.resolve_path (declaration_v);
- break;
- case Namespace::Types:
- resolved = ctx.types.resolve_path (path.get_segments ());
- resolved_bind = ctx.types.resolve_path (declaration_v);
- break;
- case Namespace::Macros:
- resolved = ctx.macros.resolve_path (path.get_segments ());
- resolved_bind = ctx.macros.resolve_path (declaration_v);
- break;
- case Namespace::Labels:
- // TODO: Is that okay?
- rust_unreachable ();
- }
-
- resolved.map ([this, &found, &declared_name, locus, ns, path,
- &resolved_bind] (Rib::Definition def) {
- found = true;
-
- insert_or_error_out (declared_name, locus, def.get_node_id (), ns);
- if (resolved_bind.has_value ())
- {
- auto bind_def = resolved_bind.value ();
- // what do we do with the id?
- auto result = node_forwarding.find (bind_def.get_node_id ());
- if (result != node_forwarding.cend ()
- && result->second != path.get_node_id ())
- rust_error_at (path.get_locus (), "%qs defined multiple times",
- declared_name.c_str ());
- }
- else
- {
- // No previous thing has inserted this into our scope
- node_forwarding.insert ({def.get_node_id (), path.get_node_id ()});
- }
- return def.get_node_id ();
- });
- };
-
- // do this for all namespaces (even Labels?)
-
- resolve_and_insert (Namespace::Values, path);
- resolve_and_insert (Namespace::Types, path);
- resolve_and_insert (Namespace::Macros, path);
-
- // TODO: No labels? No, right?
+ insert_or_error_out (type_item.get_new_type_name (), type_item,
+ Namespace::Types);
- return found;
+ DefaultResolver::visit (type_item);
}
static void
@@ -721,6 +547,8 @@ flatten_glob (const AST::UseTreeGlob &glob, std::vector<AST::SimplePath> &paths,
{
if (glob.has_path ())
paths.emplace_back (glob.get_path ());
+ else
+ paths.emplace_back (AST::SimplePath ({}, false, glob.get_locus ()));
}
void
@@ -731,6 +559,10 @@ TopLevel::visit (AST::UseDeclaration &use)
auto rebind_path
= std::vector<std::pair<AST::SimplePath, AST::UseTreeRebind>> ();
+ auto &values_rib = ctx.values.peek ();
+ auto &types_rib = ctx.types.peek ();
+ auto &macros_rib = ctx.macros.peek ();
+
// FIXME: How do we handle `use foo::{self}` imports? Some beforehand cleanup?
// How do we handle module imports in general? Should they get added to all
// namespaces?
@@ -738,21 +570,22 @@ TopLevel::visit (AST::UseDeclaration &use)
const auto &tree = use.get_tree ();
flatten (tree.get (), paths, glob_path, rebind_path, this->ctx);
- for (auto &path : paths)
- if (!handle_use_dec (path))
- rust_error_at (path.get_final_segment ().get_locus (), ErrorCode::E0433,
- "unresolved import %qs", path.as_string ().c_str ());
-
- for (auto &glob : glob_path)
- if (!handle_use_glob (glob))
- rust_error_at (glob.get_final_segment ().get_locus (), ErrorCode::E0433,
- "unresolved import %qs", glob.as_string ().c_str ());
-
- for (auto &rebind : rebind_path)
- if (!handle_rebind (rebind))
- rust_error_at (rebind.first.get_final_segment ().get_locus (),
- ErrorCode::E0433, "unresolved import %qs",
- rebind.first.as_string ().c_str ());
+ auto imports = std::vector<ImportKind> ();
+
+ for (auto &&path : paths)
+ imports.emplace_back (
+ ImportKind::Simple (std::move (path), values_rib, types_rib, macros_rib));
+
+ for (auto &&glob : glob_path)
+ imports.emplace_back (
+ ImportKind::Glob (std::move (glob), values_rib, types_rib, macros_rib));
+
+ for (auto &&rebind : rebind_path)
+ imports.emplace_back (
+ ImportKind::Rebind (std::move (rebind.first), std::move (rebind.second),
+ values_rib, types_rib, macros_rib));
+
+ imports_to_resolve.insert ({use.get_node_id (), std::move (imports)});
}
} // namespace Resolver2_0
diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h
index 0950370..3ff37ed 100644
--- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h
+++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h
@@ -19,36 +19,16 @@
#ifndef RUST_TOPLEVEL_NAME_RESOLVER_2_0_H
#define RUST_TOPLEVEL_NAME_RESOLVER_2_0_H
+#include "optional.h"
#include "rust-ast-visitor.h"
+#include "rust-ast.h"
+#include "rust-item.h"
#include "rust-name-resolution-context.h"
#include "rust-default-resolver.h"
namespace Rust {
namespace Resolver2_0 {
-class GlobbingVisitor : public AST::DefaultASTVisitor
-{
- using AST::DefaultASTVisitor::visit;
-
-public:
- GlobbingVisitor (NameResolutionContext &ctx) : ctx (ctx) {}
-
- void go (AST::Module *module);
- void visit (AST::Module &module) override;
- void visit (AST::MacroRulesDefinition &macro) override;
- void visit (AST::Function &function) override;
- void visit (AST::StaticItem &static_item) override;
- void visit (AST::StructStruct &struct_item) override;
- void visit (AST::TupleStruct &tuple_struct) override;
- void visit (AST::Enum &enum_item) override;
- void visit (AST::Union &union_item) override;
- void visit (AST::ConstantItem &const_item) override;
- void visit (AST::ExternCrate &crate) override;
- void visit (AST::UseDeclaration &use) override;
-
-private:
- NameResolutionContext &ctx;
-};
/**
* The `TopLevel` visitor takes care of collecting all the definitions in a
* crate, and inserting them into the proper namespaces. These definitions can
@@ -63,10 +43,84 @@ public:
void go (AST::Crate &crate);
-private:
+ bool is_dirty () { return dirty; }
+
+ // Each import will be transformed into an instance of `ImportKind`, a class
+ // representing some of the data we need to resolve in the
+ // `EarlyNameResolver`. Basically, for each `UseTree` that we see in
+ // `TopLevel`, create one of these. `TopLevel` should build a list of these
+ // `ImportKind`s, which `Early` can then resolve to their proper definitions.
+ // Then, a final pass will insert the definitions into the `ForeverStack` -
+ // `FinalizeImports`.
+ //
+ // Using this struct should be very simple - each path within a `UseTree`
+ // becomes one `ImportKind`. The complex case is glob imports, in which case
+ // one glob import will become one `ImportKind` which will later become
+ // multiple definitions thanks to the `GlobbingVisitor`.
+ struct ImportKind
+ {
+ enum class Kind
+ {
+ Glob,
+ Simple,
+ Rebind,
+ } kind;
+
+ static ImportKind Glob (AST::SimplePath &&to_resolve, Rib &values_rib,
+ Rib &types_rib, Rib &macros_rib)
+ {
+ return ImportKind (Kind::Glob, std::move (to_resolve), values_rib,
+ types_rib, macros_rib);
+ }
+
+ static ImportKind Simple (AST::SimplePath &&to_resolve, Rib &values_rib,
+ Rib &types_rib, Rib &macros_rib)
+ {
+ return ImportKind (Kind::Simple, std::move (to_resolve), values_rib,
+ types_rib, macros_rib);
+ }
+
+ static ImportKind Rebind (AST::SimplePath &&to_resolve,
+ AST::UseTreeRebind &&rebind, Rib &values_rib,
+ Rib &types_rib, Rib &macros_rib)
+ {
+ return ImportKind (Kind::Rebind, std::move (to_resolve), values_rib,
+ types_rib, macros_rib, std::move (rebind));
+ }
+
+ // The path for `Early` to resolve.
+ AST::SimplePath to_resolve;
+
+ // The path to rebind an import to - only present if kind is Kind::Rebind
+ tl::optional<AST::UseTreeRebind> rebind;
+
+ Rib &values_rib;
+ Rib &types_rib;
+ Rib &macros_rib;
+
+ private:
+ ImportKind (Kind kind, AST::SimplePath &&to_resolve, Rib &values_rib,
+ Rib &types_rib, Rib &macros_rib,
+ tl::optional<AST::UseTreeRebind> &&rebind = tl::nullopt)
+ : kind (kind), to_resolve (std::move (to_resolve)),
+ rebind (std::move (rebind)), values_rib (values_rib),
+ types_rib (types_rib), macros_rib (macros_rib)
+ {}
+ };
+
+ std::unordered_map<NodeId, std::vector<ImportKind>> &get_imports_to_resolve ()
+ {
+ return imports_to_resolve;
+ }
+
+ void check_multiple_insertion_error (
+ tl::expected<NodeId, DuplicateNameError> result,
+ const Identifier &identifier, const location_t &locus,
+ const NodeId node_id);
+
/**
- * Insert a new definition or error out if a definition with the same name was
- * already present in the same namespace in the same scope.
+ * Insert a new definition or error out if a definition with the same name
+ * was already present in the same namespace in the same scope.
*
* @param identifier The identifier of the definition to add.
* @param node A reference to the node, so we can get its `NodeId` and
@@ -80,19 +134,39 @@ private:
const location_t &locus, const NodeId &id,
Namespace ns);
+ template <typename T>
+ void insert_enum_variant_or_error_out (const Identifier &identifier,
+ const T &node);
+
+ void insert_enum_variant_or_error_out (const Identifier &identifier,
+ const location_t &locus,
+ const NodeId node_id);
+
+private:
+ // If a new export has been defined whilst visiting the visitor is considered
+ // dirty
+ bool dirty;
+
// FIXME: Do we move these to our mappings?
std::unordered_map<NodeId, location_t> node_locations;
// Store node forwarding for use declaration, the link between a
- // "new" local name and its definition.
+ // definition and its new local name.
std::unordered_map<NodeId, NodeId> node_forwarding;
+ // One of the outputs of the `TopLevel` visitor - the list of imports that
+ // `Early` should take care of resolving
+ std::unordered_map<NodeId, std::vector<ImportKind>> imports_to_resolve;
+
void visit (AST::Module &module) override;
void visit (AST::Trait &trait) override;
+ void visit (AST::InherentImpl &impl) override;
+ void visit (AST::TraitImpl &impl) override;
+ void visit (AST::TraitItemType &trait_item) override;
void visit (AST::MacroRulesDefinition &macro) override;
void visit (AST::Function &function) override;
- void visit (AST::BlockExpr &expr) override;
void visit (AST::StaticItem &static_item) override;
+ void visit (AST::ExternalStaticItem &static_item) override;
void visit (AST::StructStruct &struct_item) override;
void visit (AST::TupleStruct &tuple_struct) override;
void visit (AST::EnumItem &variant) override;
@@ -102,15 +176,10 @@ private:
void visit (AST::Enum &enum_item) override;
void visit (AST::Union &union_item) override;
void visit (AST::ConstantItem &const_item) override;
+ void visit (AST::TypeAlias &type_item) override;
void visit (AST::ExternCrate &crate) override;
-
- // FIXME: Documentation
- // Call this on all the paths of a UseDec - so each flattened path in a
- // UseTreeList for example
- // FIXME: Should that return `found`?
- bool handle_use_dec (AST::SimplePath &path);
- bool handle_use_glob (AST::SimplePath &glob);
- bool handle_rebind (std::pair<AST::SimplePath, AST::UseTreeRebind> &pair);
+ void visit (AST::TypeParam &type_param) override;
+ void visit (AST::ConstGenericParam &const_param) override;
void visit (AST::UseDeclaration &use) override;
};
@@ -118,4 +187,17 @@ private:
} // namespace Resolver2_0
} // namespace Rust
+// For storing Imports as keys in maps
+namespace std {
+template <> struct less<Rust::Resolver2_0::TopLevel::ImportKind>
+{
+ bool operator() (const Rust::Resolver2_0::TopLevel::ImportKind &lhs,
+ const Rust::Resolver2_0::TopLevel::ImportKind &rhs) const
+ {
+ return lhs.to_resolve.as_string () < rhs.to_resolve.as_string ()
+ && lhs.kind < rhs.kind;
+ }
+};
+} // namespace std
+
#endif // !RUST_TOPLEVEL_NAME_RESOLVER_2_0_H