diff options
Diffstat (limited to 'gcc/rust/resolve')
30 files changed, 1429 insertions, 621 deletions
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.cc b/gcc/rust/resolve/rust-ast-resolve-expr.cc index 6524376..dc7f76d 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) { @@ -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"); }); } @@ -499,7 +459,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"); }); } @@ -575,7 +535,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 +564,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 +576,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); @@ -682,7 +642,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 +711,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 +741,7 @@ ResolveExpr::visit (AST::ClosureExprInnerTyped &expr) resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); - resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_label_scope ().peek ()); std::vector<PatternBinding> bindings = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())}; diff --git a/gcc/rust/resolve/rust-ast-resolve-implitem.h b/gcc/rust/resolve/rust-ast-resolve-implitem.h index 2ca1296..971bf8f 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"); + rust_error_at (r, "defined multiple times"); }); } @@ -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"); + rust_error_at (r, "defined multiple times"); }); } @@ -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"); + rust_error_at (r, "defined multiple times"); }); } @@ -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"); + rust_error_at (r, "defined multiple times"); }); 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"); + rust_error_at (r, "defined multiple times"); }); 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"); + rust_error_at (r, "defined multiple times"); }); 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"); + rust_error_at (r, "defined multiple times"); }); 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"); + rust_error_at (r, "defined multiple times"); }); NodeId current_module = resolver->peek_current_module_scope (); @@ -240,7 +240,7 @@ public: rich_location r (line_table, type.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + rust_error_at (r, "defined multiple times"); }); 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 b26ac34..d584961 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 ()); @@ -374,8 +374,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 +409,8 @@ ResolveItem::visit (AST::Union &union_decl) resolver->get_type_scope ().push (scope_node_id); if (union_decl.has_generics ()) - for (auto &generic : union_decl.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, canonical_prefix); + ResolveGenericParams::go (union_decl.get_generic_params (), prefix, + canonical_prefix); if (union_decl.has_where_clause ()) ResolveWhereClause::Resolve (union_decl.get_where_clause ()); @@ -473,11 +473,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 +567,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 ()) @@ -648,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 ()) @@ -776,10 +776,10 @@ 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 ()); - ResolveGenericParam::go (trait.get_implicit_self (), prefix, - canonical_prefix); - 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 ( @@ -903,7 +903,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)); + } } } @@ -1040,12 +1051,12 @@ ResolveExternItem::visit (AST::Function &function) resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); - resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_label_scope ().peek ()); // resolve the generics if (function.has_generics ()) - for (auto &generic : function.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, canonical_prefix); + ResolveGenericParams::go (function.get_generic_params (), prefix, + canonical_prefix); if (function.has_return_type ()) ResolveType::go (function.get_return_type ()); diff --git a/gcc/rust/resolve/rust-ast-resolve-path.cc b/gcc/rust/resolve/rust-ast-resolve-path.cc index ea39fd4..530926d 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,8 @@ 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", + "leading path segment %qs can only be used at the " + "beginning of a path", segment.as_string ().c_str ()); return UNKNOWN_NODEID; } @@ -75,8 +80,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 +103,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 +156,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 +217,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 +268,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 +280,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 +354,28 @@ 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 (), + "%<super%> 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-stmt.cc b/gcc/rust/resolve/rust-ast-resolve-stmt.cc index 226d8e8..fefb522 100644 --- a/gcc/rust/resolve/rust-ast-resolve-stmt.cc +++ b/gcc/rust/resolve/rust-ast-resolve-stmt.cc @@ -70,7 +70,7 @@ ResolveStmt::visit (AST::StaticItem &var) [&] (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"); + rust_error_at (r, "defined multiple times"); }); ResolveType::go (var.get_type ()); diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.h b/gcc/rust/resolve/rust-ast-resolve-stmt.h index 6dfac91..6c99d6a 100644 --- a/gcc/rust/resolve/rust-ast-resolve-stmt.h +++ b/gcc/rust/resolve/rust-ast-resolve-stmt.h @@ -63,7 +63,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, constant.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + rust_error_at (r, "defined multiple times"); }); ResolveType::go (constant.get_type ()); @@ -73,9 +73,10 @@ public: void visit (AST::LetStmt &stmt) override { if (stmt.has_init_expr ()) - { - ResolveExpr::go (stmt.get_init_expr (), prefix, canonical_prefix); - } + ResolveExpr::go (stmt.get_init_expr (), prefix, canonical_prefix); + + if (stmt.has_else_expr ()) + ResolveExpr::go (stmt.get_else_expr (), prefix, canonical_prefix); PatternDeclaration::go (stmt.get_pattern (), Rib::ItemType::Var); if (stmt.has_type ()) @@ -97,17 +98,15 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, struct_decl.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + rust_error_at (r, "defined multiple times"); }); NodeId scope_node_id = struct_decl.get_node_id (); resolver->get_type_scope ().push (scope_node_id); if (struct_decl.has_generics ()) - { - for (auto &generic : struct_decl.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, canonical_prefix); - } + ResolveGenericParams::go (struct_decl.get_generic_params (), prefix, + canonical_prefix); for (AST::TupleField &field : struct_decl.get_fields ()) ResolveType::go (field.get_field_type ()); @@ -130,17 +129,15 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, enum_decl.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + rust_error_at (r, "defined multiple times"); }); NodeId scope_node_id = enum_decl.get_node_id (); resolver->get_type_scope ().push (scope_node_id); if (enum_decl.has_generics ()) - { - for (auto &generic : enum_decl.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, canonical_prefix); - } + ResolveGenericParams::go (enum_decl.get_generic_params (), prefix, + canonical_prefix); for (auto &variant : enum_decl.get_variants ()) ResolveStmt::go (*variant, path, canonical_prefix, path); @@ -162,7 +159,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, item.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + rust_error_at (r, "defined multiple times"); }); // Done, no fields. @@ -182,7 +179,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, item.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + rust_error_at (r, "defined multiple times"); }); for (auto &field : item.get_tuple_fields ()) @@ -208,7 +205,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, item.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + rust_error_at (r, "defined multiple times"); }); for (auto &field : item.get_struct_fields ()) @@ -234,7 +231,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, item.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + rust_error_at (r, "defined multiple times"); }); // Done, no fields. @@ -255,17 +252,15 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, struct_decl.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + rust_error_at (r, "defined multiple times"); }); NodeId scope_node_id = struct_decl.get_node_id (); resolver->get_type_scope ().push (scope_node_id); if (struct_decl.has_generics ()) - { - for (auto &generic : struct_decl.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, canonical_prefix); - } + ResolveGenericParams::go (struct_decl.get_generic_params (), prefix, + canonical_prefix); for (AST::StructField &field : struct_decl.get_fields ()) { @@ -293,15 +288,15 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, union_decl.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + rust_error_at (r, "defined multiple times"); }); NodeId scope_node_id = union_decl.get_node_id (); resolver->get_type_scope ().push (scope_node_id); if (union_decl.has_generics ()) - for (auto &generic : union_decl.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, canonical_prefix); + ResolveGenericParams::go (union_decl.get_generic_params (), prefix, + canonical_prefix); for (AST::StructField &field : union_decl.get_variants ()) { @@ -329,7 +324,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, function.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + rust_error_at (r, "defined multiple times"); }); NodeId scope_node_id = function.get_node_id (); @@ -338,11 +333,11 @@ public: resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); - resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_label_scope ().peek ()); if (function.has_generics ()) - for (auto &generic : function.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, canonical_prefix); + ResolveGenericParams::go (function.get_generic_params (), prefix, + canonical_prefix); if (function.has_return_type ()) ResolveType::go (function.get_return_type ()); diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h b/gcc/rust/resolve/rust-ast-resolve-toplevel.h index 565ca92..379ccab 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"); + rust_error_at (r, "defined multiple times"); }); 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"); + rust_error_at (r, "defined multiple times"); }); 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"); + rust_error_at (r, "defined multiple times"); }); 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"); + rust_error_at (r, "defined multiple times"); }); 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"); + rust_error_at (r, "defined multiple times"); }); 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"); + rust_error_at (r, "defined multiple times"); }); 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"); + rust_error_at (r, "defined multiple times"); }); 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"); + rust_error_at (r, "defined multiple times"); }); 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); + rust_error_at (r, "defined multiple times"); + }; + + 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"); + rust_error_at (r, "defined multiple times"); }); 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"); + rust_error_at (r, "defined multiple times"); }); 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"); + rust_error_at (r, "defined multiple times"); }); 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"); + rust_error_at (r, "defined multiple times"); }); 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"); + rust_error_at (r, "defined multiple times"); }); 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"); + rust_error_at (r, "defined multiple times"); }); 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"); + rust_error_at (r, "defined multiple times"); }); } diff --git a/gcc/rust/resolve/rust-ast-resolve-type.cc b/gcc/rust/resolve/rust-ast-resolve-type.cc index 63c9dac..5ab0c44 100644 --- a/gcc/rust/resolve/rust-ast-resolve-type.cc +++ b/gcc/rust/resolve/rust-ast-resolve-type.cc @@ -27,6 +27,49 @@ 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) { @@ -72,7 +115,7 @@ ResolveType::visit (AST::RawPointerType &type) void ResolveType::visit (AST::InferredType &) { - // FIXME + // nothing to do } void @@ -87,6 +130,19 @@ ResolveType::visit (AST::SliceType &type) resolved_node = ResolveType::go (type.get_elem_type ()); } +void +ResolveType::visit (AST::ImplTraitType &type) +{ + for (auto &bound : type.get_type_param_bounds ()) + ResolveTypeBound::go (*bound); +} + +void +ResolveType::visit (AST::ImplTraitTypeOneBound &type) +{ + ResolveTypeBound::go (type.get_trait_bound ()); +} + // resolve relative type-paths bool @@ -120,8 +176,8 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id) 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", + "leading path segment %qs can only be used at the " + "beginning of a path", segment->as_string ().c_str ()); return false; } @@ -193,14 +249,28 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id) = 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_lang_item () && segment->is_lower_self_seg ()) @@ -208,8 +278,16 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id) // 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; } @@ -227,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 { @@ -260,7 +356,7 @@ 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", + "could not resolve type path %qs", segment->as_string ().c_str ()); return false; } @@ -271,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 { diff --git a/gcc/rust/resolve/rust-ast-resolve-type.h b/gcc/rust/resolve/rust-ast-resolve-type.h index 662f2f5..8379d0e 100644 --- a/gcc/rust/resolve/rust-ast-resolve-type.h +++ b/gcc/rust/resolve/rust-ast-resolve-type.h @@ -61,61 +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 () {} @@ -142,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); + 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); + } + + static void go_single (AST::GenericParam ¶m, const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) + { + ResolveGenericParams resolver (prefix, canonical_prefix); + + param.accept_vis (resolver); + resolver.first_pass = false; param.accept_vis (resolver); - return resolver.resolved_node; } void visit (AST::ConstGenericParam ¶m) override { - ResolveType::go (param.get_type ()); - - if (param.has_default_value ()) + if (first_pass) + ResolveType::go (param.get_type ()); + else if (param.has_default_value ()) ResolveExpr::go (param.get_default_value ().get_expression (), prefix, canonical_prefix); - - ok = true; } void visit (AST::TypeParam ¶m) override { - // if it has a type lets resolve it - if (param.has_type ()) - ResolveType::go (param.get_type ()); - - if (param.has_type_param_bounds ()) + 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..3e3c992 100644 --- a/gcc/rust/resolve/rust-ast-resolve.cc +++ b/gcc/rust/resolve/rust-ast-resolve.cc @@ -75,7 +75,7 @@ NameResolution::go (AST::Crate &crate) resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); - resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_label_scope ().peek ()); // get the root segment CanonicalPath crate_prefix diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc index 342f102..afaca1f 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc @@ -22,11 +22,13 @@ #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,16 +53,10 @@ 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 @@ -74,7 +70,8 @@ Early::go (AST::Crate &crate) 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.get_segments (), Namespace::Types); if (!resolved.has_value ()) return false; @@ -226,11 +223,24 @@ Early::visit (AST::BlockExpr &block) void Early::visit (AST::Module &module) { - textual_scope.push (); + bool is_macro_use = false; + + for (const auto &attr : module.get_outer_attrs ()) + { + if (attr.get_path ().as_string () == Values::Attributes::MACRO_USE) + { + is_macro_use = true; + break; + } + } + + if (!is_macro_use) + textual_scope.push (); DefaultResolver::visit (module); - textual_scope.pop (); + if (!is_macro_use) + textual_scope.pop (); } void @@ -259,13 +269,14 @@ Early::visit (AST::MacroInvocation &invoc) // we won't have changed `definition` from `nullopt` if there are more // than one segments in our path if (!definition.has_value ()) - definition = ctx.macros.resolve_path (path.get_segments ()); + definition = ctx.resolve_path (path.get_segments (), Namespace::Macros); // if the definition still does not have a value, then it's an error if (!definition.has_value ()) { collect_error (Error (invoc.get_locus (), ErrorCode::E0433, - "could not resolve macro invocation")); + "could not resolve macro invocation %qs", + path.as_string ().c_str ())); return; } @@ -300,8 +311,8 @@ Early::visit_attributes (std::vector<AST::Attribute> &attrs) auto traits = attr.get_traits_to_derive (); for (auto &trait : traits) { - auto definition - = ctx.macros.resolve_path (trait.get ().get_segments ()); + auto definition = ctx.resolve_path (trait.get ().get_segments (), + Namespace::Macros); if (!definition.has_value ()) { // FIXME: Change to proper error message @@ -324,8 +335,8 @@ Early::visit_attributes (std::vector<AST::Attribute> &attrs) ->lookup_builtin (name) .is_error ()) // Do not resolve builtins { - auto definition - = ctx.macros.resolve_path (attr.get_path ().get_segments ()); + auto definition = ctx.resolve_path (attr.get_path ().get_segments (), + Namespace::Macros); if (!definition.has_value ()) { // FIXME: Change to proper error message @@ -359,5 +370,103 @@ Early::visit (AST::StructStruct &s) DefaultResolver::visit (s); } +void +Early::finalize_simple_import (const Early::ImportPair &mapping) +{ + // FIXME: We probably need to store namespace information + + auto locus = mapping.import_kind.to_resolve.get_locus (); + auto data = mapping.data; + auto identifier + = mapping.import_kind.to_resolve.get_final_segment ().get_segment_name (); + + for (auto &&definition : data.definitions ()) + toplevel + .insert_or_error_out ( + identifier, locus, definition.first.get_node_id (), definition.second /* TODO: This isn't clear - it would be better if it was called .ns or something */); +} + +void +Early::finalize_glob_import (NameResolutionContext &ctx, + const Early::ImportPair &mapping) +{ + auto module = Analysis::Mappings::get ().lookup_ast_module ( + mapping.data.module ().get_node_id ()); + rust_assert (module); + + GlobbingVisitor glob_visitor (ctx); + glob_visitor.go (module.value ()); +} + +void +Early::finalize_rebind_import (const Early::ImportPair &mapping) +{ + // We can fetch the value here as `resolve_rebind` will only be called on + // imports of the right kind + auto &path = mapping.import_kind.to_resolve; + auto &rebind = mapping.import_kind.rebind.value (); + auto data = mapping.data; + + location_t locus = UNKNOWN_LOCATION; + std::string declared_name; + + // FIXME: This needs to be done in `FinalizeImports` + switch (rebind.get_new_bind_type ()) + { + case AST::UseTreeRebind::NewBindType::IDENTIFIER: + declared_name = rebind.get_identifier ().as_string (); + locus = rebind.get_identifier ().get_locus (); + break; + case AST::UseTreeRebind::NewBindType::NONE: { + const auto &segments = path.get_segments (); + // We don't want to insert `self` with `use module::self` + if (path.get_final_segment ().is_lower_self_seg ()) + { + rust_assert (segments.size () > 1); + declared_name = segments[segments.size () - 2].as_string (); + } + else + declared_name = path.get_final_segment ().as_string (); + locus = path.get_final_segment ().get_locus (); + break; + } + case AST::UseTreeRebind::NewBindType::WILDCARD: + rust_unreachable (); + break; + } + + for (auto &&definition : data.definitions ()) + toplevel.insert_or_error_out ( + declared_name, locus, definition.first.get_node_id (), definition.second /* TODO: This isn't clear - it would be better if it was called .ns or something */); +} + +void +Early::visit (AST::UseDeclaration &decl) +{ + auto &imports = toplevel.get_imports_to_resolve (); + auto current_import = imports.find (decl.get_node_id ()); + if (current_import != imports.end ()) + { + build_import_mapping (*current_import); + } + + // Once this is done, we finalize their resolution + for (const auto &mapping : import_mappings.get (decl.get_node_id ())) + switch (mapping.import_kind.kind) + { + case TopLevel::ImportKind::Kind::Glob: + finalize_glob_import (ctx, mapping); + break; + case TopLevel::ImportKind::Kind::Simple: + finalize_simple_import (mapping); + break; + case TopLevel::ImportKind::Kind::Rebind: + finalize_rebind_import (mapping); + break; + } + + DefaultResolver::visit (decl); +} + } // namespace Resolver2_0 } // namespace Rust diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.h b/gcc/rust/resolve/rust-early-name-resolver-2.0.h index a7ad0f7..c4226fe 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 { @@ -227,9 +229,12 @@ 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)); + ctx.resolve_path (segments, Namespace::Values) + .map (pair_with_ns (Namespace::Values)); + ctx.resolve_path (segments, Namespace::Types) + .map (pair_with_ns (Namespace::Types)); + ctx.resolve_path (segments, Namespace::Macros) + .map (pair_with_ns (Namespace::Macros)); return resolved; } @@ -243,6 +248,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 34bac98..fc9a26c 100644 --- a/gcc/rust/resolve/rust-early-name-resolver.cc +++ b/gcc/rust/resolve/rust-early-name-resolver.cc @@ -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 @@ -476,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; } @@ -560,30 +562,6 @@ EarlyNameResolver::visit (AST::TupleStructPattern &pattern) } void -EarlyNameResolver::visit (AST::TraitBound &) -{} - -void -EarlyNameResolver::visit (AST::ImplTraitType &) -{} - -void -EarlyNameResolver::visit (AST::TraitObjectType &) -{} - -void -EarlyNameResolver::visit (AST::ParenthesisedType &) -{} - -void -EarlyNameResolver::visit (AST::ImplTraitTypeOneBound &) -{} - -void -EarlyNameResolver::visit (AST::TraitObjectTypeOneBound &) -{} - -void EarlyNameResolver::visit (AST::TupleType &) {} diff --git a/gcc/rust/resolve/rust-early-name-resolver.h b/gcc/rust/resolve/rust-early-name-resolver.h index 48562df..26fc84d 100644 --- a/gcc/rust/resolve/rust-early-name-resolver.h +++ b/gcc/rust/resolve/rust-early-name-resolver.h @@ -36,6 +36,7 @@ public: private: using AST::DefaultASTVisitor::visit; + /** * Execute a lambda within a scope. This is equivalent to calling * `enter_scope` before your code and `exit_scope` after. This ensures @@ -181,12 +182,6 @@ private: virtual void visit (AST::StructPatternFieldIdent &field); virtual void visit (AST::StructPattern &pattern); virtual void visit (AST::TupleStructPattern &pattern); - virtual void visit (AST::TraitBound &bound); - virtual void visit (AST::ImplTraitType &type); - virtual void visit (AST::TraitObjectType &type); - virtual void visit (AST::ParenthesisedType &type); - virtual void visit (AST::ImplTraitTypeOneBound &type); - virtual void visit (AST::TraitObjectTypeOneBound &type); virtual void visit (AST::TupleType &type); virtual void visit (AST::RawPointerType &type); virtual void visit (AST::ReferenceType &type); diff --git a/gcc/rust/resolve/rust-finalize-imports-2.0.cc b/gcc/rust/resolve/rust-finalize-imports-2.0.cc index 71916ae..b0e8651 100644 --- a/gcc/rust/resolve/rust-finalize-imports-2.0.cc +++ b/gcc/rust/resolve/rust-finalize-imports-2.0.cc @@ -125,100 +125,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..d587a5e 100644 --- a/gcc/rust/resolve/rust-finalize-imports-2.0.h +++ b/gcc/rust/resolve/rust-finalize-imports-2.0.h @@ -49,62 +49,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.h b/gcc/rust/resolve/rust-forever-stack.h index 66e1266..f390e38 100644 --- a/gcc/rust/resolve/rust-forever-stack.h +++ b/gcc/rust/resolve/rust-forever-stack.h @@ -547,13 +547,17 @@ 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)), 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 ()); } /** @@ -588,6 +592,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 * @@ -651,6 +658,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` @@ -661,7 +670,9 @@ public: * current map, an empty one otherwise. */ template <typename S> - tl::optional<Rib::Definition> resolve_path (const std::vector<S> &segments); + tl::optional<Rib::Definition> resolve_path ( + const std::vector<S> &segments, + std::function<void (const S &, NodeId)> insert_segment_resolution); // FIXME: Documentation tl::optional<Resolver::CanonicalPath> to_canonical_path (NodeId id) const; @@ -670,7 +681,7 @@ public: 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 @@ -713,6 +724,7 @@ private: {} bool is_root () const; + bool is_prelude () const; bool is_leaf () const; void insert_child (Link link, Node child); @@ -748,13 +760,21 @@ 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; + 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` */ @@ -764,14 +784,20 @@ private: Node &find_closest_module (Node &starting_point); template <typename S> - tl::optional<SegIterator<S>> - find_starting_point (const std::vector<S> &segments, - std::reference_wrapper<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); 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); + + 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 diff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx index d3d7889..885f282 100644 --- a/gcc/rust/resolve/rust-forever-stack.hxx +++ b/gcc/rust/resolve/rust-forever-stack.hxx @@ -21,6 +21,7 @@ #include "rust-diagnostics.h" #include "rust-forever-stack.h" #include "rust-rib.h" +#include "rust-unwrap-segment.h" #include "optional.h" namespace Rust { @@ -35,6 +36,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 (); @@ -62,6 +70,16 @@ 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 @@ -172,6 +190,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 () @@ -274,10 +300,12 @@ ForeverStack<N>::get (const Identifier &name) return candidate.map_or ( [&resolved_definition] (Rib::Definition found) { - // for most namespaces, we do not need to care about various ribs - they - // are available from all contexts if defined in the current scope, or - // an outermore one. so if we do have a candidate, we can return it - // directly and stop iterating + if (found.is_variant ()) + return KeepGoing::Yes; + // for most namespaces, we do not need to care about various ribs - + // they are available from all contexts if defined in the current + // scope, or an outermore one. so if we do have a candidate, we can + // return it directly and stop iterating resolved_definition = found; return KeepGoing::No; @@ -289,6 +317,20 @@ ForeverStack<N>::get (const Identifier &name) return resolved_definition; } +template <Namespace N> +tl::optional<Rib::Definition> +ForeverStack<N>::get_lang_prelude (const Identifier &name) +{ + return lang_prelude.rib.get (name.as_string ()); +} + +template <Namespace N> +tl::optional<Rib::Definition> +ForeverStack<N>::get_lang_prelude (const std::string &name) +{ + return lang_prelude.rib.get (name); +} + template <> tl::optional<Rib::Definition> inline ForeverStack<Namespace::Labels>::get ( const Identifier &name) @@ -375,21 +417,20 @@ template <Namespace N> template <typename S> tl::optional<typename std::vector<S>::const_iterator> ForeverStack<N>::find_starting_point ( - const std::vector<S> &segments, std::reference_wrapper<Node> &starting_point) + const std::vector<S> &segments, std::reference_wrapper<Node> &starting_point, + std::function<void (const S &, NodeId)> insert_segment_resolution) { 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 @@ -401,17 +442,21 @@ ForeverStack<N>::find_starting_point ( 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 ()) { + starting_point = find_closest_module (starting_point); if (starting_point.get ().is_root ()) { rust_error_at (seg.get_locus (), ErrorCode::E0433, @@ -421,6 +466,8 @@ ForeverStack<N>::find_starting_point ( starting_point = find_closest_module (starting_point.get ().parent.value ()); + + insert_segment_resolution (outer_seg, starting_point.get ().id); continue; } @@ -438,13 +485,26 @@ 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) { - 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 @@ -455,55 +515,170 @@ ForeverStack<N>::resolve_segments ( tl::optional<typename ForeverStack<N>::Node &> child = tl::nullopt; - for (auto &kv : current_node->children) + /* + * On every iteration this loop either + * + * 1. terminates + * + * 2. decreases the depth of the node pointed to by current_node until + * current_node reaches the root + * + * 3. If the root node is reached, and we were not able to resolve the + * segment, we search the prelude rib for the segment, by setting + * current_node to point to the prelude, and toggling the + * searched_prelude boolean to true. If current_node is the prelude + * rib, and searched_prelude is true, we will exit. + * + * This ensures termination. + * + */ + bool searched_prelude = false; + while (true) { - auto &link = kv.first; + // may set the value of child + for (auto &kv : current_node->children) + { + auto &link = kv.first; + + if (link.path.map_or ( + [&str] (Identifier path) { + auto &path_str = path.as_string (); + return str == path_str; + }, + false)) + { + child = kv.second; + break; + } + } - if (link.path.map_or ( - [&str] (Identifier path) { - auto &path_str = path.as_string (); - return str == path_str; - }, - false)) + if (child.has_value ()) { - child = kv.second; break; } - } - if (!child.has_value ()) - { - rust_error_at (seg.get_locus (), ErrorCode::E0433, - "failed to resolve path segment %qs", str.c_str ()); - return tl::nullopt; + if (N == Namespace::Types) + { + auto rib_lookup = current_node->rib.get (seg.as_string ()); + if (rib_lookup && !rib_lookup->is_ambiguous ()) + { + insert_segment_resolution (outer_seg, + rib_lookup->get_node_id ()); + return tl::nullopt; + } + } + + if (current_node->is_root () && !searched_prelude) + { + searched_prelude = true; + current_node = &lang_prelude; + continue; + } + + if (!is_start (iterator, segments) + || current_node->rib.kind == Rib::Kind::Module + || current_node->is_prelude ()) + { + return tl::nullopt; + } + + current_node = ¤t_node->parent.value (); } + // if child didn't contain a value + // the while loop above should have return'd or kept looping current_node = &child.value (); + insert_segment_resolution (outer_seg, current_node->id); } return *current_node; } +template <> +inline tl::optional<Rib::Definition> +ForeverStack<Namespace::Types>::resolve_final_segment (Node &final_node, + std::string &seg_name, + bool is_lower_self) +{ + if (is_lower_self) + return Rib::Definition::NonShadowable (final_node.id); + else + return final_node.rib.get (seg_name); +} + +template <Namespace N> +tl::optional<Rib::Definition> +ForeverStack<N>::resolve_final_segment (Node &final_node, std::string &seg_name, + bool is_lower_self) +{ + return final_node.rib.get (seg_name); +} + template <Namespace N> template <typename S> tl::optional<Rib::Definition> -ForeverStack<N>::resolve_path (const std::vector<S> &segments) +ForeverStack<N>::resolve_path ( + const std::vector<S> &segments, + std::function<void (const S &, NodeId)> insert_segment_resolution) { // TODO: What to do if segments.empty() ? // if there's only one segment, we just use `get` if (segments.size () == 1) - return get (segments.back ().as_string ()); + { + auto &seg = segments.front (); + if (auto lang_item = unwrap_segment_get_lang_item (seg)) + { + NodeId seg_id = Analysis::Mappings::get ().get_lang_item_node ( + lang_item.value ()); + + insert_segment_resolution (seg, seg_id); + // TODO: does NonShadowable matter? + return Rib::Definition::NonShadowable (seg_id); + } + + tl::optional<Rib::Definition> res + = get (unwrap_type_segment (segments.back ()).as_string ()); + + if (!res) + res = get_lang_prelude ( + unwrap_type_segment (segments.back ()).as_string ()); + + if (res && !res->is_ambiguous ()) + insert_segment_resolution (segments.back (), res->get_node_id ()); + return res; + } std::reference_wrapper<Node> starting_point = cursor (); - return find_starting_point (segments, starting_point) - .and_then ([this, &segments, &starting_point] ( + return find_starting_point (segments, starting_point, + insert_segment_resolution) + .and_then ([this, &segments, &starting_point, &insert_segment_resolution] ( typename std::vector<S>::const_iterator iterator) { - return resolve_segments (starting_point.get (), segments, iterator); + return resolve_segments (starting_point.get (), segments, iterator, + insert_segment_resolution); }) - .and_then ([&segments] (Node final_node) { - return final_node.rib.get (segments.back ().as_string ()); + .and_then ([this, &segments, &insert_segment_resolution] ( + Node final_node) -> tl::optional<Rib::Definition> { + // leave resolution within impl blocks to type checker + if (final_node.rib.kind == Rib::Kind::TraitOrImpl) + return tl::nullopt; + + auto &seg = unwrap_type_segment (segments.back ()); + std::string seg_name = seg.as_string (); + + // assuming this can't be a lang item segment + tl::optional<Rib::Definition> res + = resolve_final_segment (final_node, seg_name, + seg.is_lower_self_seg ()); + // Ok we didn't find it in the rib, Lets try the prelude... + if (!res) + res = get_lang_prelude (seg_name); + + if (res && !res->is_ambiguous ()) + insert_segment_resolution (segments.back (), res->get_node_id ()); + + return res; }); } @@ -595,7 +770,7 @@ ForeverStack<N>::to_canonical_path (NodeId id) const auto &link = kv.first; auto &child = kv.second; - if (link.id == child.id) + if (current.id == child.id) { outer_link = &link; break; @@ -613,7 +788,12 @@ ForeverStack<N>::to_canonical_path (NodeId id) const return KeepGoing::Yes; }); - auto path = Resolver::CanonicalPath::create_empty (); + auto &mappings = Analysis::Mappings::get (); + CrateNum crate_num = mappings.lookup_crate_num (root.id).value (); + auto path = Resolver::CanonicalPath::new_seg ( + root.id, mappings.get_crate_name (crate_num).value ()); + path.set_crate_num (crate_num); + for (const auto &segment : segments) path = path.append (segment); @@ -638,9 +818,8 @@ 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 ([] (Node &x) -> Rib & { - return x.rib; - }); + return dfs_node (starting_point, to_find) + .map ([] (const Node &x) -> const Rib & { return x.rib; }); } template <Namespace N> @@ -699,15 +878,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"; @@ -718,7 +901,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, ' '); @@ -750,7 +933,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; diff --git a/gcc/rust/resolve/rust-ice-finalizer.cc b/gcc/rust/resolve/rust-ice-finalizer.cc new file mode 100644 index 0000000..bd4763f --- /dev/null +++ b/gcc/rust/resolve/rust-ice-finalizer.cc @@ -0,0 +1,36 @@ +// Copyright (C) 2020-2024 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include "rust-ice-finalizer.h" + +namespace Rust { +namespace Resolver { + +void ATTRIBUTE_NORETURN +funny_ice_text_finalizer (diagnostic_text_output_format &text_output, + const diagnostic_info *diagnostic, + diagnostic_t diag_kind) +{ + gcc_assert (diag_kind == DK_ICE_NOBT); + default_diagnostic_text_finalizer (text_output, diagnostic, diag_kind); + fnotice (stderr, "You have broken GCC Rust. This is a feature.\n"); + exit (ICE_EXIT_CODE); +} + +} // namespace Resolver +} // namespace Rust diff --git a/gcc/rust/resolve/rust-ice-finalizer.h b/gcc/rust/resolve/rust-ice-finalizer.h new file mode 100644 index 0000000..85ab88f --- /dev/null +++ b/gcc/rust/resolve/rust-ice-finalizer.h @@ -0,0 +1,65 @@ +// Copyright (C) 2020-2024 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#ifndef RUST_ICE_FINALIZER_H +#define RUST_ICE_FINALIZER_H + +#include "rust-linemap.h" +#include "diagnostic.h" + +namespace Rust { +namespace Resolver { + +/* The "break rust" Easter egg. + + Backstory: once upon a time, there used to be a bug in rustc: it would ICE + during typechecking on a 'break' with an expression outside of a loop. The + issue has been reported [0] and fixed [1], but in recognition of this, as a + special Easter egg, "break rust" was made to intentionally cause an ICE. + + [0]: https://github.com/rust-lang/rust/issues/43162 + [1]: https://github.com/rust-lang/rust/pull/43745 + + This was made in a way that does not break valid programs: namely, it only + happens when the 'break' is outside of a loop (so invalid anyway). + + GCC Rust supports this essential feature as well, but in a slightly + different way. Instead of delaying the error until type checking, we emit + it here in the resolution phase. We, too, only do this to programs that + are already invalid: we only emit our funny ICE if the name "rust" (which + must be immediately inside a break-with-a-value expression) fails to + resolve. Note that "break (rust)" does not trigger our ICE, only using + "break rust" directly does, and only if there's no "rust" in scope. We do + this in the same way regardless of whether the "break" is outside of a loop + or inside one. + + As a GNU extension, we also support "break gcc", much to the same effect, + subject to the same rules. */ + +/* The finalizer for our funny ICE. This prints a custom message instead of + the default bug reporting instructions, as there is no bug to report. */ + +void ATTRIBUTE_NORETURN +funny_ice_text_finalizer (diagnostic_text_output_format &text_output, + const diagnostic_info *diagnostic, + diagnostic_t diag_kind); + +} // namespace Resolver +} // namespace Rust + +#endif /* ! RUST_ICE_FINALIZER_H */ diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc index 5aea6a4..7d32374 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc @@ -27,6 +27,8 @@ #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 { @@ -89,16 +91,18 @@ 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 (); @@ -136,6 +140,9 @@ Late::visit (AST::LetStmt &let) visit (let.get_init_expr ()); visit (let.get_pattern ()); + 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? @@ -178,12 +185,39 @@ Late::visit (AST::SelfParam ¶m) } void +Late::visit (AST::BreakExpr &expr) +{ + 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::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; @@ -192,42 +226,96 @@ Late::visit (AST::IdentifierExpr &expr) { resolved = type; } + else if (funny_error) + { + diagnostic_text_finalizer (global_dc) = Resolver::funny_ice_text_finalizer; + emit_diagnostic (DK_ICE_NOBT, expr.get_locus (), -1, + "are you trying to break %s? how dare you?", + expr.as_string ().c_str ()); + } else { - rust_error_at (expr.get_locus (), - "could not resolve identifier expression: %qs", - expr.get_ident ().as_string ().c_str ()); + if (auto type = ctx.types.get_lang_prelude (expr.get_ident ())) + { + resolved = type; + } + else + { + rust_error_at (expr.get_locus (), ErrorCode::E0425, + "cannot find value %qs in this scope", + expr.get_ident ().as_string ().c_str ()); + return; + } + } + + if (resolved->is_ambiguous ()) + { + rust_error_at (expr.get_locus (), ErrorCode::E0659, "%qs is ambiguous", + expr.as_string ().c_str ()); return; } ctx.map_usage (Usage (expr.get_node_id ()), Definition (resolved->get_node_id ())); - // in the old resolver, resolutions are kept in the resolver, not the mappings - // :/ how do we deal with that? - // ctx.mappings.insert_resolved_name(expr, resolved); - // For empty types, do we perform a lookup in ctx.types or should the // toplevel instead insert a name in ctx.values? (like it currently does) } void +Late::visit (AST::StructExprFieldIdentifier &expr) +{ + tl::optional<Rib::Definition> resolved = tl::nullopt; + + if (auto value = ctx.values.get (expr.get_field_name ())) + { + resolved = value; + } + // seems like we don't need a type namespace lookup + else + { + rust_error_at (expr.get_locus (), "could not resolve struct field: %qs", + expr.get_field_name ().as_string ().c_str ()); + return; + } + + if (resolved->is_ambiguous ()) + { + rust_error_at (expr.get_locus (), ErrorCode::E0659, "%qs is ambiguous", + expr.as_string ().c_str ()); + return; + } + + ctx.map_usage (Usage (expr.get_node_id ()), + Definition (resolved->get_node_id ())); +} + +void Late::visit (AST::PathInExpression &expr) { // TODO: How do we have a nice error with `can't capture dynamic environment // in a function item` error here? // do we emit it in `get<Namespace::Labels>`? - auto resolved - = ctx.values.resolve_path (expr.get_segments ()).or_else ([&] () { - return ctx.types.resolve_path (expr.get_segments ()); - }); + DefaultResolver::visit (expr); + + if (expr.is_lang_item ()) + { + ctx.map_usage (Usage (expr.get_node_id ()), + Definition (Analysis::Mappings::get ().get_lang_item_node ( + expr.get_lang_item ()))); + return; + } + + auto resolved = ctx.resolve_path (expr.get_segments (), 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 (), + "could not resolve path expression: %qs", + expr.as_simple_path ().as_string ().c_str ()); return; } @@ -250,17 +338,33 @@ 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_error_at (type.get_locus (), "could not resolve type path %qs", - str.c_str ()); + // take care of only simple cases + // TODO: remove this? + rust_assert (!type.has_opening_scope_resolution_op ()); - DefaultResolver::visit (type); + // this *should* mostly work + // TODO: make sure typepath-like path resolution (?) is working + auto resolved = ctx.resolve_path (type.get_segments (), Namespace::Types); + + if (!resolved.has_value ()) + { + if (!ctx.lookup (type.get_segments ().front ()->get_node_id ())) + rust_error_at (type.get_locus (), "could not resolve type path %qs", + type.as_string ().c_str ()); + return; + } + + if (resolved->is_ambiguous ()) + { + rust_error_at (type.get_locus (), ErrorCode::E0659, "%qs is ambiguous", + type.as_string ().c_str ()); + return; + } + + ctx.map_usage (Usage (type.get_node_id ()), + Definition (resolved->get_node_id ())); } void @@ -286,7 +390,12 @@ Late::visit (AST::StructStruct &s) void Late::visit (AST::StructExprStruct &s) { - auto resolved = ctx.types.resolve_path (s.get_struct_name ().get_segments ()); + visit_outer_attrs (s); + visit_inner_attrs (s); + DefaultResolver::visit (s.get_struct_name ()); + + auto resolved + = ctx.resolve_path (s.get_struct_name ().get_segments (), Namespace::Types); ctx.map_usage (Usage (s.get_struct_name ().get_node_id ()), Definition (resolved->get_node_id ())); @@ -295,22 +404,34 @@ Late::visit (AST::StructExprStruct &s) void Late::visit (AST::StructExprStructBase &s) { - auto resolved = ctx.types.resolve_path (s.get_struct_name ().get_segments ()); + 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 ().get_segments (), 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.resolve_path (s.get_struct_name ().get_segments ()); + 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 ().get_segments (), 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 @@ -345,5 +466,31 @@ Late::visit (AST::GenericArg &arg) DefaultResolver::visit (arg); } +template <class Closure> +static void +add_captures (Closure &closure, NameResolutionContext &ctx) +{ + auto vals = ctx.values.peek ().get_values (); + for (auto &val : vals) + { + ctx.mappings.add_capture (closure.get_node_id (), + val.second.get_node_id ()); + } +} + +void +Late::visit (AST::ClosureExprInner &closure) +{ + add_captures (closure, ctx); + DefaultResolver::visit (closure); +} + +void +Late::visit (AST::ClosureExprInnerTyped &closure) +{ + add_captures (closure, ctx); + DefaultResolver::visit (closure); +} + } // 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 ade78c5..ac376b5 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 { @@ -45,6 +46,8 @@ public: // resolutions void visit (AST::IdentifierExpr &) override; + void visit (AST::StructExprFieldIdentifier &) override; + void visit (AST::BreakExpr &) override; void visit (AST::PathInExpression &) override; void visit (AST::TypePath &) override; void visit (AST::Trait &) override; @@ -54,10 +57,14 @@ public: void visit (AST::StructStruct &) override; void visit (AST::GenericArgs &) override; void visit (AST::GenericArg &); + void visit (AST::ClosureExprInner &) override; + void visit (AST::ClosureExprInnerTyped &) override; private: /* Setup Rust's builtin types (u8, i32, !...) in the resolver */ void setup_builtin_types (); + + bool funny_error; }; // TODO: Add missing mappings and data structures diff --git a/gcc/rust/resolve/rust-name-resolution-context.cc b/gcc/rust/resolve/rust-name-resolution-context.cc index 1b37521..92c4863 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.cc +++ b/gcc/rust/resolve/rust-name-resolution-context.cc @@ -46,6 +46,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) { @@ -107,6 +113,7 @@ NameResolutionContext::scoped (Rib::Kind rib_kind, NodeId id, std::function<void (void)> lambda, tl::optional<Identifier> 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); @@ -126,6 +133,9 @@ NameResolutionContext::scoped (Rib::Kind rib_kind, Namespace ns, 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: diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h index 183ce7f..ea81bde 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.h +++ b/gcc/rust/resolve/rust-name-resolution-context.h @@ -172,6 +172,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); @@ -216,6 +219,46 @@ public: tl::optional<NodeId> lookup (NodeId usage) const; + template <typename S> + tl::optional<Rib::Definition> resolve_path (const std::vector<S> &segments, + 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, insert_segment_resolution); + case Namespace::Types: + return types.resolve_path (segments, insert_segment_resolution); + case Namespace::Macros: + return macros.resolve_path (segments, insert_segment_resolution); + case Namespace::Labels: + return labels.resolve_path (segments, insert_segment_resolution); + default: + rust_unreachable (); + } + } + + template <typename S, typename... Args> + tl::optional<Rib::Definition> resolve_path (const std::vector<S> &segments, + Args... ns_args) + { + std::initializer_list<Namespace> namespaces = {ns_args...}; + + for (auto ns : namespaces) + { + if (auto ret = resolve_path (segments, ns)) + return ret; + } + + return tl::nullopt; + } + 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 0f5b108..dddaa07 100644 --- a/gcc/rust/resolve/rust-name-resolver.cc +++ b/gcc/rust/resolve/rust-name-resolver.cc @@ -472,6 +472,8 @@ 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); @@ -492,9 +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); @@ -674,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..c498328 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,42 @@ public: ForwardTypeParamBan, /* Const generic, as in the following example: fn foo<T, const X: T>() {} */ ConstParamType, + /* Prelude rib, used for both the language prelude (i32,usize,etc) and the + * (future) {std,core}::prelude::* import. A regular rib with the + * restriction that you cannot `use` items from the Prelude + */ + Prelude, } kind; + static std::string kind_to_string (Rib::Kind kind) + { + switch (kind) + { + case Rib::Kind::Normal: + return "Normal"; + case Rib::Kind::Module: + return "Module"; + case Rib::Kind::Function: + return "Function"; + case Rib::Kind::ConstantItem: + return "ConstantItem"; + case Rib::Kind::TraitOrImpl: + return "TraitOrImpl"; + case Rib::Kind::Item: + return "Item"; + case Rib::Kind::Closure: + return "Closure"; + case Rib::Kind::MacroDefinition: + return "Macro definition"; + case Rib::Kind::ForwardTypeParamBan: + return "Forward type param ban"; + case Rib::Kind::ConstParamType: + return "Const Param Type"; + default: + rust_unreachable (); + } + } + Rib (Kind kind); Rib (Kind kind, std::string identifier, NodeId id); Rib (Kind kind, std::unordered_map<std::string, NodeId> values); diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc index 4c6664f..8863be7 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) @@ -110,6 +138,8 @@ TopLevel::visit (AST::InherentImpl &impl) insert_or_error_out (Identifier ("Self", impl.get_type ().get_locus ()), impl.get_type (), Namespace::Types); + // We do want to visit with the default visitor instead of default resolver + // because we don't want to insert the scope twice. AST::DefaultASTVisitor::visit (impl); }; @@ -123,6 +153,8 @@ TopLevel::visit (AST::TraitImpl &impl) insert_or_error_out (Identifier ("Self", impl.get_type ().get_locus ()), impl.get_type (), Namespace::Types); + // We do want to visit using the default visitor instead of default resolver + // because we don't want to insert the scope twice. AST::DefaultASTVisitor::visit (impl); }; @@ -159,7 +191,16 @@ void TopLevel::visit (AST::ExternCrate &crate) { auto &mappings = Analysis::Mappings::get (); - CrateNum num = *mappings.lookup_crate_name (crate.get_referenced_crate ()); + auto num_opt = mappings.lookup_crate_name (crate.get_referenced_crate ()); + + if (!num_opt) + { + rust_error_at (crate.get_locus (), "unknown crate %qs", + crate.get_referenced_crate ().c_str ()); + return; + } + + CrateNum num = *num_opt; auto attribute_macros = mappings.lookup_attribute_proc_macros (num); @@ -323,19 +364,19 @@ TopLevel::visit (AST::TupleStruct &tuple_struct) void TopLevel::visit (AST::EnumItem &variant) { - insert_or_error_out (variant.get_identifier (), variant, Namespace::Types); + insert_enum_variant_or_error_out (variant.get_identifier (), variant); } void TopLevel::visit (AST::EnumItemTuple &variant) { - insert_or_error_out (variant.get_identifier (), variant, Namespace::Types); + insert_enum_variant_or_error_out (variant.get_identifier (), variant); } void TopLevel::visit (AST::EnumItemStruct &variant) { - insert_or_error_out (variant.get_identifier (), variant, Namespace::Types); + insert_enum_variant_or_error_out (variant.get_identifier (), variant); } void 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 fabcb5b..3ff37ed 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 |