https://gcc.gnu.org/g:41a3c8a9c31e4389f1238a75709bb7e8e7da76cf
commit r17-1078-g41a3c8a9c31e4389f1238a75709bb7e8e7da76cf Author: Arthur Cohen <[email protected]> Date: Mon Mar 23 05:36:16 2026 +0100 gccrs: nr: Move path resolution from ForeverStack to NRCtx gcc/rust/ChangeLog: * resolve/rust-forever-stack.h: Move declarations from ForeverStack to NRCtx, make most of the ForeverStack members public as it helps the Ctx a lot. * resolve/rust-forever-stack.hxx: Move implementation of resolve_path methods to NRCtx. * resolve/rust-name-resolution-context.h: Declare resolve_path methods. * resolve/rust-name-resolution-context.hxx: New file with resolve_path impls. Diff: --- gcc/rust/resolve/rust-forever-stack.h | 30 +-- gcc/rust/resolve/rust-forever-stack.hxx | 214 ------------------- gcc/rust/resolve/rust-name-resolution-context.h | 62 ++++-- gcc/rust/resolve/rust-name-resolution-context.hxx | 249 ++++++++++++++++++++++ 4 files changed, 296 insertions(+), 259 deletions(-) diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h index f6e351a1c4f7..242b588a3945 100644 --- a/gcc/rust/resolve/rust-forever-stack.h +++ b/gcc/rust/resolve/rust-forever-stack.h @@ -749,23 +749,6 @@ public: tl::optional<Rib::Definition> get_from_prelude (NodeId prelude, const Identifier &name); - /** - * Resolve a path to its definition in the current `ForeverStack` - * - * // TODO: Add documentation for `segments` - * - * @return a valid option with the Definition if the path is present in the - * current map, an empty one otherwise. - */ - tl::optional<Rib::Definition> resolve_path ( - const ResolutionPath &path, ResolutionMode mode, - std::function<void (Usage, Definition)> insert_segment_resolution, - std::vector<Error> &collect_errors); - tl::optional<Rib::Definition> resolve_path ( - const ResolutionPath &path, ResolutionMode mode, - std::function<void (Usage, Definition)> insert_segment_resolution, - std::vector<Error> &collect_errors, NodeId starting_point_id); - // FIXME: Documentation tl::optional<Rib &> to_rib (NodeId rib_id); tl::optional<const Rib &> to_rib (NodeId rib_id) const; @@ -778,7 +761,6 @@ public: */ bool is_module_descendant (NodeId parent, NodeId child) const; -private: /** * A link between two Nodes in our trie data structure. This class represents * the edges of the graph @@ -826,18 +808,8 @@ private: tl::optional<Node &> parent; // `None` only if the node is a root }; - /** - * Private overloads which allow specifying a starting point - */ - tl::optional<Rib::Definition> get (Node &start, const Identifier &name); - tl::optional<Rib::Definition> resolve_path ( - const ResolutionPath &path, ResolutionMode mode, - std::function<void (Usage, Definition)> insert_segment_resolution, - std::vector<Error> &collect_errors, - std::reference_wrapper<Node> starting_point); - /* Should we keep going upon seeing a Rib? */ enum class KeepGoing { @@ -859,6 +831,7 @@ private: Node &cursor (); const Node &cursor () const; + void update_cursor (Node &new_cursor); /* The forever stack's actual nodes */ @@ -930,7 +903,6 @@ private: tl::optional<const Node &> dfs_node (const Node &starting_point, NodeId to_find) const; -public: bool forward_declared (NodeId definition, NodeId usage) { if (peek ().kind != Rib::Kind::ForwardTypeParamBan) diff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx index c7f90ae3a216..e3cd5b7add3b 100644 --- a/gcc/rust/resolve/rust-forever-stack.hxx +++ b/gcc/rust/resolve/rust-forever-stack.hxx @@ -667,220 +667,6 @@ ForeverStack<N>::resolve_final_segment (Node &final_node, std::string &seg_name, return final_node.rib.get (seg_name); } -template <Namespace N> -tl::optional<Rib::Definition> -ForeverStack<N>::resolve_path ( - const ResolutionPath &path, ResolutionMode mode, - std::function<void (Usage, Definition)> insert_segment_resolution, - std::vector<Error> &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 (path, mode, insert_segment_resolution, collect_errors, - *starting_point); -} - -template <Namespace N> -tl::optional<Rib::Definition> -ForeverStack<N>::resolve_path ( - const ResolutionPath &path, ResolutionMode mode, - std::function<void (Usage, Definition)> insert_segment_resolution, - std::vector<Error> &collect_errors) -{ - std::reference_wrapper<Node> starting_point = cursor (); - - return resolve_path (path, mode, insert_segment_resolution, collect_errors, - starting_point); -} - -template <Namespace N> -tl::optional<Rib::Definition> -ForeverStack<N>::resolve_path ( - const ResolutionPath &path, ResolutionMode mode, - std::function<void (Usage, Definition)> insert_segment_resolution, - std::vector<Error> &collect_errors, - std::reference_wrapper<Node> starting_point) -{ - bool can_descend = true; - - rust_debug ("resolving %s", path.as_string ().c_str ()); - - if (auto lang_item = path.get_lang_prefix ()) - { - NodeId seg_id - = Analysis::Mappings::get ().get_lang_item_node (lang_item->first); - - insert_segment_resolution (Usage (lang_item->second), - Definition (seg_id)); - - if (path.get_segments ().empty ()) - return Rib::Definition::NonShadowable (seg_id); - - auto new_start = dfs_node (root, seg_id); - rust_assert (new_start.has_value ()); - starting_point = new_start.value (); - - can_descend = false; - } - else - { - switch (mode) - { - case ResolutionMode::Normal: - break; // default - case ResolutionMode::FromRoot: - starting_point = root; - break; - case ResolutionMode::FromExtern: - starting_point = extern_prelude; - break; - default: - rust_unreachable (); - } - } - - if (path.get_segments ().empty ()) - { - return Rib::Definition::NonShadowable (starting_point.get ().id); - } - - auto &segments = path.get_segments (); - - // if there's only one segment, we just use `get` - if (can_descend && segments.size () == 1) - { - auto &seg = segments.front (); - - tl::optional<Rib::Definition> res = get (starting_point.get (), seg.name); - - if (!res) - res = get_lang_prelude (seg.name); - - if (N == Namespace::Types && !res) - { - if (seg.is_crate_path_seg ()) - { - insert_segment_resolution (Usage (seg.node_id), - Definition (root.id)); - // TODO: does NonShadowable matter? - return Rib::Definition::NonShadowable (root.id); - } - else if (seg.is_lower_self_seg ()) - { - NodeId id = find_closest_module (starting_point.get ()).id; - insert_segment_resolution (Usage (seg.node_id), Definition (id)); - // TODO: does NonShadowable matter? - return Rib::Definition::NonShadowable (id); - } - else if (seg.is_super_path_seg ()) - { - Node &closest_module - = find_closest_module (starting_point.get ()); - if (closest_module.is_root ()) - { - rust_error_at (seg.locus, ErrorCode::E0433, - "too many leading %<super%> keywords"); - return tl::nullopt; - } - - NodeId id - = find_closest_module (closest_module.parent.value ()).id; - insert_segment_resolution (Usage (seg.node_id), Definition (id)); - // TODO: does NonShadowable matter? - return Rib::Definition::NonShadowable (id); - } - else - { - // HACK: check for a module after we check the language prelude - for (auto &kv : - find_closest_module (starting_point.get ()).children) - { - auto &link = kv.first; - - if (link.path.map_or ( - [&seg] (Identifier path) { - auto &path_str = path.as_string (); - return path_str == seg.name; - }, - false)) - { - insert_segment_resolution (Usage (seg.node_id), - Definition (kv.second.id)); - return Rib::Definition::NonShadowable (kv.second.id); - } - } - } - } - - if (res && !res->is_ambiguous ()) - insert_segment_resolution (Usage (seg.node_id), - Definition (res->get_node_id ())); - return res; - } - - auto iterator = segments.begin (); - if (can_descend) - { - if (auto res - = find_starting_point (segments, starting_point, - insert_segment_resolution, collect_errors)) - iterator = *res; - else - return tl::nullopt; - } - - return resolve_segments (starting_point.get (), segments, iterator, - insert_segment_resolution, collect_errors) - .and_then ([this, &segments, &insert_segment_resolution] ( - Node &final_node) -> tl::optional<Rib::Definition> { - // leave resolution within impl blocks to type checker - if (final_node.rib.kind == Rib::Kind::TraitOrImpl) - return tl::nullopt; - - auto &seg = segments.back (); - std::string seg_name = seg.name; - - tl::optional<Rib::Definition> res - = resolve_final_segment (final_node, seg_name, - seg.is_lower_self_seg ()); - // Ok we didn't find it in the rib, Lets try the prelude... - if (!res) - res = get_lang_prelude (seg_name); - - if (N == Namespace::Types && !res) - { - // HACK: check for a module after we check the language prelude - for (auto &kv : final_node.children) - { - auto &link = kv.first; - - if (link.path.map_or ( - [&seg_name] (Identifier path) { - auto &path_str = path.as_string (); - return path_str == seg_name; - }, - false)) - { - insert_segment_resolution (Usage (seg.node_id), - Definition (kv.second.id)); - return Rib::Definition::NonShadowable (kv.second.id); - } - } - } - - if (res && !res->is_ambiguous ()) - insert_segment_resolution (Usage (seg.node_id), - Definition (res->get_node_id ())); - - return res; - }); -} - template <Namespace N> tl::optional<typename ForeverStack<N>::DfsResult> ForeverStack<N>::dfs (ForeverStack<N>::Node &starting_point, NodeId to_find) diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h index eac38eb62d61..c5b2d0b1c00c 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.h +++ b/gcc/rust/resolve/rust-name-resolution-context.h @@ -543,20 +543,20 @@ public: switch (ns) { case Namespace::Values: - resolved = values.resolve_path (path, mode, insert_segment_resolution, - collect_errors); + resolved = resolve_path (values, path, mode, insert_segment_resolution, + collect_errors); break; case Namespace::Types: - resolved = types.resolve_path (path, mode, insert_segment_resolution, - collect_errors); + resolved = resolve_path (types, path, mode, insert_segment_resolution, + collect_errors); break; case Namespace::Macros: - resolved = macros.resolve_path (path, mode, insert_segment_resolution, - collect_errors); + resolved = resolve_path (macros, path, mode, insert_segment_resolution, + collect_errors); break; case Namespace::Labels: - resolved = labels.resolve_path (path, mode, insert_segment_resolution, - collect_errors); + resolved = resolve_path (labels, path, mode, insert_segment_resolution, + collect_errors); break; default: rust_unreachable (); @@ -569,17 +569,17 @@ public: switch (ns) { case Namespace::Values: - return values.resolve_path (path, mode, insert_segment_resolution, - collect_errors, *prelude); + return resolve_path (values, path, mode, insert_segment_resolution, + collect_errors, *prelude); case Namespace::Types: - return types.resolve_path (path, mode, insert_segment_resolution, - collect_errors, *prelude); + return resolve_path (types, path, mode, insert_segment_resolution, + collect_errors, *prelude); case Namespace::Macros: - return macros.resolve_path (path, mode, insert_segment_resolution, - collect_errors, *prelude); + return resolve_path (macros, path, mode, insert_segment_resolution, + collect_errors, *prelude); case Namespace::Labels: - return labels.resolve_path (path, mode, insert_segment_resolution, - collect_errors, *prelude); + return resolve_path (labels, path, mode, insert_segment_resolution, + collect_errors, *prelude); default: rust_unreachable (); } @@ -774,6 +774,34 @@ public: std::forward<Args> (args)...); } + /** + * Resolve a path to its definition in the current `ForeverStack` + * + * // TODO: Add documentation for `segments` + * + * @return a valid option with the Definition if the path is present in the + * current map, an empty one otherwise. + */ + template <Namespace N> + tl::optional<Rib::Definition> resolve_path ( + ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode, + std::function<void (Usage, Definition)> insert_segment_resolution, + std::vector<Error> &collect_errors); + + template <Namespace N> + tl::optional<Rib::Definition> resolve_path ( + ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode, + std::function<void (Usage, Definition)> insert_segment_resolution, + std::vector<Error> &collect_errors, NodeId starting_point_id); + + /* TODO: Make private? */ + template <Namespace N> + tl::optional<Rib::Definition> resolve_path ( + ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode, + std::function<void (Usage, Definition)> insert_segment_resolution, + std::vector<Error> &collect_errors, + std::reference_wrapper<typename ForeverStack<N>::Node> starting_point); + /* If declared with #[prelude_import], the current standard library module */ tl::optional<NodeId> prelude; @@ -785,4 +813,6 @@ private: } // namespace Resolver2_0 } // namespace Rust +#include "rust-name-resolution-context.hxx" + #endif // ! RUST_NAME_RESOLVER_2_0_CTX_H diff --git a/gcc/rust/resolve/rust-name-resolution-context.hxx b/gcc/rust/resolve/rust-name-resolution-context.hxx new file mode 100644 index 000000000000..ae89126153de --- /dev/null +++ b/gcc/rust/resolve/rust-name-resolution-context.hxx @@ -0,0 +1,249 @@ +// Copyright (C) 2026 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-name-resolution-context.h" + +/** + * Split the actual path resolution logic in its own file because it's a lot, + * and it could get even worse for certain edge cases. + */ + +namespace Rust { +namespace Resolver2_0 { + +template <Namespace N> +tl::optional<Rib::Definition> +NameResolutionContext::resolve_path ( + ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode, + std::function<void (Usage, Definition)> insert_segment_resolution, + std::vector<Error> &collect_errors) +{ + std::reference_wrapper<typename ForeverStack<N>::Node> starting_point + = stack.cursor (); + + return NameResolutionContext::resolve_path (stack, path, mode, + insert_segment_resolution, + collect_errors, starting_point); +} + +template <Namespace N> +tl::optional<Rib::Definition> +NameResolutionContext::resolve_path ( + ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode, + std::function<void (Usage, Definition)> insert_segment_resolution, + std::vector<Error> &collect_errors, NodeId starting_point_id) + +{ + auto starting_point = stack.dfs_node (stack.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 NameResolutionContext::resolve_path (stack, path, mode, + insert_segment_resolution, + collect_errors, *starting_point); +} + +template <Namespace N> +tl::optional<Rib::Definition> +NameResolutionContext::resolve_path ( + ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode, + std::function<void (Usage, Definition)> insert_segment_resolution, + std::vector<Error> &collect_errors, + std::reference_wrapper<typename ForeverStack<N>::Node> starting_point) +{ + bool can_descend = true; + + rust_debug ("resolving %s", path.as_string ().c_str ()); + + if (auto lang_item = path.get_lang_prefix ()) + { + NodeId seg_id + = Analysis::Mappings::get ().get_lang_item_node (lang_item->first); + + insert_segment_resolution (Usage (lang_item->second), + Definition (seg_id)); + + if (path.get_segments ().empty ()) + return Rib::Definition::NonShadowable (seg_id); + + auto new_start = stack.dfs_node (stack.root, seg_id); + rust_assert (new_start.has_value ()); + starting_point = new_start.value (); + + can_descend = false; + } + else + { + switch (mode) + { + case ResolutionMode::Normal: + break; // default + case ResolutionMode::FromRoot: + starting_point = stack.root; + break; + case ResolutionMode::FromExtern: + starting_point = stack.extern_prelude; + break; + default: + rust_unreachable (); + } + } + + if (path.get_segments ().empty ()) + return Rib::Definition::NonShadowable (starting_point.get ().id); + + auto &segments = path.get_segments (); + + // if there's only one segment, we just use `get` + if (can_descend && segments.size () == 1) + { + auto &seg = segments.front (); + + tl::optional<Rib::Definition> res + = stack.get (starting_point.get (), seg.name); + + if (!res) + res = stack.get_lang_prelude (seg.name); + + if (N == Namespace::Types && !res) + { + if (seg.is_crate_path_seg ()) + { + insert_segment_resolution (Usage (seg.node_id), + Definition (stack.root.id)); + // TODO: does NonShadowable matter? + return Rib::Definition::NonShadowable (stack.root.id); + } + else if (seg.is_lower_self_seg ()) + { + NodeId id = stack.find_closest_module (starting_point.get ()).id; + insert_segment_resolution (Usage (seg.node_id), Definition (id)); + // TODO: does NonShadowable matter? + return Rib::Definition::NonShadowable (id); + } + else if (seg.is_super_path_seg ()) + { + auto &closest_module + = stack.find_closest_module (starting_point.get ()); + if (closest_module.is_root ()) + { + rust_error_at (seg.locus, ErrorCode::E0433, + "too many leading %<super%> keywords"); + return tl::nullopt; + } + + NodeId id + = stack.find_closest_module (closest_module.parent.value ()).id; + insert_segment_resolution (Usage (seg.node_id), Definition (id)); + // TODO: does NonShadowable matter? + return Rib::Definition::NonShadowable (id); + } + else + { + // HACK: check for a module after we check the language prelude + for (auto &kv : + stack.find_closest_module (starting_point.get ()).children) + { + auto &link = kv.first; + + if (link.path.map_or ( + [&seg] (Identifier path) { + auto &path_str = path.as_string (); + return path_str == seg.name; + }, + false)) + { + insert_segment_resolution (Usage (seg.node_id), + Definition (kv.second.id)); + return Rib::Definition::NonShadowable (kv.second.id); + } + } + } + } + + if (res && !res->is_ambiguous ()) + insert_segment_resolution (Usage (seg.node_id), + Definition (res->get_node_id ())); + return res; + } + + auto iterator = segments.begin (); + if (can_descend) + { + if (auto res = stack.find_starting_point (segments, starting_point, + insert_segment_resolution, + collect_errors)) + iterator = *res; + else + return tl::nullopt; + } + + return stack + .resolve_segments (starting_point.get (), segments, iterator, + insert_segment_resolution, collect_errors) + .and_then ([&segments, &insert_segment_resolution, + &stack] (typename ForeverStack<N>::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 = segments.back (); + std::string seg_name = seg.name; + + tl::optional<Rib::Definition> res + = stack.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 = stack.get_lang_prelude (seg_name); + + if (N == Namespace::Types && !res) + { + // HACK: check for a module after we check the language prelude + for (auto &kv : final_node.children) + { + auto &link = kv.first; + + if (link.path.map_or ( + [&seg_name] (Identifier path) { + auto &path_str = path.as_string (); + return path_str == seg_name; + }, + false)) + { + insert_segment_resolution (Usage (seg.node_id), + Definition (kv.second.id)); + return Rib::Definition::NonShadowable (kv.second.id); + } + } + } + + if (res && !res->is_ambiguous ()) + insert_segment_resolution (Usage (seg.node_id), + Definition (res->get_node_id ())); + + return res; + }); +} + +} // namespace Resolver2_0 +} // namespace Rust
