diff options
Diffstat (limited to 'gcc/rust/resolve')
38 files changed, 3868 insertions, 1035 deletions
diff --git a/gcc/rust/resolve/rust-ast-resolve-base.cc b/gcc/rust/resolve/rust-ast-resolve-base.cc index b23c1eb..3c7b425 100644 --- a/gcc/rust/resolve/rust-ast-resolve-base.cc +++ b/gcc/rust/resolve/rust-ast-resolve-base.cc @@ -72,14 +72,6 @@ ResolverBase::visit (AST::ConstGenericParam &) {} void -ResolverBase::visit (AST::RegularPath &) -{} - -void -ResolverBase::visit (AST::LangItemPath &) -{} - -void ResolverBase::visit (AST::PathInExpression &) {} @@ -124,7 +116,7 @@ ResolverBase::visit (AST::MetaItemLitExpr &) {} void -ResolverBase::visit (AST::MetaItemPathLit &) +ResolverBase::visit (AST::MetaItemPathExpr &) {} void @@ -240,6 +232,14 @@ ResolverBase::visit (AST::BlockExpr &) {} void +ResolverBase::visit (AST::AnonConst &) +{} + +void +ResolverBase::visit (AST::ConstBlock &) +{} + +void ResolverBase::visit (AST::ClosureExprInnerTyped &) {} @@ -284,6 +284,10 @@ ResolverBase::visit (AST::ReturnExpr &) {} void +ResolverBase::visit (AST::TryExpr &) +{} + +void ResolverBase::visit (AST::UnsafeBlockExpr &) {} @@ -336,6 +340,10 @@ ResolverBase::visit (AST::InlineAsm &) {} void +ResolverBase::visit (AST::LlvmInlineAsm &) +{} + +void ResolverBase::visit (AST::TypeParam &) {} @@ -576,6 +584,14 @@ ResolverBase::visit (AST::GroupedPattern &) {} void +ResolverBase::visit (AST::SlicePatternItemsNoRest &) +{} + +void +ResolverBase::visit (AST::SlicePatternItemsHasRest &) +{} + +void ResolverBase::visit (AST::SlicePattern &) {} @@ -667,5 +683,9 @@ void ResolverBase::visit (AST::FormatArgs &fmt) {} +void +ResolverBase::visit (AST::OffsetOf &offset_of) +{} + } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/resolve/rust-ast-resolve-base.h b/gcc/rust/resolve/rust-ast-resolve-base.h index 703460a..89c5c35 100644 --- a/gcc/rust/resolve/rust-ast-resolve-base.h +++ b/gcc/rust/resolve/rust-ast-resolve-base.h @@ -21,12 +21,19 @@ #include "rust-ast-visitor.h" #include "rust-ast.h" +#include "rust-builtin-ast-nodes.h" +#include "rust-expr.h" #include "rust-name-resolver.h" #include "rust-diagnostics.h" #include "rust-location.h" namespace Rust { namespace Resolver { +inline void +redefined_error (const rich_location &loc) +{ + rust_error_at (loc, "redefined multiple times"); +} class ResolverBase : public AST::ASTVisitor { @@ -40,8 +47,6 @@ public: void visit (AST::Lifetime &); void visit (AST::LifetimeParam &); void visit (AST::ConstGenericParam &); - void visit (AST::RegularPath &); - void visit (AST::LangItemPath &); void visit (AST::PathInExpression &); void visit (AST::TypePathSegment &); void visit (AST::TypePathSegmentGeneric &); @@ -53,7 +58,7 @@ public: void visit (AST::AttrInputLiteral &); void visit (AST::AttrInputMacro &); void visit (AST::MetaItemLitExpr &); - void visit (AST::MetaItemPathLit &); + void visit (AST::MetaItemPathExpr &); void visit (AST::BorrowExpr &); void visit (AST::DereferenceExpr &); void visit (AST::ErrorPropagationExpr &); @@ -82,6 +87,8 @@ public: void visit (AST::FieldAccessExpr &); void visit (AST::ClosureExprInner &); void visit (AST::BlockExpr &); + void visit (AST::AnonConst &); + void visit (AST::ConstBlock &); void visit (AST::ClosureExprInnerTyped &); void visit (AST::ContinueExpr &); void visit (AST::BreakExpr &); @@ -93,6 +100,7 @@ public: void visit (AST::RangeToInclExpr &); void visit (AST::BoxExpr &); void visit (AST::ReturnExpr &); + void visit (AST::TryExpr &); void visit (AST::UnsafeBlockExpr &); void visit (AST::LoopExpr &); void visit (AST::WhileLoopExpr &); @@ -107,6 +115,7 @@ public: void visit (AST::AwaitExpr &); void visit (AST::AsyncBlockExpr &); void visit (AST::InlineAsm &); + void visit (AST::LlvmInlineAsm &); void visit (AST::TypeParam &); @@ -177,6 +186,8 @@ public: void visit (AST::TuplePatternItemsRanged &); void visit (AST::TuplePattern &); void visit (AST::GroupedPattern &); + void visit (AST::SlicePatternItemsNoRest &); + void visit (AST::SlicePatternItemsHasRest &); void visit (AST::SlicePattern &); void visit (AST::AltPattern &); @@ -203,6 +214,7 @@ public: void visit (AST::SelfParam ¶m); void visit (AST::FormatArgs &fmt); + void visit (AST::OffsetOf &offset_of); protected: ResolverBase () diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.cc b/gcc/rust/resolve/rust-ast-resolve-expr.cc index 7ddf4a9..a410193 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.cc +++ b/gcc/rust/resolve/rust-ast-resolve-expr.cc @@ -22,8 +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 { @@ -108,46 +108,6 @@ ResolveExpr::visit (AST::AssignmentExpr &expr) ResolveExpr::go (expr.get_right_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) -{ - 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); -} - void ResolveExpr::visit (AST::IdentifierExpr &expr) { @@ -169,8 +129,8 @@ ResolveExpr::visit (AST::IdentifierExpr &expr) resolve. Emit a funny ICE. We set the finalizer to our custom one, and use the lower-level emit_diagnostic () instead of the more common internal_error_no_backtrace () in order to pass our locus. */ - diagnostic_text_finalizer (global_dc) = funny_ice_text_finalizer; - emit_diagnostic (DK_ICE_NOBT, expr.get_locus (), -1, + diagnostics::text_finalizer (global_dc) = funny_ice_text_finalizer; + emit_diagnostic (diagnostics::kind::ice_nobt, expr.get_locus (), -1, "are you trying to break %s? how dare you?", expr.as_string ().c_str ()); } @@ -249,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. @@ -279,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. @@ -308,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 ()) { @@ -327,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"); }); } @@ -355,6 +315,18 @@ ResolveExpr::visit (AST::BlockExpr &expr) } void +ResolveExpr::visit (AST::AnonConst &expr) +{ + ResolveExpr::go (expr.get_inner_expr (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::ConstBlock &expr) +{ + ResolveExpr::go (expr.get_const_expr (), prefix, canonical_prefix); +} + +void translate_operand (AST::InlineAsm &expr, const CanonicalPath &prefix, const CanonicalPath &canonical_prefix) { @@ -364,38 +336,46 @@ translate_operand (AST::InlineAsm &expr, const CanonicalPath &prefix, { switch (operand.get_register_type ()) { - case RegisterType::In: { + case RegisterType::In: + { auto in = operand.get_in (); ResolveExpr::go (*in.expr, prefix, canonical_prefix); break; } - case RegisterType::Out: { + case RegisterType::Out: + { auto out = operand.get_out (); ResolveExpr::go (*out.expr, prefix, canonical_prefix); break; } - case RegisterType::InOut: { + case RegisterType::InOut: + { auto in_out = operand.get_in_out (); ResolveExpr::go (*in_out.expr, prefix, canonical_prefix); break; } - case RegisterType::SplitInOut: { + 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: { + case RegisterType::Const: + { auto anon_const = operand.get_const ().anon_const; - ResolveExpr::go (*anon_const.expr, prefix, canonical_prefix); + ResolveExpr::go (anon_const.get_inner_expr (), prefix, + canonical_prefix); break; } - case RegisterType::Sym: { + case RegisterType::Sym: + { auto sym = operand.get_sym (); ResolveExpr::go (*sym.expr, prefix, canonical_prefix); break; } - case RegisterType::Label: { + case RegisterType::Label: + { auto label = operand.get_label (); ResolveExpr::go (*label.expr, prefix, canonical_prefix); break; @@ -408,6 +388,17 @@ 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) { @@ -499,7 +490,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"); }); } @@ -511,7 +502,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 (), @@ -526,8 +517,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); @@ -537,7 +528,7 @@ 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 @@ -575,7 +566,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"); }); } @@ -604,7 +595,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"); }); } @@ -616,7 +607,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); @@ -634,7 +625,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 (), @@ -648,9 +639,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); @@ -682,7 +673,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 (); @@ -751,7 +742,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> ())}; @@ -781,7 +772,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> ())}; @@ -795,7 +786,7 @@ ResolveExpr::visit (AST::ClosureExprInnerTyped &expr) resolver->push_closure_context (expr.get_node_id ()); - ResolveExpr::go (expr.get_definition_block (), prefix, canonical_prefix); + ResolveExpr::go (expr.get_definition_expr (), prefix, canonical_prefix); resolver->pop_closure_context (); diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h index 562a3bd..aad1605 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.h +++ b/gcc/rust/resolve/rust-ast-resolve-expr.h @@ -56,7 +56,10 @@ public: void visit (AST::IfLetExpr &expr) override; void visit (AST::IfLetExprConseqElse &expr) override; void visit (AST::BlockExpr &expr) override; + void visit (AST::AnonConst &expr) override; + void visit (AST::ConstBlock &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; 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..1d5ebed 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 ()); @@ -451,7 +453,8 @@ ResolveItem::visit (AST::ConstantItem &constant) resolve_visibility (constant.get_visibility ()); ResolveType::go (constant.get_type ()); - ResolveExpr::go (constant.get_expr (), path, cpath); + if (constant.has_expr ()) + ResolveExpr::go (constant.get_expr (), path, cpath); } void @@ -473,11 +476,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 +570,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 +585,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 ()); @@ -599,10 +609,7 @@ ResolveItem::visit (AST::InherentImpl &impl_block) } else { - std::string seg_buf = "<impl " + self_cpath.get () + ">"; - CanonicalPath seg - = CanonicalPath::new_seg (impl_block.get_node_id (), seg_buf); - cpath = canonical_prefix.append (seg); + cpath = canonical_prefix.append (impl_type_seg); } // done setup paths @@ -641,11 +648,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 +678,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 +699,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 ()); @@ -709,13 +730,7 @@ ResolveItem::visit (AST::TraitImpl &impl_block) } else { - std::string projection_str = canonical_projection.get (); - std::string seg_buf - = "<impl " + projection_str.substr (1, projection_str.size () - 2) - + ">"; - CanonicalPath seg - = CanonicalPath::new_seg (impl_block.get_node_id (), seg_buf); - cpath = canonical_prefix.append (seg); + cpath = canonical_prefix.append (canonical_projection); } // DONE setup canonical-path @@ -755,20 +770,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 ()) { @@ -821,29 +830,32 @@ ResolveItem::resolve_extern_item (AST::ExternalItem &item) ResolveExternItem::go (item, prefix, canonical_prefix); } -static void -flatten_glob (const AST::UseTreeGlob &glob, std::vector<Import> &imports); -static void -flatten_rebind (const AST::UseTreeRebind &glob, std::vector<Import> &imports); -static void -flatten_list (const AST::UseTreeList &glob, std::vector<Import> &imports); +static void flatten_glob (const AST::UseTreeGlob &glob, + std::vector<Import> &imports); +static void flatten_rebind (const AST::UseTreeRebind &glob, + std::vector<Import> &imports); +static void flatten_list (const AST::UseTreeList &glob, + std::vector<Import> &imports); static void flatten (const AST::UseTree *tree, std::vector<Import> &imports) { switch (tree->get_kind ()) { - case AST::UseTree::Glob: { + case AST::UseTree::Glob: + { auto glob = static_cast<const AST::UseTreeGlob *> (tree); flatten_glob (*glob, imports); break; } - case AST::UseTree::Rebind: { + case AST::UseTree::Rebind: + { auto rebind = static_cast<const AST::UseTreeRebind *> (tree); flatten_rebind (*rebind, imports); break; } - case AST::UseTree::List: { + case AST::UseTree::List: + { auto list = static_cast<const AST::UseTreeList *> (tree); flatten_list (*list, imports); break; @@ -888,7 +900,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 +1048,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-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h index 776dd53..d31f910 100644 --- a/gcc/rust/resolve/rust-ast-resolve-item.h +++ b/gcc/rust/resolve/rust-ast-resolve-item.h @@ -153,8 +153,7 @@ private: #if CHECKING_P namespace selftest { -extern void -rust_simple_path_resolve_test (void); +extern void rust_simple_path_resolve_test (void); } // namespace selftest #endif // CHECKING_P 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 ee84be8..3b80f9f 100644 --- a/gcc/rust/resolve/rust-ast-resolve-pattern.cc +++ b/gcc/rust/resolve/rust-ast-resolve-pattern.cc @@ -62,6 +62,11 @@ PatternDeclaration::go (AST::Pattern &pattern, Rib::ItemType type, void PatternDeclaration::visit (AST::IdentifierPattern &pattern) { + if (pattern.has_subpattern ()) + { + pattern.get_subpattern ().accept_vis (*this); + } + Mutability mut = pattern.get_is_mut () ? Mutability::Mut : Mutability::Imm; add_new_binding (pattern.get_ident (), pattern.get_node_id (), BindingTypeInfo (mut, pattern.get_is_ref (), @@ -94,13 +99,15 @@ PatternDeclaration::visit (AST::TupleStructPattern &pattern) AST::TupleStructItems &items = pattern.get_items (); switch (items.get_item_type ()) { - case AST::TupleStructItems::RANGE: { + case AST::TupleStructItems::RANGE: + { // TODO rust_unreachable (); } break; - case AST::TupleStructItems::NO_RANGE: { + case AST::TupleStructItems::NO_RANGE: + { auto &items_no_range = static_cast<AST::TupleStructItemsNoRange &> (items); @@ -123,7 +130,8 @@ PatternDeclaration::visit (AST::StructPattern &pattern) { switch (field->get_item_type ()) { - case AST::StructPatternField::ItemType::TUPLE_PAT: { + case AST::StructPatternField::ItemType::TUPLE_PAT: + { AST::StructPatternFieldTuplePat &tuple = static_cast<AST::StructPatternFieldTuplePat &> (*field); @@ -131,7 +139,8 @@ PatternDeclaration::visit (AST::StructPattern &pattern) } break; - case AST::StructPatternField::ItemType::IDENT_PAT: { + case AST::StructPatternField::ItemType::IDENT_PAT: + { AST::StructPatternFieldIdentPat &ident = static_cast<AST::StructPatternFieldIdentPat &> (*field); @@ -139,7 +148,8 @@ PatternDeclaration::visit (AST::StructPattern &pattern) } break; - case AST::StructPatternField::ItemType::IDENT: { + case AST::StructPatternField::ItemType::IDENT: + { auto &ident = static_cast<AST::StructPatternFieldIdent &> (*field); Mutability mut @@ -160,7 +170,8 @@ PatternDeclaration::visit (AST::TuplePattern &pattern) auto &items = pattern.get_items (); switch (items.get_pattern_type ()) { - case AST::TuplePatternItems::TuplePatternItemType::MULTIPLE: { + case AST::TuplePatternItems::TuplePatternItemType::MULTIPLE: + { auto &ref = static_cast<AST::TuplePatternItemsMultiple &> ( pattern.get_items ()); @@ -169,7 +180,8 @@ PatternDeclaration::visit (AST::TuplePattern &pattern) } break; - case AST::TuplePatternItems::TuplePatternItemType::RANGED: { + case AST::TuplePatternItems::TuplePatternItemType::RANGED: + { auto &ref = static_cast<AST::TuplePatternItemsRanged &> (pattern.get_items ()); @@ -348,14 +360,16 @@ resolve_range_pattern_bound (AST::RangePatternBound &bound) // Nothing to resolve for a literal. break; - case AST::RangePatternBound::RangePatternBoundType::PATH: { + case AST::RangePatternBound::RangePatternBoundType::PATH: + { auto &ref = static_cast<AST::RangePatternBoundPath &> (bound); ResolvePath::go (ref.get_path ()); } break; - case AST::RangePatternBound::RangePatternBoundType::QUALPATH: { + case AST::RangePatternBound::RangePatternBoundType::QUALPATH: + { auto &ref = static_cast<AST::RangePatternBoundQualPath &> (bound); ResolvePath::go (ref.get_qualified_path ()); @@ -374,9 +388,30 @@ PatternDeclaration::visit (AST::RangePattern &pattern) void PatternDeclaration::visit (AST::SlicePattern &pattern) { - for (auto &p : pattern.get_items ()) + auto &items = pattern.get_items (); + switch (items.get_pattern_type ()) { - p->accept_vis (*this); + case AST::SlicePatternItems::SlicePatternItemType::NO_REST: + { + auto &ref + = static_cast<AST::SlicePatternItemsNoRest &> (pattern.get_items ()); + + for (auto &p : ref.get_patterns ()) + p->accept_vis (*this); + } + break; + + case AST::SlicePatternItems::SlicePatternItemType::HAS_REST: + { + auto &ref + = static_cast<AST::SlicePatternItemsHasRest &> (pattern.get_items ()); + + for (auto &p : ref.get_lower_patterns ()) + p->accept_vis (*this); + for (auto &p : ref.get_upper_patterns ()) + p->accept_vis (*this); + } + break; } } 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..d714511 100644 --- a/gcc/rust/resolve/rust-ast-resolve-stmt.h +++ b/gcc/rust/resolve/rust-ast-resolve-stmt.h @@ -63,19 +63,21 @@ 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 ()); - ResolveExpr::go (constant.get_expr (), prefix, canonical_prefix); + if (constant.has_expr ()) + ResolveExpr::go (constant.get_expr (), prefix, canonical_prefix); } 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 +99,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 +130,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 +160,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 +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); }); for (auto &field : item.get_tuple_fields ()) @@ -208,7 +206,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 +232,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 +253,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 +289,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 +325,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 +334,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 +384,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 ec5e8a7..a040228 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,7 +115,7 @@ ResolveType::visit (AST::RawPointerType &type) void ResolveType::visit (AST::InferredType &) { - // FIXME + // nothing to do } 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 ().get ()); +} + // resolve relative type-paths bool @@ -91,50 +156,62 @@ 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 ()) { - case AST::TypePathSegment::SegmentType::GENERIC: { + case AST::TypePathSegment::SegmentType::GENERIC: + { AST::TypePathSegmentGeneric *s = static_cast<AST::TypePathSegmentGeneric *> (segment.get ()); if (s->has_generic_args ()) @@ -169,27 +246,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 +297,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 +305,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 +356,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 +367,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 { @@ -381,7 +510,8 @@ ResolveTypeToCanonicalPath::visit (AST::TypePath &path) auto &final_seg = path.get_segments ().back (); switch (final_seg->get_type ()) { - case AST::TypePathSegment::SegmentType::GENERIC: { + case AST::TypePathSegment::SegmentType::GENERIC: + { AST::TypePathSegmentGeneric *s = static_cast<AST::TypePathSegmentGeneric *> (final_seg.get ()); @@ -495,10 +625,60 @@ 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 diff --git a/gcc/rust/resolve/rust-ast-resolve-type.h b/gcc/rust/resolve/rust-ast-resolve-type.h index 561948e..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; }; diff --git a/gcc/rust/resolve/rust-ast-resolve.cc b/gcc/rust/resolve/rust-ast-resolve.cc index a093ef7..2208f70 100644 --- a/gcc/rust/resolve/rust-ast-resolve.cc +++ b/gcc/rust/resolve/rust-ast-resolve.cc @@ -24,8 +24,7 @@ #include "rust-ast-resolve-expr.h" #include "rust-ast-resolve-struct-expr-field.h" -extern bool -saw_errors (void); +extern bool saw_errors (void); namespace Rust { namespace Resolver { @@ -75,7 +74,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 57b1cc4..f1c0e5c 100644 --- a/gcc/rust/resolve/rust-default-resolver.cc +++ b/gcc/rust/resolve/rust-default-resolver.cc @@ -25,6 +25,21 @@ namespace Rust { namespace Resolver2_0 { void +DefaultResolver::visit (AST::Crate &crate) +{ + auto inner_fn = [this, &crate] () { AST::DefaultASTVisitor::visit (crate); }; + + auto &mappings = Analysis::Mappings::get (); + + auto crate_num = mappings.lookup_crate_num (crate.get_node_id ()); + rust_assert (crate_num.has_value ()); + auto crate_name = mappings.get_crate_name (*crate_num); + rust_assert (crate_name.has_value ()); + + ctx.canonical_ctx.scope_crate (crate.get_node_id (), *crate_name, inner_fn); +} + +void DefaultResolver::visit (AST::BlockExpr &expr) { // extracting the lambda from the `scoped` call otherwise the code looks like @@ -38,19 +53,32 @@ DefaultResolver::visit (AST::BlockExpr &expr) void DefaultResolver::visit (AST::Module &module) { - auto item_fn = [this, &module] () { AST::DefaultASTVisitor::visit (module); }; + auto item_fn_1 + = [this, &module] () { AST::DefaultASTVisitor::visit (module); }; - ctx.scoped (Rib::Kind::Module, module.get_node_id (), item_fn, + auto item_fn_2 = [this, &module, &item_fn_1] () { + ctx.canonical_ctx.scope (module.get_node_id (), module.get_name (), + std::move (item_fn_1)); + }; + + ctx.scoped (Rib::Kind::Module, module.get_node_id (), item_fn_2, module.get_name ()); } void DefaultResolver::visit (AST::Function &function) { - auto def_fn + auto def_fn_1 = [this, &function] () { AST::DefaultASTVisitor::visit (function); }; - ctx.scoped (Rib::Kind::Function, function.get_node_id (), def_fn); + auto def_fn_2 = [this, &function, &def_fn_1] () { + ctx.canonical_ctx.scope (function.get_node_id (), + function.get_function_name (), + std::move (def_fn_1)); + }; + + ctx.scoped (Rib::Kind::Function, function.get_node_id (), def_fn_2, + function.get_function_name ()); } void @@ -61,52 +89,252 @@ DefaultResolver::visit (AST::ForLoopExpr &expr) } void -DefaultResolver::visit (AST::Trait &trait) +DefaultResolver::visit_if_let_patterns (AST::IfLetExpr &expr) +{ + for (auto &pattern : expr.get_patterns ()) + visit (pattern); +} + +void +DefaultResolver::visit (AST::IfLetExpr &expr) { - auto inner_fn = [this, &trait] () { AST::DefaultASTVisitor::visit (trait); }; + auto inner_vis = [this, &expr] () { + visit_if_let_patterns (expr); + visit (expr.get_if_block ()); + }; - ctx.scoped (Rib::Kind::TraitOrImpl, trait.get_node_id (), inner_fn, + visit_outer_attrs (expr); + + visit (expr.get_value_expr ()); + + ctx.scoped (Rib::Kind::Normal, expr.get_node_id (), inner_vis); +} + +void +DefaultResolver::visit (AST::IfLetExprConseqElse &expr) +{ + DefaultResolver::visit (static_cast<AST::IfLetExpr &> (expr)); + visit (expr.get_else_block ()); +} + +void +DefaultResolver::visit (AST::Trait &trait) +{ + visit_outer_attrs (trait); + visit (trait.get_visibility ()); + visit_inner_attrs (trait); + + auto inner_fn_1 = [this, &trait] () { + for (auto &item : trait.get_trait_items ()) + visit (item); + }; + + auto inner_fn_2 = [this, &trait, &inner_fn_1] () { + visit (trait.get_implicit_self ()); + for (auto &generic : trait.get_generic_params ()) + visit (generic); + if (trait.has_where_clause ()) + visit (trait.get_where_clause ()); + for (auto &bound : trait.get_type_param_bounds ()) + visit (bound); + + ctx.scoped (Rib::Kind::TraitOrImpl, trait.get_node_id (), inner_fn_1); + }; + + auto inner_fn_3 = [this, &trait, &inner_fn_2] () { + ctx.canonical_ctx.scope (trait.get_node_id (), trait.get_identifier (), + std::move (inner_fn_2)); + }; + + ctx.scoped (Rib::Kind::Generics, trait.get_node_id (), inner_fn_3, trait.get_identifier () /* FIXME: Is that valid?*/); } void DefaultResolver::visit (AST::InherentImpl &impl) { - auto inner_fn = [this, &impl] () { AST::DefaultASTVisitor::visit (impl); }; - - ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn); + visit_outer_attrs (impl); + visit (impl.get_visibility ()); + visit_inner_attrs (impl); + + auto inner_fn_1 = [this, &impl] () { + for (auto &item : impl.get_impl_items ()) + visit (item); + }; + + auto inner_fn_2 = [this, &impl, &inner_fn_1] () { + maybe_insert_big_self (impl); + for (auto &generic : impl.get_generic_params ()) + visit (generic); + if (impl.has_where_clause ()) + visit (impl.get_where_clause ()); + visit_impl_type (impl.get_type ()); + + ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn_1); + }; + + auto inner_fn_3 = [this, &impl, &inner_fn_2] () { + ctx.canonical_ctx.scope_impl (impl, std::move (inner_fn_2)); + }; + + ctx.scoped (Rib::Kind::Generics, impl.get_node_id (), inner_fn_3); } void DefaultResolver::visit (AST::TraitImpl &impl) { - auto inner_fn = [this, &impl] () { AST::DefaultASTVisitor::visit (impl); }; - - ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn); + visit_outer_attrs (impl); + visit (impl.get_visibility ()); + visit_inner_attrs (impl); + + auto inner_fn_1 = [this, &impl] () { + for (auto &item : impl.get_impl_items ()) + visit (item); + }; + + auto inner_fn_2 = [this, &impl, &inner_fn_1] () { + maybe_insert_big_self (impl); + for (auto &generic : impl.get_generic_params ()) + visit (generic); + if (impl.has_where_clause ()) + visit (impl.get_where_clause ()); + visit_impl_type (impl.get_type ()); + visit (impl.get_trait_path ()); + + ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn_1); + }; + + auto inner_fn_3 = [this, &impl, &inner_fn_2] () { + ctx.canonical_ctx.scope_impl (impl, std::move (inner_fn_2)); + }; + + ctx.scoped (Rib::Kind::Generics, impl.get_node_id (), inner_fn_3); } void DefaultResolver::visit (AST::StructStruct &type) { - // do we need to scope anything here? no, right? + auto inner_fn_1 = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; - // 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_2 = [this, &type, &inner_fn_1] () { + ctx.canonical_ctx.scope (type.get_node_id (), type.get_struct_name (), + std::move (inner_fn_1)); + }; - AST::DefaultASTVisitor::visit (type); + ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (), + inner_fn_2, type.get_struct_name ()); +} + +void +DefaultResolver::visit (AST::TupleStruct &type) +{ + auto inner_fn_1 = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + + auto inner_fn_2 = [this, &type, &inner_fn_1] () { + ctx.canonical_ctx.scope (type.get_node_id (), type.get_struct_name (), + std::move (inner_fn_1)); + }; + + ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (), + inner_fn_2, type.get_struct_name ()); +} + +void +DefaultResolver::visit (AST::EnumItem &item) +{ + auto inner_fn = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; + + ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (), + inner_fn); +} + +void +DefaultResolver::visit (AST::EnumItemTuple &item) +{ + auto inner_fn = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; + + ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (), + inner_fn); +} + +void +DefaultResolver::visit (AST::EnumItemStruct &item) +{ + auto inner_fn = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; + + ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (), + inner_fn); +} + +void +DefaultResolver::visit (AST::EnumItemDiscriminant &item) +{ + auto inner_fn = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; - // FIXME: ??? + ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (), + inner_fn); } void DefaultResolver::visit (AST::Enum &type) { - // FIXME: Do we need to scope anything by default? + auto inner_fn_1 = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + + auto inner_fn_2 = [this, &type, &inner_fn_1] () { + ctx.canonical_ctx.scope (type.get_node_id (), type.get_identifier (), + std::move (inner_fn_1)); + }; + + ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (), + inner_fn_2, type.get_identifier ()); +} + +void +DefaultResolver::visit (AST::Union &type) +{ + auto inner_fn_1 = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; - auto variant_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + auto inner_fn_2 = [this, &type, &inner_fn_1] () { + ctx.canonical_ctx.scope (type.get_node_id (), type.get_identifier (), + std::move (inner_fn_1)); + }; ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (), - variant_fn, type.get_identifier ()); + inner_fn_2, type.get_identifier ()); +} + +void +DefaultResolver::visit (AST::TypeAlias &type) +{ + auto inner_fn_1 = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + + auto inner_fn_2 = [this, &type, &inner_fn_1] () { + ctx.canonical_ctx.scope (type.get_node_id (), type.get_new_type_name (), + std::move (inner_fn_1)); + }; + + ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (), + inner_fn_2, type.get_new_type_name ()); +} + +void +DefaultResolver::visit_closure_params (AST::ClosureExpr &expr) +{ + for (auto ¶m : expr.get_params ()) + visit (param); +} + +void +DefaultResolver::visit (AST::ClosureExpr &expr) +{ + auto expr_fn = [this, &expr] () { + visit_closure_params (expr); + visit (expr.get_definition_expr ()); + }; + + visit_outer_attrs (expr); + + ctx.scoped (Rib::Kind::Normal, expr.get_node_id (), expr_fn); } void @@ -115,7 +343,7 @@ DefaultResolver::visit (AST::ClosureExprInner &expr) if (expr.is_marked_for_strip ()) return; - AST::DefaultASTVisitor::visit (expr); + visit (static_cast<AST::ClosureExpr &> (expr)); } void @@ -124,7 +352,8 @@ DefaultResolver::visit (AST::ClosureExprInnerTyped &expr) if (expr.is_marked_for_strip ()) return; - AST::DefaultASTVisitor::visit (expr); + visit (static_cast<AST::ClosureExpr &> (expr)); + visit (expr.get_return_type ()); } void @@ -139,23 +368,78 @@ DefaultResolver::visit (AST::MatchExpr &expr) void DefaultResolver::visit (AST::ConstantItem &item) { - if (item.has_expr ()) - { - auto expr_vis - = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; + auto expr_vis_1 = [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); - } + auto expr_vis_2 = [this, &item, &expr_vis_1] () { + ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (), + std::move (expr_vis_1)); + }; + + // FIXME: Why do we need a Rib here? + ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis_2); } void DefaultResolver::visit (AST::StaticItem &item) { - auto expr_vis = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; + auto expr_vis_1 = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; + + auto expr_vis_2 = [this, &item, &expr_vis_1] () { + ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (), + std::move (expr_vis_1)); + }; // FIXME: Why do we need a Rib here? - ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis); + ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis_2); +} + +void +DefaultResolver::visit (AST::TypeParam ¶m) +{ + auto expr_vis = [this, ¶m] () { AST::DefaultASTVisitor::visit (param); }; + + ctx.scoped (Rib::Kind::ForwardTypeParamBan, param.get_node_id (), expr_vis); +} + +void +DefaultResolver::visit_extern_crate (AST::ExternCrate &extern_crate, + AST::Crate &crate, CrateNum num) +{ + visit (crate); +} + +void +DefaultResolver::visit (AST::ExternCrate &crate) +{ + auto &mappings = Analysis::Mappings::get (); + 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; + + AST::Crate &referenced_crate = mappings.get_ast_crate (num); + + auto sub_visitor_1 + = [&, this] () { visit_extern_crate (crate, referenced_crate, num); }; + + auto sub_visitor_2 = [&] () { + ctx.canonical_ctx.scope_crate (referenced_crate.get_node_id (), + crate.get_referenced_crate (), + std::move (sub_visitor_1)); + }; + + if (crate.has_as_clause ()) + ctx.scoped (Rib::Kind::Module, referenced_crate.get_node_id (), + sub_visitor_2, crate.get_as_clause ()); + else + ctx.scoped (Rib::Kind::Module, referenced_crate.get_node_id (), + sub_visitor_2, crate.get_referenced_crate ()); } } // namespace Resolver2_0 diff --git a/gcc/rust/resolve/rust-default-resolver.h b/gcc/rust/resolve/rust-default-resolver.h index 9fcddd1..cf0df68 100644 --- a/gcc/rust/resolve/rust-default-resolver.h +++ b/gcc/rust/resolve/rust-default-resolver.h @@ -39,6 +39,7 @@ public: virtual ~DefaultResolver () {} + void visit (AST::Crate &) override; // 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 @@ -46,15 +47,35 @@ public: void visit (AST::Module &) override; void visit (AST::Function &) override; void visit (AST::ForLoopExpr &expr) override; + virtual void visit_if_let_patterns (AST::IfLetExpr &expr); + void visit (AST::IfLetExpr &expr) override; + void visit (AST::IfLetExprConseqElse &expr) override; void visit (AST::Trait &) override; + // used to handle Self insertion in TopLevel + virtual void maybe_insert_big_self (AST::Impl &) {} + virtual void visit_impl_type (AST::Type &type) { visit (type); } void visit (AST::InherentImpl &) override; void visit (AST::TraitImpl &) override; + void visit (AST::TypeParam &) override; + + virtual void visit_extern_crate (AST::ExternCrate &, AST::Crate &, CrateNum); + void visit (AST::ExternCrate &) override; + // type dec nodes, which visit their fields or variants by default void visit (AST::StructStruct &) override; + void visit (AST::TupleStruct &) override; + void visit (AST::EnumItem &) override; + void visit (AST::EnumItemTuple &) override; + void visit (AST::EnumItemStruct &) override; + void visit (AST::EnumItemDiscriminant &) override; void visit (AST::Enum &) override; + void visit (AST::Union &) override; + void visit (AST::TypeAlias &) override; // Visitors that visit their expression node(s) + virtual void visit_closure_params (AST::ClosureExpr &); + virtual void visit (AST::ClosureExpr &); void visit (AST::ClosureExprInner &) override; void visit (AST::ClosureExprInnerTyped &) override; void visit (AST::MatchExpr &) override; 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 5533048..4fd1dd2 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc @@ -17,16 +17,21 @@ // <http://www.gnu.org/licenses/>. #include "rust-early-name-resolver-2.0.h" -#include "rust-ast-full.h" +#include "optional.h" +#include "options.h" #include "rust-diagnostics.h" +#include "rust-hir-map.h" +#include "rust-item.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), dirty (false) +Early::Early (NameResolutionContext &ctx) + : DefaultResolver (ctx), toplevel (TopLevel (ctx)), dirty (false) {} void @@ -51,35 +56,31 @@ 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); // We start with resolving the list of imports that `TopLevel` has built for // us - for (auto &&import : toplevel.get_imports_to_resolve ()) - build_import_mapping (std::move (import)); - - // Once this is done, we finalize their resolution - FinalizeImports (std::move (import_mappings), toplevel, ctx).go (crate); 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); + + visit (crate); + textual_scope.pop (); } bool Early::resolve_glob_import (NodeId use_dec_id, TopLevel::ImportKind &&glob) { - auto resolved = ctx.types.resolve_path (glob.to_resolve.get_segments ()); + 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 ()); + auto result = Analysis::Mappings::get ().lookup_glob_container ( + resolved->get_node_id ()); + if (!result) return false; @@ -144,6 +145,10 @@ Early::build_import_mapping ( // 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: @@ -157,7 +162,7 @@ Early::build_import_mapping ( break; } - if (!found) + 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 ())); @@ -226,17 +231,39 @@ 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 Early::visit (AST::MacroInvocation &invoc) { - auto path = invoc.get_invoc_data ().get_path (); + auto &path = invoc.get_invoc_data ().get_path (); + + // We special case the `offset_of!()` macro if the flag is here, otherwise + // we accept whatever `offset_of!()` definition we resolved to. + auto resolve_offset_of + = flag_assume_builtin_offset_of && (path.as_string () == "offset_of"); + + 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 @@ -255,13 +282,16 @@ 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, Namespace::Macros); - // if the definition still does not have a value, then it's an error + // if the definition still does not have a value, then it's an error - unless + // we should automatically resolve offset_of!() calls if (!definition.has_value ()) { - collect_error (Error (invoc.get_locus (), ErrorCode::E0433, - "could not resolve macro invocation")); + if (!resolve_offset_of) + collect_error (Error (invoc.get_locus (), ErrorCode::E0433, + "could not resolve macro invocation %qs", + path.as_string ().c_str ())); return; } @@ -297,7 +327,7 @@ Early::visit_attributes (std::vector<AST::Attribute> &attrs) for (auto &trait : traits) { auto definition - = ctx.macros.resolve_path (trait.get ().get_segments ()); + = ctx.resolve_path (trait.get (), Namespace::Macros); if (!definition.has_value ()) { // FIXME: Change to proper error message @@ -310,10 +340,9 @@ Early::visit_attributes (std::vector<AST::Attribute> &attrs) 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 () @@ -321,7 +350,7 @@ Early::visit_attributes (std::vector<AST::Attribute> &attrs) .is_error ()) // Do not resolve builtins { auto definition - = ctx.macros.resolve_path (attr.get_path ().get_segments ()); + = ctx.resolve_path (attr.get_path (), Namespace::Macros); if (!definition.has_value ()) { // FIXME: Change to proper error message @@ -333,7 +362,8 @@ Early::visit_attributes (std::vector<AST::Attribute> &attrs) auto pm_def = mappings.lookup_attribute_proc_macro_def ( definition->get_node_id ()); - rust_assert (pm_def.has_value ()); + if (!pm_def.has_value ()) + return; mappings.insert_attribute_proc_macro_invocation (attr.get_path (), pm_def.value ()); @@ -355,5 +385,104 @@ 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 container = Analysis::Mappings::get ().lookup_glob_container ( + mapping.data.container ().get_node_id ()); + + rust_assert (container); + + GlobbingVisitor (ctx).go (container.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 a7ad0f7..960de0e 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.h @@ -34,6 +34,7 @@ class Early : public DefaultResolver { using DefaultResolver::visit; + TopLevel toplevel; bool dirty; public: @@ -59,6 +60,7 @@ public: void visit (AST::Function &) override; void visit (AST::StructStruct &) override; + void visit (AST::UseDeclaration &) override; struct ImportData { @@ -81,15 +83,15 @@ public: return ImportData (Kind::Rebind, std::move (definitions)); } - static ImportData Glob (Rib::Definition module) + static ImportData Glob (Rib::Definition container) { - return ImportData (Kind::Glob, module); + return ImportData (Kind::Glob, container); } - Rib::Definition module () const + Rib::Definition container () const { rust_assert (kind == Kind::Glob); - return glob_module; + return glob_container; } std::vector<std::pair<Rib::Definition, Namespace>> definitions () const @@ -105,8 +107,8 @@ public: : kind (kind), resolved_definitions (std::move (definitions)) {} - ImportData (Kind kind, Rib::Definition module) - : kind (kind), glob_module (module) + ImportData (Kind kind, Rib::Definition container) + : kind (kind), glob_container (container) {} // TODO: Should this be a union? @@ -115,7 +117,7 @@ public: std::vector<std::pair<Rib::Definition, Namespace>> resolved_definitions; // For Glob - Rib::Definition glob_module; + Rib::Definition glob_container; }; struct ImportPair @@ -216,7 +218,6 @@ private: std::vector<std::pair<Rib::Definition, Namespace>> resolve_path_in_all_ns (const P &path) { - const auto &segments = path.get_segments (); std::vector<std::pair<Rib::Definition, Namespace>> resolved; // Pair a definition with the namespace it was found in @@ -227,9 +228,21 @@ private: }; }; - ctx.values.resolve_path (segments).map (pair_with_ns (Namespace::Values)); - ctx.types.resolve_path (segments).map (pair_with_ns (Namespace::Types)); - ctx.macros.resolve_path (segments).map (pair_with_ns (Namespace::Macros)); + 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; } @@ -243,6 +256,13 @@ private: 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..7b365ef 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 @@ -204,7 +205,7 @@ EarlyNameResolver::visit (AST::MetaItemLitExpr &) {} void -EarlyNameResolver::visit (AST::MetaItemPathLit &) +EarlyNameResolver::visit (AST::MetaItemPathExpr &) {} 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..d3c5225 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 @@ -141,7 +142,7 @@ private: virtual void visit (AST::AttrInputLiteral &attr_input); virtual void visit (AST::AttrInputMacro &attr_input); virtual void visit (AST::MetaItemLitExpr &meta_item); - virtual void visit (AST::MetaItemPathLit &meta_item); + virtual void visit (AST::MetaItemPathExpr &meta_item); virtual void visit (AST::StructExprStruct &expr); virtual void visit (AST::StructExprFieldIdentifier &field); virtual void visit (AST::StructExprStructBase &expr); @@ -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 index 71916ae..317acb0 100644 --- a/gcc/rust/resolve/rust-finalize-imports-2.0.cc +++ b/gcc/rust/resolve/rust-finalize-imports-2.0.cc @@ -21,19 +21,44 @@ #include "rust-hir-map.h" #include "rust-name-resolution-context.h" #include "rust-rib.h" +#include "rust-system.h" #include "rust-toplevel-name-resolver-2.0.h" namespace Rust { namespace Resolver2_0 { void -GlobbingVisitor::go (AST::Module *module) +GlobbingVisitor::go (AST::Item *container) { - for (auto &i : module->get_items ()) + switch (container->get_item_kind ()) + { + case AST::Item::Kind::Module: + visit_module_container (static_cast<AST::Module &> (*container)); + break; + case AST::Item::Kind::Enum: + visit_enum_container (static_cast<AST::Enum &> (*container)); + break; + default: + rust_unreachable (); + } +} + +void +GlobbingVisitor::visit_module_container (AST::Module &module) +{ + for (auto &i : module.get_items ()) visit (i); } void +GlobbingVisitor::visit_enum_container (AST::Enum &item) +{ + for (auto &variant : item.get_variants ()) + ctx.insert_globbed (variant->get_identifier (), variant->get_node_id (), + Namespace::Types); +} + +void GlobbingVisitor::visit (AST::Module &module) { if (module.get_visibility ().is_public ()) @@ -125,100 +150,5 @@ GlobbingVisitor::visit (AST::UseDeclaration &use) // Handle cycles ? } -void -finalize_simple_import (TopLevel &toplevel, 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 -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 -finalize_rebind_import (TopLevel &toplevel, 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: - 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 */); -} - -FinalizeImports::FinalizeImports (Early::ImportMappings &&data, - TopLevel &toplevel, - NameResolutionContext &ctx) - : DefaultResolver (ctx), data (std::move (data)), toplevel (toplevel), - ctx (ctx) -{} - -void -FinalizeImports::go (AST::Crate &crate) -{ - for (auto &item : crate.items) - item->accept_vis (*this); -} - -void -FinalizeImports::visit (AST::UseDeclaration &use) -{ - auto import_mappings = data.get (use.get_node_id ()); - - for (const auto &mapping : import_mappings) - switch (mapping.import_kind.kind) - { - case TopLevel::ImportKind::Kind::Glob: - finalize_glob_import (ctx, mapping); - break; - case TopLevel::ImportKind::Kind::Simple: - finalize_simple_import (toplevel, mapping); - break; - case TopLevel::ImportKind::Kind::Rebind: - finalize_rebind_import (toplevel, mapping); - break; - } -} - } // 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 index 0fba5a5..4ae1d6d 100644 --- a/gcc/rust/resolve/rust-finalize-imports-2.0.h +++ b/gcc/rust/resolve/rust-finalize-imports-2.0.h @@ -18,6 +18,7 @@ #include "rust-ast.h" #include "rust-expr.h" +#include "rust-item.h" #include "rust-name-resolution-context.h" #include "rust-toplevel-name-resolver-2.0.h" #include "rust-early-name-resolver-2.0.h" @@ -32,7 +33,11 @@ class GlobbingVisitor : public AST::DefaultASTVisitor public: GlobbingVisitor (NameResolutionContext &ctx) : ctx (ctx) {} - void go (AST::Module *module); + void go (AST::Item *container); + + void visit_module_container (AST::Module &module); + void visit_enum_container (AST::Enum &item); + void visit (AST::Module &module) override; void visit (AST::MacroRulesDefinition ¯o) override; void visit (AST::Function &function) override; @@ -49,62 +54,5 @@ private: NameResolutionContext &ctx; }; -// TODO: Fix documentation -// How do we do that? -// -// We want to resolve in the EarlyNameResolver, but we want to declare in the -// TopLevel Should the TopLevel declare stubs? How does rustc do it? How to do -// that for globbing? Should we do globbing afterwards once we've declared all -// the Uses*? -// -// Basically, for each use declare it in a separate map - in the -// EarlyNameResolver resolve and fix the ForeverStack? Emptying the maps each -// time? -// -// e.g. TopLevel builds a std::vector<NodeId, SimplePath> use_trees_to_resolve; -// Early goes through and resolves the SimplePath, then replaces the NodeId with -// the resolved one? Do we even need to do that? -// -// rustc just creates an empty definition for the use tree. -// -// What about globbing? std::vector<GlobbulesPath> globules; -// Early goes through and visits the module's path and calls the -// GlobbingVisitor? -// -// the file `imports.rs` goes through and *finalizes* imports. So we can -// probably add a FinalizeImport pass after the TopLevel and the Early. -// - TopLevel takes care of declaring these use trees -// - Early takes care of resolving them to definition points -// - Finalize takes care of mapping the use's definition point to the actual -// definition point -// - We need to work more on that last bit to know exactly what is being -// inserted, but probably it's going to mutate the ForeverStack - is that okay? -// - Oh actually maybe no! -// - TopLevel creates a map of UseTrees with paths to resolve. This should -// probably be an ImportKind enum or whatever -// - Early resolves them, creates a map of SimplePath with the associated -// definition: Map<ImportKind, ImportData> -// - Finalizes visits all UseTrees and inserts the Definitions found for -// each ImportKind - easy! -// - yay! - -class FinalizeImports : DefaultResolver -{ -public: - FinalizeImports (Early::ImportMappings &&data, TopLevel &toplevel, - NameResolutionContext &ctx); - - void go (AST::Crate &crate); - -private: - using AST::DefaultASTVisitor::visit; - - void visit (AST::UseDeclaration &) override; - - Early::ImportMappings data; - TopLevel &toplevel; - 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 8c5e207..75dd873 100644 --- a/gcc/rust/resolve/rust-forever-stack.h +++ b/gcc/rust/resolve/rust-forever-stack.h @@ -392,17 +392,180 @@ 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; +}; + +enum class ResolutionMode +{ + Normal, + FromRoot, + FromExtern, // extern prelude +}; + 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 +579,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 +600,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 * @@ -500,6 +666,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` @@ -510,16 +678,22 @@ public: * current map, an empty one otherwise. */ template <typename S> - tl::optional<Rib::Definition> resolve_path (const std::vector<S> &segments); - - // FIXME: Documentation - tl::optional<Resolver::CanonicalPath> to_canonical_path (NodeId id) const; + tl::optional<Rib::Definition> resolve_path ( + const std::vector<S> &segments, ResolutionMode mode, + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors); // 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: /** @@ -556,6 +730,7 @@ private: {} bool is_root () const; + bool is_prelude () const; bool is_leaf () const; void insert_child (Link link, Node child); @@ -568,6 +743,9 @@ private: tl::optional<Node &> parent; // `None` only if the node is a root }; + // private overload which allows specifying a starting point + tl::optional<Rib::Definition> get (Node &start, const Identifier &name); + /* Should we keep going upon seeing a Rib? */ enum class KeepGoing { @@ -591,13 +769,25 @@ private: 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` */ @@ -607,13 +797,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 @@ -635,6 +834,25 @@ private: 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 5a5a7c7..1ed87b3 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 @@ -171,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 () @@ -263,20 +291,26 @@ ForeverStack<N>::update_cursor (Node &new_cursor) template <Namespace N> tl::optional<Rib::Definition> -ForeverStack<N>::get (const Identifier &name) +ForeverStack<N>::get (Node &start, const Identifier &name) { tl::optional<Rib::Definition> resolved_definition = tl::nullopt; // TODO: Can we improve the API? have `reverse_iter` return an optional? - reverse_iter ([&resolved_definition, &name] (Node ¤t) { + reverse_iter (start, [&resolved_definition, &name] (Node ¤t) { + // we can't reference associated types/functions like this + if (current.rib.kind == Rib::Kind::TraitOrImpl) + return KeepGoing::Yes; + auto candidate = current.rib.get (name.as_string ()); 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; @@ -288,6 +322,27 @@ ForeverStack<N>::get (const Identifier &name) return resolved_definition; } +template <Namespace N> +tl::optional<Rib::Definition> +ForeverStack<N>::get (const Identifier &name) +{ + return get (cursor (), name); +} + +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) @@ -354,12 +409,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; @@ -373,52 +429,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; } @@ -436,72 +501,300 @@ 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; - - if (link.path.map_or ( - [&str] (Identifier path) { - auto &path_str = path.as_string (); - return str == path_str; - }, - false)) + if (is_start (iterator, segments) + && current_node->rib.kind == Rib::Kind::TraitOrImpl) + { + // we can't reference associated types/functions like this + current_node = ¤t_node->parent.value (); + continue; + } + + // 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 (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, ResolutionMode mode, + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors) { - // TODO: What to do if segments.empty() ? + rust_assert (!segments.empty ()); + + std::reference_wrapper<Node> starting_point = cursor (); + switch (mode) + { + case ResolutionMode::Normal: + break; // default + case ResolutionMode::FromRoot: + starting_point = root; + break; + case ResolutionMode::FromExtern: + starting_point = extern_prelude; + break; + default: + rust_unreachable (); + } // if there's only one segment, we just use `get` if (segments.size () == 1) - return get (segments.back ().as_string ()); + { + auto &outer_seg = segments.front (); + if (auto lang_item = unwrap_segment_get_lang_item (outer_seg)) + { + NodeId seg_id = Analysis::Mappings::get ().get_lang_item_node ( + lang_item.value ()); + + insert_segment_resolution (outer_seg, seg_id); + // TODO: does NonShadowable matter? + return Rib::Definition::NonShadowable (seg_id); + } + + auto &seg = unwrap_type_segment (outer_seg); + + tl::optional<Rib::Definition> res + = get (starting_point.get (), seg.as_string ()); - auto starting_point = cursor (); + if (!res) + res = get_lang_prelude (seg.as_string ()); + + if (N == Namespace::Types && !res) + { + if (seg.is_crate_path_seg ()) + { + insert_segment_resolution (outer_seg, root.id); + // TODO: does NonShadowable matter? + return Rib::Definition::NonShadowable (root.id); + } + else if (seg.is_lower_self_seg ()) + { + NodeId id = find_closest_module (starting_point.get ()).id; + insert_segment_resolution (outer_seg, id); + // TODO: does NonShadowable matter? + return Rib::Definition::NonShadowable (id); + } + else if (seg.is_super_path_seg ()) + { + Node &closest_module + = find_closest_module (starting_point.get ()); + if (closest_module.is_root ()) + { + rust_error_at (seg.get_locus (), ErrorCode::E0433, + "too many leading %<super%> keywords"); + return tl::nullopt; + } + + NodeId id + = find_closest_module (closest_module.parent.value ()).id; + insert_segment_resolution (outer_seg, id); + // TODO: does NonShadowable matter? + return Rib::Definition::NonShadowable (id); + } + else + { + // HACK: check for a module after we check the language prelude + for (auto &kv : + find_closest_module (starting_point.get ()).children) + { + auto &link = kv.first; + + if (link.path.map_or ( + [&seg] (Identifier path) { + auto &path_str = path.as_string (); + return path_str == seg.as_string (); + }, + false)) + { + insert_segment_resolution (outer_seg, kv.second.id); + return Rib::Definition::NonShadowable (kv.second.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 ()); + if (res && !res->is_ambiguous ()) + insert_segment_resolution (outer_seg, res->get_node_id ()); + return res; + } + + return 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 (N == Namespace::Types && !res) + { + // HACK: check for a module after we check the language prelude + for (auto &kv : final_node.children) + { + auto &link = kv.first; + + if (link.path.map_or ( + [&seg_name] (Identifier path) { + auto &path_str = path.as_string (); + return path_str == seg_name; + }, + false)) + { + insert_segment_resolution (segments.back (), kv.second.id); + return Rib::Definition::NonShadowable (kv.second.id); + } + } + } + + if (res && !res->is_ambiguous ()) + insert_segment_resolution (segments.back (), res->get_node_id ()); + + return res; }); } @@ -567,71 +860,34 @@ ForeverStack<N>::dfs (const ForeverStack<N>::Node &starting_point, } template <Namespace N> -tl::optional<Resolver::CanonicalPath> -ForeverStack<N>::to_canonical_path (NodeId id) const +tl::optional<Rib &> +ForeverStack<N>::dfs_rib (ForeverStack<N>::Node &starting_point, NodeId to_find) { - // 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] (ConstDfsResult tuple) { - auto containing_node = tuple.first; - auto name = tuple.second; - - auto segments = std::vector<Resolver::CanonicalPath> (); - - reverse_iter (containing_node, [&segments] (const Node ¤t) { - if (current.is_root ()) - return KeepGoing::No; - - auto children = current.parent.value ().children; - const Link *outer_link = nullptr; - - for (auto &kv : children) - { - auto &link = kv.first; - auto &child = kv.second; - - if (link.id == child.id) - { - outer_link = &link; - break; - } - } - - rust_assert (outer_link); - - outer_link->path.map ([&segments, outer_link] (Identifier path) { - segments.emplace (segments.begin (), - Resolver::CanonicalPath::new_seg (outer_link->id, - path.as_string ())); - }); - - return KeepGoing::Yes; - }); - - auto path = Resolver::CanonicalPath::create_empty (); - for (const auto &segment : segments) - path = path.append (segment); - - // Finally, append the name - path = path.append (Resolver::CanonicalPath::new_seg (id, name)); - - return path; + return dfs_node (starting_point, to_find).map ([] (Node &x) -> Rib & { + return x.rib; }); } template <Namespace N> -tl::optional<Rib &> -ForeverStack<N>::dfs_rib (ForeverStack<N>::Node &starting_point, NodeId to_find) +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.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; @@ -641,16 +897,16 @@ ForeverStack<N>::dfs_rib (ForeverStack<N>::Node &starting_point, NodeId to_find) } template <Namespace N> -tl::optional<const Rib &> -ForeverStack<N>::dfs_rib (const ForeverStack<N>::Node &starting_point, - NodeId to_find) const +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; @@ -677,15 +933,19 @@ 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"; @@ -696,7 +956,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, ' '); @@ -728,7 +988,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; @@ -737,6 +997,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..79a06c3 --- /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 (diagnostics::text_sink &text_output, + const diagnostics::diagnostic_info *diagnostic, + enum diagnostics::kind diag_kind) +{ + gcc_assert (diag_kind == diagnostics::kind::ice_nobt); + diagnostics::default_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..5120176 --- /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 (diagnostics::text_sink &text_output, + const diagnostics::diagnostic_info *diagnostic, + enum diagnostics::kind 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 43f33df..e39ca15 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc @@ -18,6 +18,8 @@ #include "optional.h" #include "rust-ast-full.h" +#include "rust-diagnostics.h" +#include "rust-expr.h" #include "rust-hir-map.h" #include "rust-late-name-resolver-2.0.h" #include "rust-default-resolver.h" @@ -26,11 +28,15 @@ #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 { -Late::Late (NameResolutionContext &ctx) : DefaultResolver (ctx) {} +Late::Late (NameResolutionContext &ctx) + : DefaultResolver (ctx), funny_error (false), block_big_self (false) +{} static NodeId next_node_id () @@ -88,19 +94,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); } @@ -109,8 +117,7 @@ Late::go (AST::Crate &crate) { setup_builtin_types (); - for (auto &item : crate.items) - item->accept_vis (*this); + visit (crate); } void @@ -124,10 +131,69 @@ Late::new_label (Identifier name, NodeId id) } void +Late::visit (AST::ForLoopExpr &expr) +{ + visit_outer_attrs (expr); + + ctx.bindings.enter (BindingSource::For); + + visit (expr.get_pattern ()); + + ctx.bindings.exit (); + + visit (expr.get_iterator_expr ()); + + if (expr.has_loop_label ()) + visit (expr.get_loop_label ()); + + visit (expr.get_loop_block ()); +} + +void +Late::visit_if_let_patterns (AST::IfLetExpr &expr) +{ + ctx.bindings.enter (BindingSource::IfLet); + + DefaultResolver::visit_if_let_patterns (expr); + + ctx.bindings.exit (); +} + +void +Late::visit (AST::MatchArm &arm) +{ + visit_outer_attrs (arm); + + ctx.bindings.enter (BindingSource::Match); + + for (auto &pattern : arm.get_patterns ()) + visit (pattern); + + ctx.bindings.exit (); + + if (arm.has_match_arm_guard ()) + visit (arm.get_guard_expr ()); +} + +void Late::visit (AST::LetStmt &let) { - // 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? @@ -147,15 +213,184 @@ Late::visit (AST::LetStmt &let) } void -Late::visit (AST::IdentifierPattern &identifier) +Late::visit (AST::WhileLetLoopExpr &while_let) +{ + DefaultASTVisitor::visit_outer_attrs (while_let); + + if (while_let.has_loop_label ()) + visit (while_let.get_loop_label ()); + + // visit expression before pattern + // this makes variable shadowing work properly + visit (while_let.get_scrutinee_expr ()); + + ctx.bindings.enter (BindingSource::WhileLet); + + for (auto &pattern : while_let.get_patterns ()) + visit (pattern); + + ctx.bindings.exit (); + + visit (while_let.get_loop_block ()); +} + +static void +visit_identifier_as_pattern (NameResolutionContext &ctx, + const Identifier &ident, location_t locus, + NodeId node_id, bool is_ref, bool is_mut) { // do we insert in labels or in values // but values does not allow shadowing... since functions cannot shadow // do we insert functions in labels as well? - // We do want to ignore duplicated data because some situations rely on it. - std::ignore = ctx.values.insert_shadowable (identifier.get_ident (), - identifier.get_node_id ()); + if (ctx.bindings.peek ().is_and_bound (ident)) + { + if (ctx.bindings.peek ().get_source () == BindingSource::Param) + rust_error_at ( + locus, ErrorCode::E0415, + "identifier %qs is bound more than once in the same parameter list", + ident.as_string ().c_str ()); + else + rust_error_at ( + locus, ErrorCode::E0416, + "identifier %qs is bound more than once in the same pattern", + ident.as_string ().c_str ()); + return; + } + + ctx.bindings.peek ().insert_ident (ident.as_string (), locus, is_ref, is_mut); + + if (ctx.bindings.peek ().is_or_bound (ident)) + { + auto res = ctx.values.get (ident); + rust_assert (res.has_value () && !res->is_ambiguous ()); + ctx.map_usage (Usage (node_id), Definition (res->get_node_id ())); + } + else + { + // We do want to ignore duplicated data because some situations rely on + // it. + std::ignore = ctx.values.insert_shadowable (ident, node_id); + } +} + +void +Late::visit (AST::IdentifierPattern &identifier) +{ + DefaultResolver::visit (identifier); + + visit_identifier_as_pattern (ctx, identifier.get_ident (), + identifier.get_locus (), + identifier.get_node_id (), + identifier.get_is_ref (), + identifier.get_is_mut ()); +} + +void +Late::visit (AST::AltPattern &pattern) +{ + ctx.bindings.peek ().push (Binding::Kind::Or); + for (auto &alt : pattern.get_alts ()) + { + ctx.bindings.peek ().push (Binding::Kind::Product); + visit (alt); + ctx.bindings.peek ().merge (); + } + ctx.bindings.peek ().merge (); +} + +void +Late::visit_function_params (AST::Function &function) +{ + ctx.bindings.enter (BindingSource::Param); + + for (auto ¶m : function.get_function_params ()) + visit (param); + + ctx.bindings.exit (); +} + +void +Late::visit (AST::StructPatternFieldIdent &field) +{ + visit_identifier_as_pattern (ctx, field.get_identifier (), field.get_locus (), + field.get_node_id (), field.is_ref (), + field.is_mut ()); +} + +void +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 @@ -164,7 +399,6 @@ Late::visit (AST::IdentifierExpr &expr) // TODO: same thing as visit(PathInExpression) here? tl::optional<Rib::Definition> resolved = tl::nullopt; - if (auto value = ctx.values.get (expr.get_ident ())) { resolved = value; @@ -173,49 +407,96 @@ Late::visit (AST::IdentifierExpr &expr) { resolved = type; } + else if (funny_error) + { + diagnostics::text_finalizer (global_dc) + = Resolver::funny_ice_text_finalizer; + emit_diagnostic (diagnostics::kind::ice_nobt, expr.get_locus (), -1, + "are you trying to break %s? how dare you?", + expr.as_string ().c_str ()); + } 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>`? - rust_debug ("[ARTHUR]: %s", expr.as_simple_path ().as_string ().c_str ()); + DefaultResolver::visit (expr); - tl::optional<Rib::Definition> resolved = tl::nullopt; - - if (auto value = ctx.values.resolve_path (expr.get_segments ())) - { - resolved = value; - } - else if (auto type = ctx.types.resolve_path (expr.get_segments ())) + if (expr.is_lang_item ()) { - resolved = type; + ctx.map_usage (Usage (expr.get_node_id ()), + Definition (Analysis::Mappings::get ().get_lang_item_node ( + expr.get_lang_item ()))); + return; } - else + + auto resolved = ctx.resolve_path (expr, Namespace::Values, Namespace::Types); + + if (!resolved) { - rust_error_at (expr.get_locus (), - "could not resolve path expression: %qs", - expr.as_simple_path ().as_string ().c_str ()); + 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; } @@ -225,11 +506,22 @@ Late::visit (AST::PathInExpression &expr) expr.as_string ().c_str ()); return; } + ctx.map_usage (Usage (expr.get_node_id ()), Definition (resolved->get_node_id ())); } void +Late::visit_impl_type (AST::Type &type) +{ + // TODO: does this have to handle reentrancy? + rust_assert (!block_big_self); + block_big_self = true; + visit (type); + block_big_self = false; +} + +void Late::visit (AST::TypePath &type) { // should we add type path resolution in `ForeverStack` directly? Since it's @@ -237,42 +529,161 @@ Late::visit (AST::TypePath &type) // maybe we can overload `resolve_path<Namespace::Types>` to only do // typepath-like path resolution? that sounds good - auto str = type.get_segments ().back ()->get_ident_segment ().as_string (); - auto values = ctx.types.peek ().get_values (); + DefaultResolver::visit (type); - if (auto resolved = ctx.types.get (str)) - ctx.map_usage (Usage (type.get_node_id ()), - Definition (resolved->get_node_id ())); - else - rust_unreachable (); + // prevent "impl Self {}" and similar + if (type.get_segments ().size () == 1 + && !type.get_segments ().front ()->is_lang_item () + && type.get_segments ().front ()->is_big_self_seg () && block_big_self) + { + rust_error_at (type.get_locus (), + "%<Self%> is not valid in the self type of an impl block"); + return; + } + + // this *should* mostly work + // TODO: make sure typepath-like path resolution (?) is working + auto resolved = ctx.resolve_path (type, Namespace::Types); + + if (!resolved.has_value ()) + { + if (!ctx.lookup (type.get_segments ().front ()->get_node_id ())) + rust_error_at (type.get_locus (), ErrorCode::E0412, + "could not resolve type path %qs", + type.make_debug_string ().c_str ()); + return; + } + + if (resolved->is_ambiguous ()) + { + rust_error_at (type.get_locus (), ErrorCode::E0659, "%qs is ambiguous", + type.make_debug_string ().c_str ()); + return; + } + + if (ctx.types.forward_declared (resolved->get_node_id (), + type.get_node_id ())) + { + rust_error_at (type.get_locus (), ErrorCode::E0128, + "type parameters with a default cannot use forward " + "declared identifiers"); + } + + ctx.map_usage (Usage (type.get_node_id ()), + Definition (resolved->get_node_id ())); +} + +void +Late::visit (AST::Visibility &vis) +{ + if (!vis.has_path ()) + return; + + AST::SimplePath &path = vis.get_path (); + + rust_assert (path.get_segments ().size ()); + auto &first_seg = path.get_segments ()[0]; + + auto mode = ResolutionMode::Normal; + + if (path.has_opening_scope_resolution ()) + { + if (get_rust_edition () == Edition::E2015) + mode = ResolutionMode::FromRoot; + else + mode = ResolutionMode::FromExtern; + } + else if (!first_seg.is_crate_path_seg () && !first_seg.is_super_path_seg () + && !first_seg.is_lower_self_seg ()) + { + if (get_rust_edition () == Edition::E2015) + { + mode = ResolutionMode::FromRoot; + } + else + { + rust_error_at (path.get_locus (), + "relative paths are not supported in visibilities in " + "2018 edition or later"); + return; + } + } + + auto res = ctx.resolve_path (path.get_segments (), mode, Namespace::Types); + + if (!res.has_value ()) + { + rust_error_at (path.get_locus (), ErrorCode::E0433, + "could not resolve path %qs", path.as_string ().c_str ()); + return; + } + + // TODO: is this possible? + if (res->is_ambiguous ()) + { + rust_error_at (path.get_locus (), ErrorCode::E0659, "%qs is ambiguous", + path.as_string ().c_str ()); + return; + } + + ctx.map_usage (Usage (path.get_node_id ()), Definition (res->get_node_id ())); +} + +void +Late::visit (AST::Trait &trait) +{ + // kind of weird how this is done + // 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) +Late::visit (AST::StructExprStruct &s) { - auto s_vis = [this, &s] () { AST::DefaultASTVisitor::visit (s); }; - ctx.scoped (Rib::Kind::Item, s.get_node_id (), s_vis); + 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 ())); - - DefaultResolver::visit (s); } // needed because Late::visit (AST::GenericArg &) is non-virtual @@ -307,5 +718,28 @@ Late::visit (AST::GenericArg &arg) DefaultResolver::visit (arg); } +void +Late::visit_closure_params (AST::ClosureExpr &closure) +{ + ctx.bindings.enter (BindingSource::Param); + + DefaultResolver::visit_closure_params (closure); + + ctx.bindings.exit (); +} + +void +Late::visit (AST::ClosureExpr &expr) +{ + // add captures + auto vals = ctx.values.peek ().get_values (); + for (auto &val : vals) + { + ctx.mappings.add_capture (expr.get_node_id (), val.second.get_node_id ()); + } + + DefaultResolver::visit (expr); +} + } // namespace Resolver2_0 } // namespace Rust 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 7e33c96..95540e3 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,25 +37,51 @@ 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; + void visit (AST::WhileLetLoopExpr &) 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_if_let_patterns (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_impl_type (AST::Type &) override; void visit (AST::TypePath &) override; + void visit (AST::Visibility &) 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_closure_params (AST::ClosureExpr &) override; + void visit (AST::ClosureExpr &) 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; + + /* used to prevent "impl Self {}", "impl (Self, i32) {}", etc */ + bool block_big_self; }; // 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 9bfaa09..1b84f1d 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.cc +++ b/gcc/rust/resolve/rust-name-resolution-context.cc @@ -23,8 +23,169 @@ 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.idents.find (ident.as_string ()) != bind.idents.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 (std::string ident, location_t locus, bool is_ref, + bool is_mut) +{ + bindings.back ().idents.emplace ( + std::move (ident), std::make_pair (locus, IdentifierMode (is_ref, is_mut))); +} + +void +BindingLayer::merge () +{ + auto last_binding = std::move (bindings.back ()); + bindings.pop_back (); + + if (bindings.back ().has_expected_bindings) + { + for (auto &value : bindings.back ().idents) + { + auto ident = value.first; + if (last_binding.idents.find (ident) == last_binding.idents.end ()) + { + location_t locus = value.second.first; + rust_error_at (locus, ErrorCode::E0408, + "variable %qs is not bound in all patterns", + ident.c_str ()); + } + } + } + + for (auto &value : last_binding.idents) + { + auto res = bindings.back ().idents.emplace (value); + if (res.second) + { + if (bindings.back ().has_expected_bindings) + { + auto &ident = value.first; + location_t locus = value.second.first; + rust_error_at (locus, ErrorCode::E0408, + "variable %qs is not bound in all patterns", + ident.c_str ()); + } + } + else + { + auto this_mode = value.second.second; + auto other_mode = res.first->second.second; + if (this_mode != other_mode) + { + auto &ident = value.first; + location_t locus = value.second.first; + rust_error_at (locus, ErrorCode::E0409, + "variable %qs is bound inconsistently across " + "pattern alternatives", + ident.c_str ()); + } + } + } + + if (bindings.back ().kind == Binding::Kind::Or) + bindings.back ().has_expected_bindings = true; +} + +BindingSource +BindingLayer::get_source () const +{ + return source; +} + +Resolver::CanonicalPath +CanonicalPathRecordCrateRoot::as_path (const NameResolutionContext &) +{ + auto ret = Resolver::CanonicalPath::new_seg (node_id, seg); + ret.set_crate_num (crate_num); + return ret; +} + +Resolver::CanonicalPath +CanonicalPathRecordNormal::as_path (const NameResolutionContext &ctx) +{ + auto parent_path = get_parent ().as_path (ctx); + return parent_path.append (Resolver::CanonicalPath::new_seg (node_id, seg)); +} + +Resolver::CanonicalPath +CanonicalPathRecordLookup::as_path (const NameResolutionContext &ctx) +{ + if (!cache) + { + auto res = ctx.lookup (lookup_id).and_then ( + [&ctx] (NodeId id) { return ctx.canonical_ctx.get_record_opt (id); }); + + if (!res) + { + // HACK: use a dummy value + // this should bring us roughly to parity with nr1.0 + // since nr1.0 doesn't seem to handle canonical paths for generics + // quite right anyways + return Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, "XXX"); + } + + cache = res.value (); + } + return cache->as_path (ctx); +} + +Resolver::CanonicalPath +CanonicalPathRecordImpl::as_path (const NameResolutionContext &ctx) +{ + auto parent_path = get_parent ().as_path (ctx); + return parent_path.append ( + Resolver::CanonicalPath::inherent_impl_seg (impl_id, + type_record.as_path (ctx))); +} + +Resolver::CanonicalPath +CanonicalPathRecordTraitImpl::as_path (const NameResolutionContext &ctx) +{ + auto parent_path = get_parent ().as_path (ctx); + return parent_path.append ( + Resolver::CanonicalPath::trait_impl_projection_seg ( + impl_id, trait_path_record.as_path (ctx), type_record.as_path (ctx))); +} + NameResolutionContext::NameResolutionContext () - : mappings (Analysis::Mappings::get ()) + : mappings (Analysis::Mappings::get ()), canonical_ctx (*this) {} tl::expected<NodeId, DuplicateNameError> @@ -46,6 +207,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) { @@ -103,13 +270,14 @@ NameResolutionContext::lookup (NodeId usage) const } 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 (); @@ -121,17 +289,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 cd6fa93..558b3ca 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.h +++ b/gcc/rust/resolve/rust-name-resolution-context.h @@ -23,6 +23,8 @@ #include "rust-forever-stack.h" #include "rust-hir-map.h" #include "rust-rib.h" +#include "rust-stacked-contexts.h" +#include "rust-item.h" namespace Rust { namespace Resolver2_0 { @@ -156,6 +158,326 @@ public: NodeId id; }; +struct IdentifierMode +{ + bool is_ref; + bool is_mut; + + IdentifierMode (bool is_ref, bool is_mut) : is_ref (is_ref), is_mut (is_mut) + {} + + bool operator== (const IdentifierMode &other) + { + return other.is_ref == is_ref && other.is_mut == is_mut; + } + + bool operator!= (const IdentifierMode &other) { return !(*this == other); } +}; + +struct Binding +{ + enum class Kind + { + Product, + Or, + } kind; + + // used to check the correctness of or-bindings + bool has_expected_bindings; + + std::unordered_map<std::string, std::pair<location_t, IdentifierMode>> idents; + + Binding (Binding::Kind kind) : kind (kind), has_expected_bindings (false) {} +}; + +/** + * Used to identify the source of a binding, and emit the correct error message. + */ +enum class BindingSource +{ + Match, + Let, + IfLet, + WhileLet, + 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 (std::string ident, location_t locus, bool is_ref, + bool is_mut); + + void merge (); + + BindingSource get_source () const; +}; + +class NameResolutionContext; +/* + * Used to handle canonical paths + * Similar to ForeverStack, but namespace independent and more specialized + */ +class CanonicalPathRecord +{ +public: + virtual Resolver::CanonicalPath as_path (const NameResolutionContext &) = 0; + + virtual bool is_root () const = 0; + + virtual ~CanonicalPathRecord () = default; +}; + +class CanonicalPathRecordWithParent : public CanonicalPathRecord +{ +public: + CanonicalPathRecordWithParent (CanonicalPathRecord &parent) : parent (&parent) + {} + + CanonicalPathRecord &get_parent () { return *parent; } + + bool is_root () const override final { return false; } + +private: + CanonicalPathRecord *parent; +}; + +class CanonicalPathRecordCrateRoot : public CanonicalPathRecord +{ +public: + CanonicalPathRecordCrateRoot (NodeId node_id, std::string seg) + : node_id (node_id), seg (std::move (seg)) + { + rust_assert (Analysis::Mappings::get ().node_is_crate (node_id)); + crate_num = Analysis::Mappings::get ().lookup_crate_num (node_id).value (); + } + + Resolver::CanonicalPath as_path (const NameResolutionContext &) override; + + bool is_root () const override final { return true; } + +private: + NodeId node_id; + CrateNum crate_num; + std::string seg; +}; + +class CanonicalPathRecordNormal : public CanonicalPathRecordWithParent +{ +public: + CanonicalPathRecordNormal (CanonicalPathRecord &parent, NodeId node_id, + std::string seg) + : CanonicalPathRecordWithParent (parent), node_id (node_id), + seg (std::move (seg)) + { + rust_assert (!Analysis::Mappings::get ().node_is_crate (node_id)); + } + + Resolver::CanonicalPath as_path (const NameResolutionContext &) override; + +private: + NodeId node_id; + std::string seg; +}; + +class CanonicalPathRecordLookup : public CanonicalPathRecord +{ +public: + CanonicalPathRecordLookup (NodeId lookup_id) + : lookup_id (lookup_id), cache (nullptr) + {} + + Resolver::CanonicalPath as_path (const NameResolutionContext &) override; + + bool is_root () const override final { return true; } + +private: + NodeId lookup_id; + CanonicalPathRecord *cache; +}; + +class CanonicalPathRecordImpl : public CanonicalPathRecordWithParent +{ +public: + CanonicalPathRecordImpl (CanonicalPathRecord &parent, NodeId impl_id, + NodeId type_id) + : CanonicalPathRecordWithParent (parent), impl_id (impl_id), + type_record (type_id) + {} + + Resolver::CanonicalPath as_path (const NameResolutionContext &) override; + +private: + NodeId impl_id; + CanonicalPathRecordLookup type_record; +}; + +class CanonicalPathRecordTraitImpl : public CanonicalPathRecordWithParent +{ +public: + CanonicalPathRecordTraitImpl (CanonicalPathRecord &parent, NodeId impl_id, + NodeId type_id, NodeId trait_path_id) + : CanonicalPathRecordWithParent (parent), impl_id (impl_id), + type_record (type_id), trait_path_record (trait_path_id) + {} + + Resolver::CanonicalPath as_path (const NameResolutionContext &) override; + +private: + NodeId impl_id; + CanonicalPathRecordLookup type_record; + CanonicalPathRecordLookup trait_path_record; +}; + +class CanonicalPathCtx +{ +public: + CanonicalPathCtx (const NameResolutionContext &ctx) + : current_record (nullptr), nr_ctx (&ctx) + {} + + Resolver::CanonicalPath get_path (NodeId id) const + { + return get_record (id).as_path (*nr_ctx); + } + + CanonicalPathRecord &get_record (NodeId id) const + { + auto it = records.find (id); + rust_assert (it != records.end ()); + return *it->second; + } + + tl::optional<CanonicalPathRecord *> get_record_opt (NodeId id) const + { + auto it = records.find (id); + if (it == records.end ()) + return tl::nullopt; + else + return it->second.get (); + } + + void insert_record (NodeId id, const Identifier &ident) + { + insert_record (id, ident.as_string ()); + } + + void insert_record (NodeId id, std::string seg) + { + rust_assert (current_record != nullptr); + + auto it = records.find (id); + if (it == records.end ()) + { + auto record = new CanonicalPathRecordNormal (*current_record, id, + std::move (seg)); + bool ok + = records.emplace (id, std::unique_ptr<CanonicalPathRecord> (record)) + .second; + rust_assert (ok); + } + } + + template <typename F> void scope (NodeId id, const Identifier &ident, F &&f) + { + scope (id, ident.as_string (), std::forward<F> (f)); + } + + template <typename F> void scope (NodeId id, std::string seg, F &&f) + { + rust_assert (current_record != nullptr); + + scope_inner (id, std::forward<F> (f), [this, id, &seg] () { + return new CanonicalPathRecordNormal (*current_record, id, + std::move (seg)); + }); + } + + template <typename F> void scope_impl (AST::InherentImpl &impl, F &&f) + { + rust_assert (current_record != nullptr); + + NodeId id = impl.get_node_id (); + scope_inner (id, std::forward<F> (f), [this, id, &impl] () { + return new CanonicalPathRecordImpl (*current_record, id, + impl.get_type ().get_node_id ()); + }); + } + + template <typename F> void scope_impl (AST::TraitImpl &impl, F &&f) + { + rust_assert (current_record != nullptr); + + NodeId id = impl.get_node_id (); + scope_inner (id, std::forward<F> (f), [this, id, &impl] () { + return new CanonicalPathRecordTraitImpl ( + *current_record, id, impl.get_type ().get_node_id (), + impl.get_trait_path ().get_node_id ()); + }); + } + + template <typename F> + void scope_crate (NodeId node_id, std::string crate_name, F &&f) + { + scope_inner (node_id, std::forward<F> (f), [node_id, &crate_name] () { + return new CanonicalPathRecordCrateRoot (node_id, std::move (crate_name)); + }); + } + +private: + template <typename FCreate, typename FCallback> + void scope_inner (NodeId id, FCallback &&f_callback, FCreate &&f_create) + { + auto it = records.find (id); + if (it == records.end ()) + { + CanonicalPathRecord *record = std::forward<FCreate> (f_create) (); + it = records.emplace (id, std::unique_ptr<CanonicalPathRecord> (record)) + .first; + } + + rust_assert (it->second->is_root () + || &static_cast<CanonicalPathRecordWithParent &> (*it->second) + .get_parent () + == current_record); + + CanonicalPathRecord *stash = it->second.get (); + std::swap (stash, current_record); + + std::forward<FCallback> (f_callback) (); + + std::swap (stash, current_record); + } + + std::unordered_map<NodeId, std::unique_ptr<CanonicalPathRecord>> records; + CanonicalPathRecord *current_record; + + const NameResolutionContext *nr_ctx; +}; + // Now our resolver, which keeps track of all the `ForeverStack`s we could want class NameResolutionContext { @@ -172,6 +494,9 @@ 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); @@ -185,8 +510,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 @@ -196,9 +521,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 = {}); @@ -208,6 +534,9 @@ public: ForeverStack<Namespace::Labels> labels; Analysis::Mappings &mappings; + StackedContexts<BindingLayer> bindings; + + CanonicalPathCtx canonical_ctx; // TODO: Rename // TODO: Use newtype pattern for Usage and Definition @@ -215,6 +544,138 @@ public: tl::optional<NodeId> lookup (NodeId usage) const; + Resolver::CanonicalPath to_canonical_path (NodeId id) const + { + return canonical_ctx.get_path (id); + } + + template <typename S> + tl::optional<Rib::Definition> + resolve_path (const std::vector<S> &segments, ResolutionMode mode, + 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, mode, insert_segment_resolution, + collect_errors); + case Namespace::Types: + return types.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); + case Namespace::Macros: + return macros.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); + case Namespace::Labels: + return labels.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); + default: + rust_unreachable (); + } + } + + template <typename S, typename... Args> + tl::optional<Rib::Definition> + resolve_path (const std::vector<S> &segments, ResolutionMode mode, + 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, mode, 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 S, typename... Args> + tl::optional<Rib::Definition> + resolve_path (const std::vector<S> &path_segments, + bool has_opening_scope_resolution, + tl::optional<std::vector<Error> &> collect_errors, + Namespace ns_first, Args... ns_args) + { + auto mode = ResolutionMode::Normal; + if (has_opening_scope_resolution) + { + if (get_rust_edition () == Edition::E2015) + mode = ResolutionMode::FromRoot; + else + mode = ResolutionMode::FromExtern; + } + return resolve_path (path_segments, mode, collect_errors, ns_first, + ns_args...); + } + + template <typename S, typename... Args> + tl::optional<Rib::Definition> + resolve_path (const std::vector<S> &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...); + } + + template <typename S, typename... Args> + tl::optional<Rib::Definition> + resolve_path (const std::vector<S> &path_segments, ResolutionMode mode, + Namespace ns_first, Args... ns_args) + { + return resolve_path (path_segments, mode, tl::nullopt, ns_first, + ns_args...); + } + + template <typename... Args> + tl::optional<Rib::Definition> resolve_path (const AST::SimplePath &path, + Args &&...args) + { + return resolve_path (path.get_segments (), + path.has_opening_scope_resolution (), + std::forward<Args> (args)...); + } + + template <typename... Args> + tl::optional<Rib::Definition> resolve_path (const AST::PathInExpression &path, + Args &&...args) + { + return resolve_path (path.get_segments (), path.opening_scope_resolution (), + std::forward<Args> (args)...); + } + + template <typename... Args> + tl::optional<Rib::Definition> resolve_path (const AST::TypePath &path, + Args &&...args) + { + return resolve_path (path.get_segments (), + path.has_opening_scope_resolution_op (), + std::forward<Args> (args)...); + } + private: /* Map of "usage" nodes which have been resolved to a "definition" node */ std::map<Usage, Definition> resolved_nodes; diff --git a/gcc/rust/resolve/rust-name-resolver.cc b/gcc/rust/resolve/rust-name-resolver.cc index 21147bd8..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 { @@ -435,8 +438,7 @@ Resolver::generate_builtins () 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); @@ -469,6 +471,9 @@ Resolver::setup_builtin (const std::string &name, TyTy::BaseType *tyty) 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); @@ -477,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; @@ -488,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); @@ -498,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; @@ -509,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 ()); @@ -519,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; @@ -530,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 ()); @@ -540,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; @@ -551,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 ()); @@ -560,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; @@ -662,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 43b79e5..a3b34a9 100644 --- a/gcc/rust/resolve/rust-name-resolver.h +++ b/gcc/rust/resolve/rust-name-resolver.h @@ -204,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); diff --git a/gcc/rust/resolve/rust-rib.cc b/gcc/rust/resolve/rust-rib.cc index b0380bb..690bde9 100644 --- a/gcc/rust/resolve/rust-rib.cc +++ b/gcc/rust/resolve/rust-rib.cc @@ -22,7 +22,8 @@ namespace Rust { namespace Resolver2_0 { -Rib::Definition::Definition (NodeId id, Mode mode) +Rib::Definition::Definition (NodeId id, Mode mode, bool enum_variant) + : enum_variant (enum_variant) { switch (mode) { @@ -51,6 +52,12 @@ Rib::Definition::is_ambiguous () const return ids_globbed.size () > 1; } +bool +Rib::Definition::is_variant () const +{ + return enum_variant; +} + std::string Rib::Definition::to_string () const { @@ -69,25 +76,27 @@ Rib::Definition::to_string () const } } out << "]"; + if (enum_variant) + out << "(enum variant)"; return out.str (); } Rib::Definition Rib::Definition::Shadowable (NodeId id) { - return Definition (id, Mode::SHADOWABLE); + return Definition (id, Mode::SHADOWABLE, false); } Rib::Definition -Rib::Definition::NonShadowable (NodeId id) +Rib::Definition::NonShadowable (NodeId id, bool enum_variant) { - return Definition (id, Mode::NON_SHADOWABLE); + return Definition (id, Mode::NON_SHADOWABLE, enum_variant); } Rib::Definition Rib::Definition::Globbed (NodeId id) { - return Definition (id, Mode::GLOBBED); + return Definition (id, Mode::GLOBBED, false); } DuplicateNameError::DuplicateNameError (std::string name, NodeId existing) diff --git a/gcc/rust/resolve/rust-rib.h b/gcc/rust/resolve/rust-rib.h index 2eb8de8..140c991 100644 --- a/gcc/rust/resolve/rust-rib.h +++ b/gcc/rust/resolve/rust-rib.h @@ -111,7 +111,7 @@ public: class Definition { public: - static Definition NonShadowable (NodeId id); + static Definition NonShadowable (NodeId id, bool enum_variant = false); static Definition Shadowable (NodeId id); static Definition Globbed (NodeId id); @@ -124,11 +124,21 @@ public: 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 () const @@ -155,7 +165,7 @@ public: GLOBBED }; - Definition (NodeId id, Mode mode); + Definition (NodeId id, Mode mode, bool enum_variant); }; enum class Kind @@ -173,8 +183,48 @@ 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, + /* Generic rib, used to store generics */ + Generics, } 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"; + case Kind::Prelude: + return "Prelude"; + case Kind::Generics: + return "Generics"; + } + + 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 a0d8492..0930f96 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc @@ -32,21 +32,18 @@ TopLevel::TopLevel (NameResolutionContext &resolver) template <typename T> void -TopLevel::insert_or_error_out (const Identifier &identifier, const T &node, - Namespace ns) +TopLevel::insert_enum_variant_or_error_out (const Identifier &identifier, + const T &node) { - insert_or_error_out (identifier, node.get_locus (), node.get_node_id (), ns); + insert_enum_variant_or_error_out (identifier, node.get_locus (), + node.get_node_id ()); } void -TopLevel::insert_or_error_out (const Identifier &identifier, - const location_t &locus, const NodeId &node_id, - Namespace ns) +TopLevel::check_multiple_insertion_error ( + tl::expected<NodeId, DuplicateNameError> result, const Identifier &identifier, + const location_t &locus, const NodeId node_id) { - // keep track of each node's location to provide useful errors - node_locations.emplace (node_id, locus); - - auto result = ctx.insert (identifier, node_id, ns); if (result) dirty = true; else if (result.error ().existing != node_id) @@ -58,6 +55,37 @@ TopLevel::insert_or_error_out (const Identifier &identifier, identifier.as_string ().c_str ()); } } +void +TopLevel::insert_enum_variant_or_error_out (const Identifier &identifier, + const location_t &locus, + const NodeId node_id) +{ + // keep track of each node's location to provide useful errors + node_locations.emplace (node_id, locus); + + auto result = ctx.insert_variant (identifier, node_id); + check_multiple_insertion_error (result, identifier, locus, node_id); +} + +template <typename T> +void +TopLevel::insert_or_error_out (const Identifier &identifier, const T &node, + Namespace ns) +{ + insert_or_error_out (identifier, node.get_locus (), node.get_node_id (), ns); +} + +void +TopLevel::insert_or_error_out (const Identifier &identifier, + const location_t &locus, const NodeId &node_id, + Namespace ns) +{ + // keep track of each node's location to provide useful errors + node_locations.emplace (node_id, locus); + + auto result = ctx.insert (identifier, node_id, ns); + check_multiple_insertion_error (result, identifier, locus, node_id); +} void TopLevel::go (AST::Crate &crate) @@ -67,62 +95,43 @@ TopLevel::go (AST::Crate &crate) // times in a row in a fixed-point fashion, so it would make the code // responsible for this ugly and perfom a lot of error checking. - for (auto &item : crate.items) - item->accept_vis (*this); + visit (crate); } void TopLevel::visit (AST::Module &module) { - insert_or_error_out (module.get_name (), module, Namespace::Types); - - // 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 (); - - auto sub_visitor = [this, &module] () { - for (auto &item : module.get_items ()) - item->accept_vis (*this); - }; + DefaultResolver::visit (module); - ctx.scoped (Rib::Kind::Module, module.get_node_id (), sub_visitor, - module.get_name ()); - - if (Analysis::Mappings::get ().lookup_ast_module (module.get_node_id ()) + if (Analysis::Mappings::get ().lookup_glob_container (module.get_node_id ()) == tl::nullopt) - Analysis::Mappings::get ().insert_ast_module (&module); + Analysis::Mappings::get ().insert_glob_container (&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::maybe_insert_big_self (AST::Impl &impl) +{ + insert_or_error_out (Identifier ("Self", impl.get_type ().get_locus ()), + impl.get_type (), Namespace::Types); +} + +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) @@ -141,10 +150,10 @@ insert_macros (std::vector<PROC_MACRO> ¯os, NameResolutionContext &ctx) } void -TopLevel::visit (AST::ExternCrate &crate) +TopLevel::visit_extern_crate (AST::ExternCrate &extern_crate, AST::Crate &crate, + CrateNum num) { auto &mappings = Analysis::Mappings::get (); - CrateNum num = *mappings.lookup_crate_name (crate.get_referenced_crate ()); auto attribute_macros = mappings.lookup_attribute_proc_macros (num); @@ -152,34 +161,27 @@ TopLevel::visit (AST::ExternCrate &crate) auto derive_macros = mappings.lookup_derive_proc_macros (num); - auto sub_visitor = [&] () { - // TODO: Find a way to keep this part clean without the double dispatch. - if (derive_macros.has_value ()) - { - insert_macros (derive_macros.value (), ctx); - for (auto ¯o : derive_macros.value ()) - mappings.insert_derive_proc_macro_def (macro); - } - if (attribute_macros.has_value ()) - { - insert_macros (attribute_macros.value (), ctx); - for (auto ¯o : attribute_macros.value ()) - mappings.insert_attribute_proc_macro_def (macro); - } - if (bang_macros.has_value ()) - { - insert_macros (bang_macros.value (), ctx); - for (auto ¯o : bang_macros.value ()) - mappings.insert_bang_proc_macro_def (macro); - } - }; + // TODO: Find a way to keep this part clean without the double dispatch. + if (derive_macros.has_value ()) + { + insert_macros (derive_macros.value (), ctx); + for (auto ¯o : derive_macros.value ()) + mappings.insert_derive_proc_macro_def (macro); + } + if (attribute_macros.has_value ()) + { + insert_macros (attribute_macros.value (), ctx); + for (auto ¯o : attribute_macros.value ()) + mappings.insert_attribute_proc_macro_def (macro); + } + if (bang_macros.has_value ()) + { + insert_macros (bang_macros.value (), ctx); + for (auto ¯o : bang_macros.value ()) + mappings.insert_bang_proc_macro_def (macro); + } - if (crate.has_as_clause ()) - ctx.scoped (Rib::Kind::Module, crate.get_node_id (), sub_visitor, - crate.get_as_clause ()); - else - ctx.scoped (Rib::Kind::Module, crate.get_node_id (), sub_visitor, - crate.get_referenced_crate ()); + visit (crate); } static bool @@ -236,32 +238,12 @@ TopLevel::visit (AST::Function &function) } void -TopLevel::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 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); - }; - - ctx.scoped (Rib::Kind::Normal, expr.get_node_id (), sub_vis); -} - -void TopLevel::visit (AST::StaticItem &static_item) { - auto sub_vis - = [this, &static_item] () { static_item.get_expr ().accept_vis (*this); }; - - ctx.scoped (Rib::Kind::Item, static_item.get_node_id (), sub_vis); - - insert_or_error_out (static_item.get_identifier ().as_string (), static_item, + insert_or_error_out (static_item.get_identifier (), static_item, Namespace::Values); + + DefaultResolver::visit (static_item); } void @@ -269,19 +251,14 @@ TopLevel::visit (AST::ExternalStaticItem &static_item) { insert_or_error_out (static_item.get_identifier ().as_string (), static_item, Namespace::Values); + + 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); + DefaultResolver::visit (struct_item); insert_or_error_out (struct_item.get_struct_name (), struct_item, Namespace::Types); @@ -297,11 +274,10 @@ TopLevel::visit (AST::StructStruct &struct_item) void TopLevel::visit (AST::TypeParam &type_param) { - // Hacky and weird, find a better solution - // We should probably not even insert self in the first place ? - if (type_param.get_type_representation ().as_string () != "Self") - insert_or_error_out (type_param.get_type_representation (), type_param, - Namespace::Types); + insert_or_error_out (type_param.get_type_representation (), type_param, + Namespace::Types); + + DefaultResolver::visit (type_param); } void @@ -320,30 +296,40 @@ 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); + + DefaultResolver::visit (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); + + DefaultResolver::visit (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); + + DefaultResolver::visit (variant); } void TopLevel::visit (AST::EnumItemDiscriminant &variant) { insert_or_error_out (variant.get_identifier (), variant, Namespace::Types); + + DefaultResolver::visit (variant); } void @@ -352,13 +338,14 @@ 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); - }; + DefaultResolver::visit (enum_item); - ctx.scoped (Rib::Kind::Item /* FIXME: Is that correct? */, - enum_item.get_node_id (), field_vis, enum_item.get_identifier ()); + // Since enums can be containers for imports, we need to insert them like we + // do for modules + if (Analysis::Mappings::get ().lookup_glob_container ( + enum_item.get_node_id ()) + == tl::nullopt) + Analysis::Mappings::get ().insert_glob_container (&enum_item); } void @@ -366,6 +353,8 @@ TopLevel::visit (AST::Union &union_item) { insert_or_error_out (union_item.get_identifier (), union_item, Namespace::Types); + + DefaultResolver::visit (union_item); } void @@ -386,21 +375,18 @@ TopLevel::visit (AST::TypeAlias &type_item) DefaultResolver::visit (type_item); } -static void -flatten_rebind ( +static void flatten_rebind ( const AST::UseTreeRebind &glob, std::vector<std::pair<AST::SimplePath, AST::UseTreeRebind>> &rebind_paths); -static void -flatten_list ( +static void flatten_list ( const AST::UseTreeList &glob, std::vector<AST::SimplePath> &paths, std::vector<AST::SimplePath> &glob_paths, std::vector<std::pair<AST::SimplePath, AST::UseTreeRebind>> &rebind_paths, NameResolutionContext &ctx); -static void -flatten_glob (const AST::UseTreeGlob &glob, - std::vector<AST::SimplePath> &glob_paths, - NameResolutionContext &ctx); +static void flatten_glob (const AST::UseTreeGlob &glob, + std::vector<AST::SimplePath> &glob_paths, + NameResolutionContext &ctx); static void flatten ( @@ -411,17 +397,20 @@ flatten ( { switch (tree->get_kind ()) { - case AST::UseTree::Rebind: { + case AST::UseTree::Rebind: + { auto rebind = static_cast<const AST::UseTreeRebind *> (tree); flatten_rebind (*rebind, rebind_paths); break; } - case AST::UseTree::List: { + case AST::UseTree::List: + { auto list = static_cast<const AST::UseTreeList *> (tree); flatten_list (*list, paths, glob_paths, rebind_paths, ctx); break; } - case AST::UseTree::Glob: { + case AST::UseTree::Glob: + { auto glob = static_cast<const AST::UseTreeGlob *> (tree); flatten_glob (*glob, glob_paths, ctx); break; @@ -503,6 +492,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 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 7f4e295..8d3da92 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h @@ -108,15 +108,19 @@ public: {} }; - std::unordered_map<NodeId, std::vector<ImportKind>> && - get_imports_to_resolve () + std::unordered_map<NodeId, std::vector<ImportKind>> &get_imports_to_resolve () { - return std::move (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 @@ -130,6 +134,14 @@ public: 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 @@ -148,9 +160,10 @@ private: void visit (AST::Module &module) override; void visit (AST::Trait &trait) override; + void maybe_insert_big_self (AST::Impl &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; @@ -163,7 +176,7 @@ private: 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; + void visit_extern_crate (AST::ExternCrate &, AST::Crate &, CrateNum) override; void visit (AST::TypeParam &type_param) override; void visit (AST::ConstGenericParam &const_param) override; |