diff options
Diffstat (limited to 'gcc/rust/resolve')
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 ¶m, 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 ¶m : 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 ¶m : 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 ¶m, const CanonicalPath &prefix, - const CanonicalPath &canonical_prefix) + static void go (std::vector<std::unique_ptr<AST::GenericParam>> ¶ms, + 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 ¶m : params) + param->accept_vis (resolver); + + resolver.first_pass = false; + + for (auto ¶m : params) + param->accept_vis (resolver); } - void visit (AST::ConstGenericParam ¶m) override + static void go_single (AST::GenericParam ¶m, 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 ¶m) override + void visit (AST::ConstGenericParam ¶m) 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 ¶m) 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 ¶m = static_cast<AST::VariadicParam &> (*p); - if (param.has_pattern ()) - param.get_pattern ().accept_vis (*this); - } - else if (p->is_self ()) - { - auto ¶m = static_cast<AST::SelfParam &> (*p); - param.get_type ().accept_vis (*this); - param.get_lifetime ().accept_vis (*this); - } - else - { - auto ¶m = 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 ¶m : 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 ¶m : 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 ¶m : 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 ¶m : 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 ¶m) +{ + auto expr_vis = [this, ¶m] () { 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 ¯o) +{ + 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 ¯o) 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 = ¤t_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 ¤t) { + reverse_iter (containing_node, [&segments] (const Node ¤t) { 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 ¶m : 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 ¶m) +{ + // 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 ¶m : 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 ¶m : 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 ¤t = 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 ¯o) -{ - 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> ¯os, 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 ¯os_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 ¯o) 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 ¯os_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 ¯os_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 ¯os_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 ¯os_rib; + + private: + ImportKind (Kind kind, AST::SimplePath &&to_resolve, Rib &values_rib, + Rib &types_rib, Rib ¯os_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 ¯o) 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 |