Skip to content

Commit 3c27f41

Browse files
committed
Add ForeverStackStore
ForeverStackStore is meant to partially unify the internal states of per-namespace ForeverStack instances. This commit does not contain modifications to ForeverStack which would allow it to rely on a ForeverStackStore to store nodes, but a future commit should address this. gcc/rust/ChangeLog: * Make-lang.in: Handle rust-forever-stack.cc. * resolve/rust-forever-stack.h (class ForeverStackStore): Add. * resolve/rust-forever-stack.cc: New file, based on rust-forever-stack.hxx. Signed-off-by: Owen Avery <[email protected]>
1 parent 90454a9 commit 3c27f41

File tree

3 files changed

+488
-0
lines changed

3 files changed

+488
-0
lines changed

gcc/rust/Make-lang.in

+1
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ GRS_OBJS = \
146146
rust/rust-ast-resolve-path.o \
147147
rust/rust-ast-resolve-stmt.o \
148148
rust/rust-ast-resolve-struct-expr-field.o \
149+
rust/rust-forever-stack.o \
149150
rust/rust-hir-type-check.o \
150151
rust/rust-privacy-check.o \
151152
rust/rust-privacy-ctx.o \
+336
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,336 @@
1+
// Copyright (C) 2024 Free Software Foundation, Inc.
2+
3+
// This file is part of GCC.
4+
5+
// GCC is free software; you can redistribute it and/or modify it under
6+
// the terms of the GNU General Public License as published by the Free
7+
// Software Foundation; either version 3, or (at your option) any later
8+
// version.
9+
10+
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11+
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
12+
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13+
// for more details.
14+
15+
// You should have received a copy of the GNU General Public License
16+
// along with GCC; see the file COPYING3. If not see
17+
// <http://www.gnu.org/licenses/>.
18+
19+
#include "expected.h"
20+
#include "rust-ast.h"
21+
#include "rust-diagnostics.h"
22+
#include "rust-forever-stack.h"
23+
#include "rust-rib.h"
24+
#include "optional.h"
25+
26+
namespace Rust {
27+
namespace Resolver2_0 {
28+
29+
bool
30+
ForeverStackStore::Node::is_root () const
31+
{
32+
return !parent.has_value ();
33+
}
34+
35+
bool
36+
ForeverStackStore::Node::is_leaf () const
37+
{
38+
return children.empty ();
39+
}
40+
41+
NodeId
42+
ForeverStackStore::Node::get_id () const
43+
{
44+
return id;
45+
}
46+
47+
ForeverStackStore::Node &
48+
ForeverStackStore::Node::insert_child (NodeId id, tl::optional<Identifier> path,
49+
Rib::Kind kind)
50+
{
51+
auto res = children.insert ({Link (id, path), Node (kind, id, *this)});
52+
53+
rust_debug ("inserting link: Link(%d [%s]): existed? %s", id,
54+
path.has_value () ? path.value ().as_string ().c_str ()
55+
: "<anon>",
56+
!res.second ? "yes" : "no");
57+
58+
// sanity check on rib kind
59+
// pick the value rib, since all ribs should have the same kind anyways
60+
rust_assert (res.second || res.first->second.value_rib.kind == kind);
61+
62+
// verify, if we're using an existing node, our paths don't contradict
63+
if (!res.second && path.has_value ())
64+
{
65+
auto other_path = res.first->first.path;
66+
rust_assert (!other_path.has_value ()
67+
|| other_path.value ().as_string ()
68+
== path.value ().as_string ());
69+
}
70+
71+
return res.first->second;
72+
}
73+
74+
tl::optional<ForeverStackStore::Node &>
75+
ForeverStackStore::Node::get_child (const Identifier &path)
76+
{
77+
for (auto &ent : children)
78+
{
79+
if (ent.first.path.has_value ()
80+
&& ent.first.path->as_string () == path.as_string ())
81+
return ent.second;
82+
}
83+
return tl::nullopt;
84+
}
85+
86+
tl::optional<const ForeverStackStore::Node &>
87+
ForeverStackStore::Node::get_child (const Identifier &path) const
88+
{
89+
for (auto &ent : children)
90+
{
91+
if (ent.first.path.has_value ()
92+
&& ent.first.path->as_string () == path.as_string ())
93+
return ent.second;
94+
}
95+
return tl::nullopt;
96+
}
97+
98+
tl::optional<ForeverStackStore::Node &>
99+
ForeverStackStore::Node::get_parent ()
100+
{
101+
return parent;
102+
}
103+
104+
tl::optional<const ForeverStackStore::Node &>
105+
ForeverStackStore::Node::get_parent () const
106+
{
107+
if (parent)
108+
return *parent;
109+
else
110+
return tl::nullopt;
111+
}
112+
113+
tl::optional<const Identifier &>
114+
ForeverStackStore::Node::get_parent_path () const
115+
{
116+
if (parent.has_value ())
117+
for (auto &ent : parent->children)
118+
if (ent.first.id == id && ent.first.path.has_value ())
119+
return ent.first.path.value ();
120+
return tl::nullopt;
121+
}
122+
123+
Rib &
124+
ForeverStackStore::Node::get_rib (Namespace ns)
125+
{
126+
switch (ns)
127+
{
128+
case Namespace::Values:
129+
return value_rib;
130+
case Namespace::Types:
131+
return type_rib;
132+
case Namespace::Labels:
133+
return label_rib;
134+
case Namespace::Macros:
135+
return macro_rib;
136+
}
137+
rust_unreachable ();
138+
}
139+
140+
const Rib &
141+
ForeverStackStore::Node::get_rib (Namespace ns) const
142+
{
143+
switch (ns)
144+
{
145+
case Namespace::Values:
146+
return value_rib;
147+
case Namespace::Types:
148+
return type_rib;
149+
case Namespace::Labels:
150+
return label_rib;
151+
case Namespace::Macros:
152+
return macro_rib;
153+
}
154+
rust_unreachable ();
155+
}
156+
157+
tl::expected<NodeId, DuplicateNameError>
158+
ForeverStackStore::Node::insert (const Identifier &name, NodeId node,
159+
Namespace ns)
160+
{
161+
// So what do we do here - if the Rib has already been pushed in an earlier
162+
// pass, we might end up in a situation where it is okay to re-add new names.
163+
// Do we just ignore that here? Do we keep track of if the Rib is new or not?
164+
// should our cursor have info on the current node like "is it newly pushed"?
165+
return get_rib (ns).insert (name.as_string (),
166+
Rib::Definition::NonShadowable (node));
167+
}
168+
169+
tl::expected<NodeId, DuplicateNameError>
170+
ForeverStackStore::Node::insert_shadowable (const Identifier &name, NodeId node,
171+
Namespace ns)
172+
{
173+
return get_rib (ns).insert (name.as_string (),
174+
Rib::Definition::Shadowable (node));
175+
}
176+
177+
tl::expected<NodeId, DuplicateNameError>
178+
ForeverStackStore::Node::insert_globbed (const Identifier &name, NodeId node,
179+
Namespace ns)
180+
{
181+
return get_rib (ns).insert (name.as_string (),
182+
Rib::Definition::Globbed (node));
183+
}
184+
185+
void
186+
ForeverStackStore::Node::reverse_iter (std::function<KeepGoing (Node &)> lambda)
187+
{
188+
Node *tmp = this;
189+
190+
while (true)
191+
{
192+
auto keep_going = lambda (*tmp);
193+
if (keep_going == KeepGoing::No)
194+
return;
195+
196+
if (tmp->is_root ())
197+
return;
198+
199+
tmp = &tmp->parent.value ();
200+
}
201+
}
202+
203+
void
204+
ForeverStackStore::Node::reverse_iter (
205+
std::function<KeepGoing (const Node &)> lambda) const
206+
{
207+
const Node *tmp = this;
208+
209+
while (true)
210+
{
211+
auto keep_going = lambda (*tmp);
212+
if (keep_going == KeepGoing::No)
213+
return;
214+
215+
if (tmp->is_root ())
216+
return;
217+
218+
tmp = &tmp->parent.value ();
219+
}
220+
}
221+
222+
void
223+
ForeverStackStore::Node::child_iter (
224+
std::function<KeepGoing (NodeId, tl::optional<const Identifier &>, Node &)>
225+
lambda)
226+
{
227+
for (auto &ent : children)
228+
{
229+
tl::optional<const Identifier &> path;
230+
if (ent.first.path.has_value ())
231+
path = ent.first.path.value ();
232+
auto keep_going = lambda (ent.first.id, path, ent.second);
233+
if (keep_going == KeepGoing::No)
234+
return;
235+
}
236+
}
237+
238+
void
239+
ForeverStackStore::Node::child_iter (
240+
std::function<KeepGoing (NodeId, tl::optional<const Identifier &>,
241+
const Node &)>
242+
lambda) const
243+
{
244+
for (auto &ent : children)
245+
{
246+
tl::optional<const Identifier &> path;
247+
if (ent.first.path.has_value ())
248+
path = ent.first.path.value ();
249+
auto keep_going = lambda (ent.first.id, path, ent.second);
250+
if (keep_going == KeepGoing::No)
251+
return;
252+
}
253+
}
254+
255+
ForeverStackStore::Node &
256+
ForeverStackStore::Node::find_closest_module ()
257+
{
258+
// get kind of value_rib
259+
// but all ribs should share the same kind anyways
260+
if (value_rib.kind == Rib::Kind::Module || !parent.has_value ())
261+
return *this;
262+
else
263+
return parent->find_closest_module ();
264+
}
265+
266+
const ForeverStackStore::Node &
267+
ForeverStackStore::Node::find_closest_module () const
268+
{
269+
// get kind of value_rib
270+
// but all ribs should share the same kind anyways
271+
if (value_rib.kind != Rib::Kind::Module || !parent.has_value ())
272+
return *this;
273+
else
274+
return parent->find_closest_module ();
275+
}
276+
277+
tl::optional<ForeverStackStore::Node &>
278+
ForeverStackStore::Node::dfs_node (NodeId to_find)
279+
{
280+
if (id == to_find)
281+
return *this;
282+
283+
for (auto &child : children)
284+
{
285+
auto candidate = child.second.dfs_node (to_find);
286+
287+
if (candidate.has_value ())
288+
return candidate;
289+
}
290+
291+
return tl::nullopt;
292+
}
293+
294+
tl::optional<const ForeverStackStore::Node &>
295+
ForeverStackStore::Node::dfs_node (NodeId to_find) const
296+
{
297+
if (id == to_find)
298+
return *this;
299+
300+
for (auto &child : children)
301+
{
302+
auto candidate = child.second.dfs_node (to_find);
303+
304+
if (candidate.has_value ())
305+
return candidate;
306+
}
307+
308+
return tl::nullopt;
309+
}
310+
311+
ForeverStackStore::Node &
312+
ForeverStackStore::get_root ()
313+
{
314+
return root;
315+
}
316+
317+
const ForeverStackStore::Node &
318+
ForeverStackStore::get_root () const
319+
{
320+
return root;
321+
}
322+
323+
tl::optional<ForeverStackStore::Node &>
324+
ForeverStackStore::get_node (NodeId node_id)
325+
{
326+
return root.dfs_node (node_id);
327+
}
328+
329+
tl::optional<const ForeverStackStore::Node &>
330+
ForeverStackStore::get_node (NodeId node_id) const
331+
{
332+
return root.dfs_node (node_id);
333+
}
334+
335+
} // namespace Resolver2_0
336+
} // namespace Rust

0 commit comments

Comments
 (0)