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 0dff8315331..fb63b0edbac 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc @@ -410,6 +410,14 @@ Early::finalize_glob_import (NameResolutionContext &ctx, rust_assert (container); + if (mapping.import_kind.is_prelude) + { + rust_assert (container.value ()->get_item_kind () + == AST::Item::Kind::Module); + + ctx.prelude = container.value ()->get_node_id (); + } + GlobbingVisitor (ctx).go (container.value ()); } diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h index 75dd87395be..4e6e433e407 100644 --- a/gcc/rust/resolve/rust-forever-stack.h +++ b/gcc/rust/resolve/rust-forever-stack.h @@ -668,6 +668,8 @@ template class ForeverStack tl::optional get (const Identifier &name); tl::optional get_lang_prelude (const Identifier &name); tl::optional get_lang_prelude (const std::string &name); + tl::optional get_from_prelude (NodeId prelude, + const Identifier &name); /** * Resolve a path to its definition in the current `ForeverStack` @@ -682,6 +684,11 @@ template class ForeverStack const std::vector &segments, ResolutionMode mode, std::function insert_segment_resolution, std::vector &collect_errors); + template + tl::optional resolve_path ( + const std::vector &segments, ResolutionMode mode, + std::function insert_segment_resolution, + std::vector &collect_errors, NodeId starting_point_id); // FIXME: Documentation tl::optional to_rib (NodeId rib_id); @@ -743,9 +750,19 @@ template class ForeverStack tl::optional parent; // `None` only if the node is a root }; - // private overload which allows specifying a starting point + /** + * Private overloads which allow specifying a starting point + */ + tl::optional get (Node &start, const Identifier &name); + template + tl::optional resolve_path ( + const std::vector &segments, ResolutionMode mode, + std::function insert_segment_resolution, + std::vector &collect_errors, + std::reference_wrapper starting_point); + /* Should we keep going upon seeing a Rib? */ enum class KeepGoing { @@ -777,6 +794,7 @@ template class ForeverStack * resolution */ Node lang_prelude; + /* * The extern prelude, used for resolving external crates */ diff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx index 848f5e61522..ffdfb871155 100644 --- a/gcc/rust/resolve/rust-forever-stack.hxx +++ b/gcc/rust/resolve/rust-forever-stack.hxx @@ -343,6 +343,17 @@ ForeverStack::get_lang_prelude (const std::string &name) return lang_prelude.rib.get (name); } +template +tl::optional +ForeverStack::get_from_prelude (NodeId prelude, const Identifier &name) +{ + auto starting_point = dfs_node (root, prelude); + if (!starting_point) + return tl::nullopt; + + return get (*starting_point, name); +} + template <> tl::optional inline ForeverStack::get ( const Identifier &name) @@ -647,6 +658,25 @@ ForeverStack::resolve_final_segment (Node &final_node, std::string &seg_name, return final_node.rib.get (seg_name); } +template +template +tl::optional +ForeverStack::resolve_path ( + const std::vector &segments, ResolutionMode mode, + std::function insert_segment_resolution, + std::vector &collect_errors, NodeId starting_point_id) +{ + auto starting_point = dfs_node (root, starting_point_id); + + // We may have a prelude, but haven't visited it yet and thus it's not in our + // nodes + if (!starting_point) + return tl::nullopt; + + return resolve_path (segments, mode, insert_segment_resolution, + collect_errors, *starting_point); +} + template template tl::optional @@ -654,10 +684,24 @@ ForeverStack::resolve_path ( const std::vector &segments, ResolutionMode mode, std::function insert_segment_resolution, std::vector &collect_errors) +{ + std::reference_wrapper starting_point = cursor (); + + return resolve_path (segments, mode, insert_segment_resolution, + collect_errors, starting_point); +} + +template +template +tl::optional +ForeverStack::resolve_path ( + const std::vector &segments, ResolutionMode mode, + std::function insert_segment_resolution, + std::vector &collect_errors, + std::reference_wrapper starting_point) { rust_assert (!segments.empty ()); - std::reference_wrapper starting_point = cursor (); switch (mode) { case ResolutionMode::Normal: 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 96b38f48e4e..f87f2515e14 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc @@ -348,7 +348,17 @@ Late::visit (AST::IdentifierExpr &expr) { resolved = type; } - else + else if (!resolved && ctx.prelude) + { + resolved + = ctx.values.get_from_prelude (*ctx.prelude, expr.get_ident ()); + + if (!resolved) + resolved + = ctx.types.get_from_prelude (*ctx.prelude, expr.get_ident ()); + } + + if (!resolved) { rust_error_at (expr.get_locus (), ErrorCode::E0425, "cannot find value %qs in this scope", diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h index 558b3cab664..1abcd6456c8 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.h +++ b/gcc/rust/resolve/rust-name-resolution-context.h @@ -560,23 +560,65 @@ class NameResolutionContext if (resolved_nodes.find (Usage (seg_id)) == resolved_nodes.end ()) map_usage (Usage (seg_id), Definition (id)); }; + + tl::optional resolved = tl::nullopt; + switch (ns) { case Namespace::Values: - return values.resolve_path (segments, mode, insert_segment_resolution, - collect_errors); + resolved + = values.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); + break; case Namespace::Types: - return types.resolve_path (segments, mode, insert_segment_resolution, - collect_errors); + resolved + = types.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); + break; case Namespace::Macros: - return macros.resolve_path (segments, mode, insert_segment_resolution, - collect_errors); + resolved + = macros.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); + break; case Namespace::Labels: - return labels.resolve_path (segments, mode, insert_segment_resolution, - collect_errors); + resolved + = labels.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); + break; default: rust_unreachable (); } + + // If it fails, switch to std prelude resolution if it exists + if (prelude && !resolved) + { + std::vector ignore_errors = {}; + + // TODO: Factor this with the above + switch (ns) + { + case Namespace::Values: + return values.resolve_path (segments, mode, + insert_segment_resolution, + ignore_errors, *prelude); + case Namespace::Types: + return types.resolve_path (segments, mode, + insert_segment_resolution, ignore_errors, + *prelude); + case Namespace::Macros: + return macros.resolve_path (segments, mode, + insert_segment_resolution, + ignore_errors, *prelude); + case Namespace::Labels: + return labels.resolve_path (segments, mode, + insert_segment_resolution, + ignore_errors, *prelude); + default: + rust_unreachable (); + } + } + + return resolved; } template @@ -676,6 +718,9 @@ class NameResolutionContext std::forward (args)...); } + /* If declared with #[prelude_import], the current standard library module */ + tl::optional prelude; + private: /* Map of "usage" nodes which have been resolved to a "definition" node */ std::map resolved_nodes; 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 0930f966e20..dcd1592a837 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc @@ -496,6 +496,16 @@ flatten_glob (const AST::UseTreeGlob &glob, std::vector &paths, paths.emplace_back (AST::SimplePath ({}, false, glob.get_locus ())); } +static bool +has_prelude_import (const std::vector &attributes) +{ + for (const auto &attr : attributes) + if (attr.get_path ().as_string () == "prelude_import") + return true; + + return false; +} + void TopLevel::visit (AST::UseDeclaration &use) { @@ -523,7 +533,8 @@ TopLevel::visit (AST::UseDeclaration &use) for (auto &&glob : glob_path) imports.emplace_back ( - ImportKind::Glob (std::move (glob), values_rib, types_rib, macros_rib)); + ImportKind::Glob (std::move (glob), values_rib, types_rib, macros_rib, + has_prelude_import (use.get_outer_attrs ()))); for (auto &&rebind : rebind_path) imports.emplace_back ( 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 8d3da92961a..fca1b368b16 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h @@ -67,10 +67,10 @@ class TopLevel : public DefaultResolver } kind; static ImportKind Glob (AST::SimplePath &&to_resolve, Rib &values_rib, - Rib &types_rib, Rib ¯os_rib) + Rib &types_rib, Rib ¯os_rib, bool is_prelude) { return ImportKind (Kind::Glob, std::move (to_resolve), values_rib, - types_rib, macros_rib); + types_rib, macros_rib, is_prelude); } static ImportKind Simple (AST::SimplePath &&to_resolve, Rib &values_rib, @@ -84,8 +84,10 @@ class TopLevel : public DefaultResolver AST::UseTreeRebind &&rebind, Rib &values_rib, Rib &types_rib, Rib ¯os_rib) { - return ImportKind (Kind::Rebind, std::move (to_resolve), values_rib, - types_rib, macros_rib, std::move (rebind)); + return ImportKind ( + Kind::Rebind, std::move (to_resolve), values_rib, types_rib, macros_rib, + false /* is_prelude: rebind imports can never be preludes */, + std::move (rebind)); } // The path for `Early` to resolve. @@ -98,13 +100,17 @@ class TopLevel : public DefaultResolver Rib &types_rib; Rib ¯os_rib; + // Can only be true if we are dealing with a glob import with the + // #[prelude_import] attribute + bool is_prelude = false; + private: ImportKind (Kind kind, AST::SimplePath &&to_resolve, Rib &values_rib, - Rib &types_rib, Rib ¯os_rib, + Rib &types_rib, Rib ¯os_rib, bool is_prelude = false, tl::optional &&rebind = tl::nullopt) : kind (kind), to_resolve (std::move (to_resolve)), rebind (std::move (rebind)), values_rib (values_rib), - types_rib (types_rib), macros_rib (macros_rib) + types_rib (types_rib), macros_rib (macros_rib), is_prelude (is_prelude) {} };