Skip to content

Commit cc7c0a2

Browse files
committed
Use stacked context for nested bindings.
Binding context may be stacked when a new binding group is introduced within a const expression. gcc/rust/ChangeLog: * resolve/rust-name-resolution-context.h: Use BindingLayer instead. * resolve/rust-name-resolution-context.cc (BindingLayer::BindingLayer): Add new constructor for binding layer. (BindingLayer::bind_test): Add a function to test a binding constraint. (BindingLayer::push): Push a new binding group. (BindingLayer::and_binded): Add function to test and-binding constraint. (BindingLayer::or_binded): Add function to test or-binding constraints. (BindingLayer::insert_ident): Insert a new identifier in the current binding group. (BindingLayer::merge): Merge current binding group with it's parent. (BindingLayer::get_source): Get the source of the current binding group. * resolve/rust-name-resolution-context.h (enum class): Remove function definition. Signed-off-by: Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
1 parent ea52f41 commit cc7c0a2

File tree

4 files changed

+113
-71
lines changed

4 files changed

+113
-71
lines changed

gcc/rust/resolve/rust-late-name-resolver-2.0.cc

+22-22
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,11 @@ Late::visit (AST::ForLoopExpr &expr)
133133
{
134134
visit_outer_attrs (expr);
135135

136-
ctx.bindings.new_binding (BindingSource::For);
136+
ctx.bindings.enter (BindingSource::For);
137137

138138
visit (expr.get_pattern ());
139139

140-
ctx.bindings.clear ();
140+
ctx.bindings.exit ();
141141

142142
visit (expr.get_iterator_expr ());
143143
visit (expr.get_loop_label ());
@@ -149,12 +149,12 @@ Late::visit (AST::IfLetExpr &expr)
149149
{
150150
visit_outer_attrs (expr);
151151

152-
ctx.bindings.new_binding (BindingSource::Let);
152+
ctx.bindings.enter (BindingSource::Let);
153153

154154
for (auto &pattern : expr.get_patterns ())
155155
visit (pattern);
156156

157-
ctx.bindings.clear ();
157+
ctx.bindings.exit ();
158158

159159
visit (expr.get_value_expr ());
160160
visit (expr.get_if_block ());
@@ -165,12 +165,12 @@ Late::visit (AST::MatchArm &arm)
165165
{
166166
visit_outer_attrs (arm);
167167

168-
ctx.bindings.new_binding (BindingSource::Match);
168+
ctx.bindings.enter (BindingSource::Match);
169169

170170
for (auto &pattern : arm.get_patterns ())
171171
visit (pattern);
172172

173-
ctx.bindings.clear ();
173+
ctx.bindings.exit ();
174174

175175
if (arm.has_match_arm_guard ())
176176
visit (arm.get_guard_expr ());
@@ -187,11 +187,11 @@ Late::visit (AST::LetStmt &let)
187187
if (let.has_init_expr ())
188188
visit (let.get_init_expr ());
189189

190-
ctx.bindings.new_binding (BindingSource::Let);
190+
ctx.bindings.enter (BindingSource::Let);
191191

192192
visit (let.get_pattern ());
193193

194-
ctx.bindings.clear ();
194+
ctx.bindings.exit ();
195195

196196
if (let.has_else_expr ())
197197
visit (let.get_init_expr ());
@@ -220,9 +220,9 @@ Late::visit (AST::IdentifierPattern &identifier)
220220
// but values does not allow shadowing... since functions cannot shadow
221221
// do we insert functions in labels as well?
222222

223-
if (ctx.bindings.and_binded (identifier.get_ident ()))
223+
if (ctx.bindings.peek ().is_and_bound (identifier.get_ident ()))
224224
{
225-
if (ctx.bindings.get_source () == BindingSource::Param)
225+
if (ctx.bindings.peek ().get_source () == BindingSource::Param)
226226
rust_error_at (
227227
identifier.get_locus (), ErrorCode::E0415,
228228
"identifier %qs is bound more than once in the same parameter list",
@@ -235,9 +235,9 @@ Late::visit (AST::IdentifierPattern &identifier)
235235
return;
236236
}
237237

238-
ctx.bindings.insert_ident (identifier.get_ident ());
238+
ctx.bindings.peek ().insert_ident (identifier.get_ident ());
239239

240-
if (ctx.bindings.or_binded (identifier.get_ident ()))
240+
if (ctx.bindings.peek ().is_or_bound (identifier.get_ident ()))
241241
{
242242
// FIXME: map usage instead
243243
std::ignore = ctx.values.insert_shadowable (identifier.get_ident (),
@@ -255,14 +255,14 @@ Late::visit (AST::IdentifierPattern &identifier)
255255
void
256256
Late::visit (AST::AltPattern &pattern)
257257
{
258-
ctx.bindings.push (Binding::Kind::Or);
258+
ctx.bindings.peek ().push (Binding::Kind::Or);
259259
for (auto &alt : pattern.get_alts ())
260260
{
261-
ctx.bindings.push (Binding::Kind::Product);
261+
ctx.bindings.peek ().push (Binding::Kind::Product);
262262
visit (alt);
263-
ctx.bindings.merge ();
263+
ctx.bindings.peek ().merge ();
264264
}
265-
ctx.bindings.merge ();
265+
ctx.bindings.peek ().merge ();
266266
}
267267

268268
void
@@ -276,12 +276,12 @@ Late::visit (AST::Function &function)
276276
visit (generic);
277277

278278
// We only care about params
279-
ctx.bindings.new_binding (BindingSource::Param);
279+
ctx.bindings.enter (BindingSource::Param);
280280

281281
for (auto &param : function.get_function_params ())
282282
visit (param);
283283

284-
ctx.bindings.clear ();
284+
ctx.bindings.exit ();
285285

286286
// Back to regular visit
287287

@@ -644,12 +644,12 @@ Late::visit (AST::ClosureExprInner &closure)
644644

645645
visit_outer_attrs (closure);
646646

647-
ctx.bindings.new_binding (BindingSource::Param);
647+
ctx.bindings.enter (BindingSource::Param);
648648

649649
for (auto &param : closure.get_params ())
650650
visit (param);
651651

652-
ctx.bindings.clear ();
652+
ctx.bindings.exit ();
653653

654654
visit (closure.get_definition_expr ());
655655
}
@@ -661,12 +661,12 @@ Late::visit (AST::ClosureExprInnerTyped &closure)
661661

662662
visit_outer_attrs (closure);
663663

664-
ctx.bindings.new_binding (BindingSource::Param);
664+
ctx.bindings.enter (BindingSource::Param);
665665

666666
for (auto &param : closure.get_params ())
667667
visit (param);
668668

669-
ctx.bindings.clear ();
669+
ctx.bindings.exit ();
670670

671671
visit (closure.get_return_type ());
672672
visit (closure.get_definition_block ());

gcc/rust/resolve/rust-name-resolution-context.cc

+59
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,65 @@
2323
namespace Rust {
2424
namespace Resolver2_0 {
2525

26+
BindingLayer::BindingLayer (BindingSource source) : source (source)
27+
{
28+
push (Binding::Kind::Product);
29+
}
30+
31+
bool
32+
BindingLayer::bind_test (Identifier ident, Binding::Kind kind)
33+
{
34+
for (auto &bind : bindings)
35+
{
36+
if (bind.set.find (ident) != bind.set.cend () && bind.kind == kind)
37+
{
38+
return true;
39+
}
40+
}
41+
return false;
42+
}
43+
44+
void
45+
BindingLayer::push (Binding::Kind kind)
46+
{
47+
bindings.push_back (Binding (kind));
48+
}
49+
50+
bool
51+
BindingLayer::is_and_bound (Identifier ident)
52+
{
53+
return bind_test (ident, Binding::Kind::Product);
54+
}
55+
56+
bool
57+
BindingLayer::is_or_bound (Identifier ident)
58+
{
59+
return bind_test (ident, Binding::Kind::Or);
60+
}
61+
62+
void
63+
BindingLayer::insert_ident (Identifier ident)
64+
{
65+
bindings.back ().set.insert (ident);
66+
}
67+
68+
void
69+
BindingLayer::merge ()
70+
{
71+
auto last_binding = bindings.back ();
72+
bindings.pop_back ();
73+
for (auto &value : last_binding.set)
74+
{
75+
bindings.back ().set.insert (value);
76+
}
77+
}
78+
79+
BindingSource
80+
BindingLayer::get_source () const
81+
{
82+
return source;
83+
}
84+
2685
NameResolutionContext::NameResolutionContext ()
2786
: mappings (Analysis::Mappings::get ())
2887
{}

gcc/rust/resolve/rust-name-resolution-context.h

+24-48
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "rust-forever-stack.h"
2424
#include "rust-hir-map.h"
2525
#include "rust-rib.h"
26+
#include "rust-stacked-contexts.h"
2627

2728
namespace Rust {
2829
namespace Resolver2_0 {
@@ -169,72 +170,47 @@ struct Binding
169170
Binding (Binding::Kind kind) : kind (kind) {}
170171
};
171172

173+
/**
174+
* Used to identify the source of a binding, and emit the correct error message.
175+
*/
172176
enum class BindingSource
173177
{
174178
Match,
175179
Let,
176180
For,
181+
/* Closure param or function param */
177182
Param
178183
};
179184

180-
class BindingContext
185+
class BindingLayer
181186
{
182-
// FIXME: Use std::vector<std::vector<Binding>> to handle nested patterns
187+
BindingSource source;
183188
std::vector<Binding> bindings;
184189

185-
BindingSource source;
186-
187-
bool bind_test (Identifier ident, Binding::Kind kind)
188-
{
189-
for (auto &bind : bindings)
190-
{
191-
if (bind.set.find (ident) != bind.set.cend () && bind.kind == kind)
192-
{
193-
return true;
194-
}
195-
}
196-
return false;
197-
}
190+
bool bind_test (Identifier ident, Binding::Kind kind);
198191

199192
public:
200-
bool and_binded (Identifier ident)
201-
{
202-
return bind_test (ident, Binding::Kind::Product);
203-
}
204-
205-
bool or_binded (Identifier ident)
206-
{
207-
return bind_test (ident, Binding::Kind::Or);
208-
}
193+
void push (Binding::Kind kind);
209194

210-
void insert_ident (Identifier ident) { bindings.back ().set.insert (ident); }
195+
BindingLayer (BindingSource source);
211196

212-
void push (Binding::Kind kind) { bindings.push_back (Binding (kind)); }
197+
/**
198+
* Identifies if the identifier has been used in a product binding context.
199+
* eg. `let (a, a) = test();`
200+
*/
201+
bool is_and_bound (Identifier ident);
213202

214-
void new_binding (BindingSource source)
215-
{
216-
rust_assert (bindings.size () == 0);
217-
this->source = source;
218-
push (Binding::Kind::Product);
219-
}
203+
/**
204+
* Identifies if the identifier has been used in a or context.
205+
* eg. `let (a, 1) | (a, 2) = test()`
206+
*/
207+
bool is_or_bound (Identifier ident);
220208

221-
void clear ()
222-
{
223-
rust_assert (bindings.size () == 1);
224-
bindings.clear ();
225-
}
209+
void insert_ident (Identifier ident);
226210

227-
void merge ()
228-
{
229-
auto last_binding = bindings.back ();
230-
bindings.pop_back ();
231-
for (auto &value : last_binding.set)
232-
{
233-
bindings.back ().set.insert (value);
234-
}
235-
}
211+
void merge ();
236212

237-
BindingSource get_source () const { return source; }
213+
BindingSource get_source () const;
238214
};
239215

240216
// Now our resolver, which keeps track of all the `ForeverStack`s we could want
@@ -293,7 +269,7 @@ class NameResolutionContext
293269
ForeverStack<Namespace::Labels> labels;
294270

295271
Analysis::Mappings &mappings;
296-
BindingContext bindings;
272+
StackedContexts<BindingLayer> bindings;
297273

298274
// TODO: Rename
299275
// TODO: Use newtype pattern for Usage and Definition

gcc/rust/util/rust-stacked-contexts.h

+8-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,14 @@ template <typename T> class StackedContexts
7171
return last;
7272
}
7373

74-
const T &peek ()
74+
const T &peek () const
75+
{
76+
rust_assert (!stack.empty ());
77+
78+
return stack.back ();
79+
}
80+
81+
T &peek ()
7582
{
7683
rust_assert (!stack.empty ());
7784

0 commit comments

Comments
 (0)