From: Owen Avery <[email protected]>
Each ForeverStack builds a tree of nodes. Since we already assume that
nodes in one ForeverStack map one-to-one with nodes in another
ForeverStack, we can have multiple ForeverStack instances share the same
set of nodes.
gcc/rust/ChangeLog:
* resolve/rust-forever-stack.h (ForeverStackBase::Node::Node):
Initialize all namespace ribs with a Rib::Kind.
(ForeverStackBase::Node::rib): Replace member variable with member
function taking namespace.
(ForeverStackBase::Node::rib_values): New member variable.
(ForeverStackBase::Node::rib_types): New member variable.
(ForeverStackBase::Node::rib_labels): New member variable.
(ForeverStackBase::Node::rib_macros): New member variable.
(ForeverStackBase::ForeverStackBase): New constructor taking
references to top-level nodes.
(ForeverStack::root): Move member variable to...
(ForeverStackBase::root): ...here and make it a reference.
(ForeverStack::lang_prelude): Move member variable to...
(ForeverStackBase::lang_prelude): ...here and make it a
reference.
(ForeverStack::extern_prelude): Move member variable to...
(ForeverStackBase::extern_prelude): ...here and make it a
reference.
(ForeverStack::ForeverStack): Initialize ForeverStackBase
and take top-level nodes as by-reference arguments.
(ForeverStack::push_inner): Take Rib::Kind instead of Rib.
* resolve/rust-forever-stack.hxx (ForeverStackBase::is_prelude):
Use value rib to get rib kind.
(ForeverStack::push_inner): Take Rib::Kind instead of Rib.
(ForeverStack::pop): Use namespace specific ribs.
(ForeverStack::insert_at_root): Likewise.
(ForeverStack::insert_lang_prelude): Likewise.
(ForeverStack::peek): Likewise.
(ForeverStack::get): Likewise.
(ForeverStack::get_lang_prelude): Likewise.
(ForeverStack::find_closest_module): Likewise.
(ForeverStack::dfs): Likewise.
(ForeverStack::dfs_rib): Likewise.
(ForeverStack::stream_node): Likewise.
* resolve/rust-name-resolution-context.cc
(NameResolutionContext::merge): Likewise.
(NameResolutionContext::NameResolutionContext): Initialize
top-level nodes and construct ForeverStack instances with
references.
* resolve/rust-name-resolution-context.h
(NameResolutionContext::Node): New type alias to
ForeverStackBase::Node.
(NameResolutionContext::root): New member variable.
(NameResolutionContext::lang_prelude): New member variable.
(NameResolutionContext::extern_prelude): New member variable.
* resolve/rust-name-resolution-context.hxx
(NameResolutionContext::should_search_prelude): Use namespace
specific rib.
(NameResolutionContext::resolve_path): Simplify mapping to and
from type namespace nodes (now a no-op). Also, use namespace
specific ribs for looking up final segments.
(NameResolutionContext::resolve_segments): Use namespace
specific ribs.
(NameResolutionContext::resolve_final_segment): Likewise.
Signed-off-by: Owen Avery <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.
Commit on github:
https://github.com/Rust-GCC/gccrs/commit/836bd832f52d2becdfaf6c2103cada5bf7054e1b
The commit has NOT been mentioned in any issue.
The commit has been mentioned in the following pull-request(s):
- https://github.com/Rust-GCC/gccrs/pull/4658
gcc/rust/resolve/rust-forever-stack.h | 80 +++++++++++++------
gcc/rust/resolve/rust-forever-stack.hxx | 46 +++++------
.../resolve/rust-name-resolution-context.cc | 27 +++++--
.../resolve/rust-name-resolution-context.h | 6 ++
.../resolve/rust-name-resolution-context.hxx | 35 +++-----
5 files changed, 117 insertions(+), 77 deletions(-)
diff --git a/gcc/rust/resolve/rust-forever-stack.h
b/gcc/rust/resolve/rust-forever-stack.h
index 823868218..0f95d0d73 100644
--- a/gcc/rust/resolve/rust-forever-stack.h
+++ b/gcc/rust/resolve/rust-forever-stack.h
@@ -515,10 +515,36 @@ public:
class Node
{
public:
- Node (Rib rib, NodeId id) : rib (rib), id (id) {}
- Node (Rib rib, NodeId id, Node &parent)
- : rib (rib), id (id), parent (parent)
+ Node (Rib::Kind rib_kind, NodeId id)
+ : rib_values (rib_kind), rib_types (rib_kind), rib_labels (rib_kind),
+ rib_macros (rib_kind), id (id)
{}
+ Node (Rib::Kind rib_kind, NodeId id, Node &parent)
+ : rib_values (rib_kind), rib_types (rib_kind), rib_labels (rib_kind),
+ rib_macros (rib_kind), id (id), parent (parent)
+ {}
+
+ const Rib &rib (Namespace n) const
+ {
+ switch (n)
+ {
+ case Namespace::Values:
+ return rib_values;
+ case Namespace::Types:
+ return rib_types;
+ case Namespace::Labels:
+ return rib_labels;
+ case Namespace::Macros:
+ return rib_macros;
+ default:
+ rust_unreachable ();
+ }
+ }
+
+ Rib &rib (Namespace n)
+ {
+ return const_cast<Rib &> (const_cast<const Node *> (this)->rib (n));
+ }
inline bool is_root () const;
inline bool is_prelude () const;
@@ -526,22 +552,44 @@ public:
inline void insert_child (Link link, Node child);
- Rib rib; // this is the "value" of the node - the data it keeps.
+ // these are the "values" of the node - the data it keeps.
+ Rib rib_values;
+ Rib rib_types;
+ Rib rib_labels;
+ Rib rib_macros;
+
std::map<Link, Node, LinkCmp> children; // all the other nodes it links to
NodeId id; // The node id of the Node's scope
tl::optional<Node &> parent; // `None` only if the node is a root
};
+
+ ForeverStackBase (Node &root, Node &lang_prelude, Node &extern_prelude)
+ : root (root), lang_prelude (lang_prelude), extern_prelude (extern_prelude)
+ {}
+
+ /* The forever stack's actual nodes */
+ Node &root;
+
+ /*
+ * A special prelude node used currently for resolving language builtins
+ * It has the root node as a parent, and acts as a "special case" for name
+ * resolution
+ */
+ Node &lang_prelude;
+
+ /*
+ * The extern prelude, used for resolving external crates
+ */
+ Node &extern_prelude;
};
template <Namespace N> class ForeverStack : public ForeverStackBase
{
public:
- ForeverStack ()
- : root (Node (Rib (Rib::Kind::Normal), UNKNOWN_NODEID)),
- lang_prelude (Node (Rib (Rib::Kind::Prelude), UNKNOWN_NODEID, root)),
- extern_prelude (Node (Rib (Rib::Kind::Prelude), UNKNOWN_NODEID)),
+ ForeverStack (Node &root, Node &lang_prelude, Node &extern_prelude)
+ : ForeverStackBase (root, lang_prelude, extern_prelude),
cursor_reference (root)
{
rust_assert (root.is_root ());
@@ -686,7 +734,7 @@ public:
};
/* Add a new Rib to the stack. This is an internal method */
- void push_inner (Rib rib, Link link);
+ void push_inner (Rib::Kind rib, Link link);
/* Reverse iterate on `Node`s from the cursor, in an outwards fashion */
void reverse_iter (std::function<KeepGoing (Node &)> lambda);
@@ -702,20 +750,6 @@ public:
void update_cursor (Node &new_cursor);
- /* The forever stack's actual nodes */
- Node root;
- /*
- * A special prelude node used currently for resolving language builtins
- * It has the root node as a parent, and acts as a "special case" for name
- * resolution
- */
- Node lang_prelude;
-
- /*
- * The extern prelude, used for resolving external crates
- */
- Node extern_prelude;
-
std::reference_wrapper<Node> cursor_reference;
void stream_rib (std::stringstream &stream, const Rib &rib,
diff --git a/gcc/rust/resolve/rust-forever-stack.hxx
b/gcc/rust/resolve/rust-forever-stack.hxx
index 3ed6692ff..1b654c952 100644
--- a/gcc/rust/resolve/rust-forever-stack.hxx
+++ b/gcc/rust/resolve/rust-forever-stack.hxx
@@ -37,7 +37,7 @@ ForeverStackBase::Node::is_root () const
bool
ForeverStackBase::Node::is_prelude () const
{
- return rib.kind == Rib::Kind::Prelude;
+ return rib_values.kind == Rib::Kind::Prelude;
}
bool
@@ -65,9 +65,9 @@ ForeverStack<N>::push (Rib::Kind rib_kind, NodeId id,
template <Namespace N>
void
-ForeverStack<N>::push_inner (Rib rib, Link link)
+ForeverStack<N>::push_inner (Rib::Kind rib_kind, Link link)
{
- if (rib.kind == Rib::Kind::Prelude)
+ 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.
@@ -83,7 +83,7 @@ ForeverStack<N>::push_inner (Rib rib, Link link)
// points to it. Otherwise, it points to the newly emplaced value, so we can
// just update our cursor().
auto emplace = cursor ().children.emplace (
- std::make_pair (link, Node (rib, link.id, cursor ())));
+ std::make_pair (link, Node (rib_kind, link.id, cursor ())));
auto it = emplace.first;
auto existed = !emplace.second;
@@ -105,12 +105,12 @@ ForeverStack<N>::pop ()
rust_debug ("popping link");
- for (const auto &kv : cursor ().rib.get_values ())
+ for (const auto &kv : cursor ().rib (N).get_values ())
rust_debug ("current_rib: k: %s, v: %s", kv.first.c_str (),
kv.second.to_string ().c_str ());
if (cursor ().parent.has_value ())
- for (const auto &kv : cursor ().parent.value ().rib.get_values ())
+ for (const auto &kv : cursor ().parent.value ().rib (N).get_values ())
rust_debug ("new cursor: k: %s, v: %s", kv.first.c_str (),
kv.second.to_string ().c_str ());
@@ -161,7 +161,7 @@ template <Namespace N>
tl::expected<NodeId, DuplicateNameError>
ForeverStack<N>::insert_at_root (Identifier name, NodeId node)
{
- auto &root_rib = root.rib;
+ auto &root_rib = root.rib (N);
// inserting in the root of the crate is never a shadowing operation, even
for
// macros
@@ -207,7 +207,7 @@ template <Namespace N>
inline void
ForeverStack<N>::insert_lang_prelude (Identifier name, NodeId id)
{
- insert_inner (lang_prelude.rib, name.as_string (),
+ insert_inner (lang_prelude.rib (N), name.as_string (),
Rib::Definition::NonShadowable (id, false));
}
@@ -215,14 +215,14 @@ template <Namespace N>
Rib &
ForeverStack<N>::peek ()
{
- return cursor ().rib;
+ return cursor ().rib (N);
}
template <Namespace N>
const Rib &
ForeverStack<N>::peek () const
{
- return cursor ().rib;
+ return cursor ().rib (N);
}
template <Namespace N>
@@ -310,10 +310,10 @@ ForeverStack<N>::get (Node &start, const Identifier &name)
// TODO: Can we improve the API? have `reverse_iter` return an optional?
reverse_iter (start, [&resolved_definition, &name] (Node ¤t) {
// we can't reference associated types/functions like this
- if (current.rib.kind == Rib::Kind::TraitOrImpl)
+ if (current.rib (N).kind == Rib::Kind::TraitOrImpl)
return KeepGoing::Yes;
- auto candidate = current.rib.get (name.as_string ());
+ auto candidate = current.rib (N).get (name.as_string ());
if (candidate)
{
@@ -329,7 +329,7 @@ ForeverStack<N>::get (Node &start, const Identifier &name)
}
else
{
- if (current.rib.kind == Rib::Kind::Module)
+ if (current.rib (N).kind == Rib::Kind::Module)
return KeepGoing::No;
else
return KeepGoing::Yes;
@@ -350,14 +350,14 @@ template <Namespace N>
tl::optional<Rib::Definition>
ForeverStack<N>::get_lang_prelude (const Identifier &name)
{
- return lang_prelude.rib.get (name.as_string ());
+ return lang_prelude.rib (N).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);
+ return lang_prelude.rib (N).get (name);
}
template <Namespace N>
@@ -380,10 +380,10 @@ tl::optional<Rib::Definition> inline
ForeverStack<Namespace::Labels>::get (
reverse_iter ([&resolved_definition, &name] (Node ¤t) {
// looking up for labels cannot go through function ribs
// TODO: What other ribs?
- if (current.rib.kind == Rib::Kind::Function)
+ if (current.rib_labels.kind == Rib::Kind::Function)
return KeepGoing::No;
- auto candidate = current.rib.get (name.as_string ());
+ auto candidate = current.rib_labels.get (name.as_string ());
// FIXME: Factor this in a function with the generic `get`
return candidate.map_or (
@@ -421,7 +421,7 @@ ForeverStack<N>::find_closest_module (Node &starting_point)
auto *closest_module = &starting_point;
reverse_iter (starting_point, [&closest_module] (Node ¤t) {
- if (current.rib.kind == Rib::Kind::Module || current.is_root ())
+ if (current.rib (N).kind == Rib::Kind::Module || current.is_root ())
{
closest_module = ¤t;
return KeepGoing::No;
@@ -526,7 +526,7 @@ template <Namespace N>
tl::optional<typename ForeverStack<N>::DfsResult>
ForeverStack<N>::dfs (ForeverStack<N>::Node &starting_point, NodeId to_find)
{
- auto values = starting_point.rib.get_values ();
+ auto values = starting_point.rib (N).get_values ();
for (auto &kv : values)
{
@@ -557,7 +557,7 @@ tl::optional<typename ForeverStack<N>::ConstDfsResult>
ForeverStack<N>::dfs (const ForeverStack<N>::Node &starting_point,
NodeId to_find) const
{
- auto values = starting_point.rib.get_values ();
+ auto values = starting_point.rib (N).get_values ();
for (auto &kv : values)
{
@@ -588,7 +588,7 @@ tl::optional<Rib &>
ForeverStack<N>::dfs_rib (ForeverStack<N>::Node &starting_point, NodeId
to_find)
{
return dfs_node (starting_point, to_find).map ([] (Node &x) -> Rib & {
- return x.rib;
+ return x.rib (N);
});
}
@@ -598,7 +598,7 @@ ForeverStack<N>::dfs_rib (const ForeverStack<N>::Node
&starting_point,
NodeId to_find) const
{
return dfs_node (starting_point, to_find)
- .map ([] (const Node &x) -> const Rib & { return x.rib; });
+ .map ([] (const Node &x) -> const Rib & { return x.rib (N); });
}
template <Namespace N>
@@ -692,7 +692,7 @@ ForeverStack<N>::stream_node (std::stringstream &stream,
unsigned indentation,
<< next << "is_leaf: " << (node.is_leaf () ? "true" : "false")
<< ",\n";
- stream_rib (stream, node.rib, next, next_next);
+ stream_rib (stream, node.rib (N), next, next_next);
stream << indent << "}\n";
diff --git a/gcc/rust/resolve/rust-name-resolution-context.cc
b/gcc/rust/resolve/rust-name-resolution-context.cc
index 9444dc3a3..cff4c9ecc 100644
--- a/gcc/rust/resolve/rust-name-resolution-context.cc
+++ b/gcc/rust/resolve/rust-name-resolution-context.cc
@@ -199,7 +199,16 @@ CanonicalPathRecordTraitImpl::as_path (const
NameResolutionContext &ctx,
}
NameResolutionContext::NameResolutionContext ()
- : mappings (Analysis::Mappings::get ()), canonical_ctx (*this)
+ : root (std::make_unique<Node> (Rib::Kind::Normal, UNKNOWN_NODEID)),
+ lang_prelude (
+ std::make_unique<Node> (Rib::Kind::Prelude, UNKNOWN_NODEID, *root)),
+ extern_prelude (
+ std::make_unique<Node> (Rib::Kind::Prelude, UNKNOWN_NODEID)),
+ values (*root, *lang_prelude, *extern_prelude),
+ types (*root, *lang_prelude, *extern_prelude),
+ macros (*root, *lang_prelude, *extern_prelude),
+ labels (*root, *lang_prelude, *extern_prelude),
+ mappings (Analysis::Mappings::get ()), canonical_ctx (*this)
{}
tl::expected<NodeId, DuplicateNameError>
@@ -390,7 +399,9 @@ NameResolutionContext::scoped (Rib::Kind rib_kind,
Namespace ns,
void
NameResolutionContext::merge (NameResolutionContext &other, NodeId at)
{
- auto merge_fstack = [&] (auto &stack, auto &other_stack) {
+ // TODO: merge once, for all namespaces at once
+
+ auto merge_fstack = [&] (auto &stack, auto &other_stack, Namespace ns) {
auto node = stack.dfs_node (stack.root, at);
if (node)
{
@@ -402,21 +413,21 @@ NameResolutionContext::merge (NameResolutionContext
&other, NodeId at)
extern_crate_node.insert_child (link, child);
child.parent = extern_crate_node;
}
- for (auto kv : other_stack.root.rib.get_values ())
+ for (auto kv : other_stack.root.rib (ns).get_values ())
{
auto name = kv.first;
auto def = kv.second;
- extern_crate_node.rib.insert (name, def);
+ extern_crate_node.rib (ns).insert (name, def);
}
}
stack.resolved_nodes.insert (other_stack.resolved_nodes.begin (),
other_stack.resolved_nodes.end ());
};
- merge_fstack (values, other.values);
- merge_fstack (types, other.types);
- merge_fstack (macros, other.macros);
- merge_fstack (labels, other.labels);
+ merge_fstack (values, other.values, Namespace::Values);
+ merge_fstack (types, other.types, Namespace::Types);
+ merge_fstack (macros, other.macros, Namespace::Macros);
+ merge_fstack (labels, other.labels, Namespace::Labels);
canonical_ctx.merge (std::move (other.canonical_ctx));
}
diff --git a/gcc/rust/resolve/rust-name-resolution-context.h
b/gcc/rust/resolve/rust-name-resolution-context.h
index 5aaea9631..e30c5b59e 100644
--- a/gcc/rust/resolve/rust-name-resolution-context.h
+++ b/gcc/rust/resolve/rust-name-resolution-context.h
@@ -524,6 +524,12 @@ public:
std::function<void (void)> lambda,
tl::optional<Identifier> path = {});
+ using Node = ForeverStackBase::Node;
+
+ std::unique_ptr<Node> root;
+ std::unique_ptr<Node> lang_prelude;
+ std::unique_ptr<Node> extern_prelude;
+
ForeverStack<Namespace::Values> values;
ForeverStack<Namespace::Types> types;
ForeverStack<Namespace::Macros> macros;
diff --git a/gcc/rust/resolve/rust-name-resolution-context.hxx
b/gcc/rust/resolve/rust-name-resolution-context.hxx
index 7de8da097..3c9c6a3d9 100644
--- a/gcc/rust/resolve/rust-name-resolution-context.hxx
+++ b/gcc/rust/resolve/rust-name-resolution-context.hxx
@@ -42,7 +42,7 @@ NameResolutionContext::should_search_prelude (
// Check whether we're at the start of a module (we can't travel elsewhere
// from the start of a module)
if (is_start (iterator, segments)
- && current_node->rib.kind == Rib::Kind::Module)
+ && current_node->rib (N).kind == Rib::Kind::Module)
return true;
return false;
@@ -203,31 +203,20 @@ NameResolutionContext::resolve_path (
// We do the first part of path resolution exclusively in the types NS - this
// gives us a node in which to resolve the last segment of the path.
- // We take our starting point and then get the equivalent Node from the Types
- // NS - since it existed in whatever namespace we are right now, we assume it
- // exists in the types NS.
- auto types_starting_point
- = types.dfs_node (types.root, starting_point.get ().id);
-
- // TODO: Add a method for converting a node between namespaces? Make all of
- // the starting point stuff return a NodeId rather than a Node&? And take a
- // NodeId as a starting point rather than a Node?
-
+ // nodes are shared between stacks
auto node
- = resolve_segments (types, types_starting_point.value (), segments,
- iterator, insert_segment_resolution, collect_errors);
+ = resolve_segments (types, starting_point.get (), segments, iterator,
+ insert_segment_resolution, collect_errors);
if (!node)
return tl::nullopt;
// This node now represents the Node which *should* contain the definition
- // used by the last segment. We now get the equivalent Node from this
- // namespace after finding it in the types NS.
- auto final_node_id = node.value ().id;
- auto final_node = stack.dfs_node (stack.root, final_node_id).value ();
+ // used by the last segment.
+ auto &final_node = node.value ();
// leave resolution within impl blocks to type checker
- if (final_node.rib.kind == Rib::Kind::TraitOrImpl)
+ if (final_node.rib (N).kind == Rib::Kind::TraitOrImpl)
return tl::nullopt;
auto &seg = segments.back ();
@@ -294,7 +283,7 @@ NameResolutionContext::resolve_segments (
while (true)
{
if (is_start (iterator, segments)
- && current_node->rib.kind == Rib::Kind::TraitOrImpl)
+ && current_node->rib (N).kind == Rib::Kind::TraitOrImpl)
{
// we can't reference associated types/functions like this
current_node = ¤t_node->parent.value ();
@@ -323,7 +312,7 @@ NameResolutionContext::resolve_segments (
break;
}
- auto rib_lookup = current_node->rib.get (seg.name);
+ auto rib_lookup = current_node->rib (N).get (seg.name);
if (rib_lookup && !rib_lookup->is_ambiguous ())
{
if (Analysis::Mappings::get ()
@@ -369,7 +358,7 @@ NameResolutionContext::resolve_segments (
}
if (!is_start (iterator, segments)
- || current_node->rib.kind == Rib::Kind::Module
+ || current_node->rib (N).kind == Rib::Kind::Module
|| current_node->is_prelude ())
{
return tl::nullopt;
@@ -398,7 +387,7 @@ NameResolutionContext::resolve_final_segment (
if (is_lower_self)
return Rib::Definition::NonShadowable (final_node.id);
else
- return final_node.rib.get (seg_name);
+ return final_node.rib_types.get (seg_name);
}
template <Namespace N>
@@ -407,7 +396,7 @@ NameResolutionContext::resolve_final_segment (
ForeverStack<N> &stack, typename ForeverStack<N>::Node &final_node,
std::string &seg_name, bool is_lower_self)
{
- return final_node.rib.get (seg_name);
+ return final_node.rib (N).get (seg_name);
}
} // namespace Resolver2_0
base-commit: 5d0183e3b1be74428be76cf99ba2f43d21f9c191
--
2.54.0