From: Arthur Cohen <[email protected]>
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.
---
gcc/rust/resolve/rust-forever-stack.h | 30 +--
gcc/rust/resolve/rust-forever-stack.hxx | 214 ---------------
.../resolve/rust-name-resolution-context.h | 62 +++--
.../resolve/rust-name-resolution-context.hxx | 249 ++++++++++++++++++
4 files changed, 296 insertions(+), 259 deletions(-)
create mode 100644 gcc/rust/resolve/rust-name-resolution-context.hxx
diff --git a/gcc/rust/resolve/rust-forever-stack.h
b/gcc/rust/resolve/rust-forever-stack.h
index f6e351a1c4f..242b588a394 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 c7f90ae3a21..e3cd5b7add3 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 eac38eb62d6..c5b2d0b1c00 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 00000000000..ae89126153d
--- /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
--
2.50.1