Branch data Line data Source code
1 : : // Copyright (C) 2020-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 "rust-ast-resolve-expr.h"
20 : : #include "rust-ast-resolve-stmt.h"
21 : : #include "rust-ast-resolve-struct-expr-field.h"
22 : : #include "rust-ast-resolve-type.h"
23 : : #include "rust-ast-resolve-pattern.h"
24 : : #include "rust-ast-resolve-path.h"
25 : : #include "diagnostic.h"
26 : :
27 : : namespace Rust {
28 : : namespace Resolver {
29 : :
30 : : void
31 : 75910 : ResolveExpr::go (AST::Expr *expr, const CanonicalPath &prefix,
32 : : const CanonicalPath &canonical_prefix, bool funny_error)
33 : : {
34 : 75910 : ResolveExpr resolver (prefix, canonical_prefix, funny_error);
35 : 75910 : expr->accept_vis (resolver);
36 : 75907 : }
37 : :
38 : : void
39 : 729 : ResolveExpr::visit (AST::TupleIndexExpr &expr)
40 : : {
41 : 729 : ResolveExpr::go (expr.get_tuple_expr ().get (), prefix, canonical_prefix);
42 : 729 : }
43 : :
44 : : void
45 : 328 : ResolveExpr::visit (AST::TupleExpr &expr)
46 : : {
47 : 328 : if (expr.is_unit ())
48 : : return;
49 : :
50 : 889 : for (auto &elem : expr.get_tuple_elems ())
51 : 630 : ResolveExpr::go (elem.get (), prefix, canonical_prefix);
52 : : }
53 : :
54 : : void
55 : 10959 : ResolveExpr::visit (AST::PathInExpression &expr)
56 : : {
57 : 10959 : ResolvePath::go (&expr);
58 : 10959 : }
59 : :
60 : : void
61 : 80 : ResolveExpr::visit (AST::QualifiedPathInExpression &expr)
62 : : {
63 : 80 : ResolvePath::go (&expr);
64 : 80 : }
65 : :
66 : : void
67 : 326 : ResolveExpr::visit (AST::ReturnExpr &expr)
68 : : {
69 : 326 : if (expr.has_returned_expr ())
70 : 316 : ResolveExpr::go (expr.get_returned_expr ().get (), prefix,
71 : : canonical_prefix);
72 : 326 : }
73 : :
74 : : void
75 : 6775 : ResolveExpr::visit (AST::CallExpr &expr)
76 : : {
77 : 6775 : ResolveExpr::go (expr.get_function_expr ().get (), prefix, canonical_prefix);
78 : 14442 : for (auto ¶m : expr.get_params ())
79 : 7667 : ResolveExpr::go (param.get (), prefix, canonical_prefix);
80 : 6775 : }
81 : :
82 : : void
83 : 1036 : ResolveExpr::visit (AST::MethodCallExpr &expr)
84 : : {
85 : 1036 : ResolveExpr::go (expr.get_receiver_expr ().get (), prefix, canonical_prefix);
86 : :
87 : 1036 : if (expr.get_method_name ().has_generic_args ())
88 : : {
89 : 22 : AST::GenericArgs &args = expr.get_method_name ().get_generic_args ();
90 : 22 : ResolveGenericArgs::go (args, prefix, canonical_prefix);
91 : : }
92 : :
93 : 1036 : auto const &in_params = expr.get_params ();
94 : 1501 : for (auto ¶m : in_params)
95 : 465 : ResolveExpr::go (param.get (), prefix, canonical_prefix);
96 : 1036 : }
97 : :
98 : : void
99 : 1623 : ResolveExpr::visit (AST::AssignmentExpr &expr)
100 : : {
101 : 1623 : ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix);
102 : 1623 : ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix);
103 : 1623 : }
104 : :
105 : : /* The "break rust" Easter egg.
106 : :
107 : : Backstory: once upon a time, there used to be a bug in rustc: it would ICE
108 : : during typechecking on a 'break' with an expression outside of a loop. The
109 : : issue has been reported [0] and fixed [1], but in recognition of this, as a
110 : : special Easter egg, "break rust" was made to intentionally cause an ICE.
111 : :
112 : : [0]: https://github.com/rust-lang/rust/issues/43162
113 : : [1]: https://github.com/rust-lang/rust/pull/43745
114 : :
115 : : This was made in a way that does not break valid programs: namely, it only
116 : : happens when the 'break' is outside of a loop (so invalid anyway).
117 : :
118 : : GCC Rust supports this essential feature as well, but in a slightly
119 : : different way. Instead of delaying the error until type checking, we emit
120 : : it here in the resolution phase. We, too, only do this to programs that
121 : : are already invalid: we only emit our funny ICE if the name "rust" (which
122 : : must be immediately inside a break-with-a-value expression) fails to
123 : : resolve. Note that "break (rust)" does not trigger our ICE, only using
124 : : "break rust" directly does, and only if there's no "rust" in scope. We do
125 : : this in the same way regardless of whether the "break" is outside of a loop
126 : : or inside one.
127 : :
128 : : As a GNU extension, we also support "break gcc", much to the same effect,
129 : : subject to the same rules. */
130 : :
131 : : /* The finalizer for our funny ICE. This prints a custom message instead of
132 : : the default bug reporting instructions, as there is no bug to report. */
133 : :
134 : : static void ATTRIBUTE_NORETURN
135 : 1 : funny_ice_finalizer (diagnostic_context *context,
136 : : const diagnostic_info *diagnostic, diagnostic_t diag_kind)
137 : : {
138 : 1 : gcc_assert (diag_kind == DK_ICE_NOBT);
139 : 1 : default_diagnostic_finalizer (context, diagnostic, diag_kind);
140 : 1 : fnotice (stderr, "You have broken GCC Rust. This is a feature.\n");
141 : 1 : exit (ICE_EXIT_CODE);
142 : : }
143 : :
144 : : void
145 : 14152 : ResolveExpr::visit (AST::IdentifierExpr &expr)
146 : : {
147 : 28304 : if (resolver->get_name_scope ().lookup (
148 : 28304 : CanonicalPath::new_seg (expr.get_node_id (), expr.as_string ()),
149 : : &resolved_node))
150 : : {
151 : 14044 : resolver->insert_resolved_name (expr.get_node_id (), resolved_node);
152 : : }
153 : 216 : else if (resolver->get_type_scope ().lookup (
154 : 216 : CanonicalPath::new_seg (expr.get_node_id (), expr.as_string ()),
155 : : &resolved_node))
156 : : {
157 : 101 : resolver->insert_resolved_type (expr.get_node_id (), resolved_node);
158 : : }
159 : 7 : else if (funny_error)
160 : : {
161 : : /* This was a "break rust" or "break gcc", and the identifier failed to
162 : : resolve. Emit a funny ICE. We set the finalizer to our custom one,
163 : : and use the lower-level emit_diagnostic () instead of the more common
164 : : internal_error_no_backtrace () in order to pass our locus. */
165 : 1 : diagnostic_finalizer (global_dc) = funny_ice_finalizer;
166 : 1 : emit_diagnostic (DK_ICE_NOBT, expr.get_locus (), -1,
167 : : "are you trying to break %s? how dare you?",
168 : 1 : expr.as_string ().c_str ());
169 : : }
170 : : else
171 : : {
172 : 6 : rust_error_at (expr.get_locus (), ErrorCode::E0425,
173 : : "cannot find value %qs in this scope",
174 : 12 : expr.as_string ().c_str ());
175 : : }
176 : 14151 : }
177 : :
178 : : void
179 : 2441 : ResolveExpr::visit (AST::ArithmeticOrLogicalExpr &expr)
180 : : {
181 : 2441 : ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix);
182 : 2441 : ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix);
183 : 2441 : }
184 : :
185 : : void
186 : 160 : ResolveExpr::visit (AST::CompoundAssignmentExpr &expr)
187 : : {
188 : 160 : ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix);
189 : 160 : ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix);
190 : 160 : }
191 : :
192 : : void
193 : 900 : ResolveExpr::visit (AST::ComparisonExpr &expr)
194 : : {
195 : 900 : ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix);
196 : 900 : ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix);
197 : 900 : }
198 : :
199 : : void
200 : 378 : ResolveExpr::visit (AST::LazyBooleanExpr &expr)
201 : : {
202 : 378 : ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix);
203 : 378 : ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix);
204 : 378 : }
205 : :
206 : : void
207 : 290 : ResolveExpr::visit (AST::NegationExpr &expr)
208 : : {
209 : 290 : ResolveExpr::go (expr.get_negated_expr ().get (), prefix, canonical_prefix);
210 : 290 : }
211 : :
212 : : void
213 : 3283 : ResolveExpr::visit (AST::TypeCastExpr &expr)
214 : : {
215 : 3283 : ResolveType::go (expr.get_type_to_cast_to ().get ());
216 : 3283 : ResolveExpr::go (expr.get_casted_expr ().get (), prefix, canonical_prefix);
217 : 3283 : }
218 : :
219 : : void
220 : 300 : ResolveExpr::visit (AST::IfExpr &expr)
221 : : {
222 : 300 : ResolveExpr::go (expr.get_condition_expr ().get (), prefix, canonical_prefix);
223 : 300 : ResolveExpr::go (expr.get_if_block ().get (), prefix, canonical_prefix);
224 : 300 : }
225 : :
226 : : void
227 : 347 : ResolveExpr::visit (AST::IfExprConseqElse &expr)
228 : : {
229 : 347 : ResolveExpr::go (expr.get_condition_expr ().get (), prefix, canonical_prefix);
230 : 347 : ResolveExpr::go (expr.get_if_block ().get (), prefix, canonical_prefix);
231 : 347 : ResolveExpr::go (expr.get_else_block ().get (), prefix, canonical_prefix);
232 : 347 : }
233 : :
234 : : void
235 : 1 : ResolveExpr::visit (AST::IfLetExpr &expr)
236 : : {
237 : 1 : ResolveExpr::go (expr.get_value_expr ().get (), prefix, canonical_prefix);
238 : :
239 : 1 : NodeId scope_node_id = expr.get_node_id ();
240 : 1 : resolver->get_name_scope ().push (scope_node_id);
241 : 1 : resolver->get_type_scope ().push (scope_node_id);
242 : 1 : resolver->get_label_scope ().push (scope_node_id);
243 : 1 : resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
244 : 1 : resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
245 : 1 : resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
246 : :
247 : : // We know expr.get_patterns () has one pattern at most
248 : : // so there's no reason to handle it like an AltPattern.
249 : 1 : std::vector<PatternBinding> bindings
250 : 2 : = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())};
251 : :
252 : 2 : for (auto &pattern : expr.get_patterns ())
253 : : {
254 : 1 : PatternDeclaration::go (pattern.get (), Rib::ItemType::Var, bindings);
255 : : }
256 : :
257 : 1 : ResolveExpr::go (expr.get_if_block ().get (), prefix, canonical_prefix);
258 : :
259 : 1 : resolver->get_name_scope ().pop ();
260 : 1 : resolver->get_type_scope ().pop ();
261 : 1 : resolver->get_label_scope ().pop ();
262 : 1 : }
263 : :
264 : : void
265 : 2 : ResolveExpr::visit (AST::IfLetExprConseqElse &expr)
266 : : {
267 : 2 : ResolveExpr::go (expr.get_value_expr ().get (), prefix, canonical_prefix);
268 : :
269 : 2 : NodeId scope_node_id = expr.get_node_id ();
270 : 2 : resolver->get_name_scope ().push (scope_node_id);
271 : 2 : resolver->get_type_scope ().push (scope_node_id);
272 : 2 : resolver->get_label_scope ().push (scope_node_id);
273 : 2 : resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
274 : 2 : resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
275 : 2 : resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
276 : :
277 : : // We know expr.get_patterns () has one pattern at most
278 : : // so there's no reason to handle it like an AltPattern.
279 : 2 : std::vector<PatternBinding> bindings
280 : 4 : = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())};
281 : :
282 : 4 : for (auto &pattern : expr.get_patterns ())
283 : : {
284 : 2 : PatternDeclaration::go (pattern.get (), Rib::ItemType::Var, bindings);
285 : : }
286 : :
287 : 2 : ResolveExpr::go (expr.get_if_block ().get (), prefix, canonical_prefix);
288 : 2 : ResolveExpr::go (expr.get_else_block ().get (), prefix, canonical_prefix);
289 : :
290 : 2 : resolver->get_name_scope ().pop ();
291 : 2 : resolver->get_type_scope ().pop ();
292 : 2 : resolver->get_label_scope ().pop ();
293 : 2 : }
294 : :
295 : : void
296 : 12867 : ResolveExpr::visit (AST::BlockExpr &expr)
297 : : {
298 : 12867 : NodeId scope_node_id = expr.get_node_id ();
299 : 12867 : resolver->get_name_scope ().push (scope_node_id);
300 : 12867 : resolver->get_type_scope ().push (scope_node_id);
301 : 12867 : resolver->get_label_scope ().push (scope_node_id);
302 : 12867 : resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
303 : 12867 : resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
304 : 12867 : resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
305 : :
306 : 12867 : if (expr.has_label ())
307 : : {
308 : 0 : auto label = expr.get_label ();
309 : 0 : if (label.get_lifetime ().get_lifetime_type ()
310 : : != AST::Lifetime::LifetimeType::NAMED)
311 : : {
312 : 0 : rust_error_at (label.get_locus (),
313 : : "Labels must be a named lifetime value");
314 : 0 : return;
315 : : }
316 : :
317 : 0 : auto label_name = label.get_lifetime ().get_lifetime_name ();
318 : 0 : auto label_lifetime_node_id = label.get_lifetime ().get_node_id ();
319 : 0 : resolver->get_label_scope ().insert (
320 : 0 : CanonicalPath::new_seg (label.get_node_id (), label_name),
321 : : label_lifetime_node_id, label.get_locus (), false, Rib::ItemType::Label,
322 : 0 : [&] (const CanonicalPath &, NodeId, location_t locus) -> void {
323 : 0 : rust_error_at (label.get_locus (), "label redefined multiple times");
324 : 0 : rust_error_at (locus, "was defined here");
325 : 0 : });
326 : 0 : }
327 : :
328 : 29060 : for (auto &s : expr.get_statements ())
329 : : {
330 : 16193 : if (s->is_item ())
331 : 298 : ResolveStmt::go (s.get (), prefix, canonical_prefix,
332 : 596 : CanonicalPath::create_empty ());
333 : : }
334 : :
335 : 29059 : for (auto &s : expr.get_statements ())
336 : : {
337 : 16193 : if (!s->is_item ())
338 : 15895 : ResolveStmt::go (s.get (), prefix, canonical_prefix,
339 : 31789 : CanonicalPath::create_empty ());
340 : : }
341 : :
342 : 12866 : if (expr.has_tail_expr ())
343 : 8442 : ResolveExpr::go (expr.get_tail_expr ().get (), prefix, canonical_prefix);
344 : :
345 : 12866 : resolver->get_name_scope ().pop ();
346 : 12866 : resolver->get_type_scope ().pop ();
347 : 12866 : resolver->get_label_scope ().pop ();
348 : : }
349 : :
350 : : void
351 : 2479 : ResolveExpr::visit (AST::UnsafeBlockExpr &expr)
352 : : {
353 : 2479 : expr.get_block_expr ()->accept_vis (*this);
354 : 2479 : }
355 : :
356 : : void
357 : 198 : ResolveExpr::visit (AST::ArrayElemsValues &elems)
358 : : {
359 : 1148 : for (auto &elem : elems.get_values ())
360 : 950 : ResolveExpr::go (elem.get (), prefix, canonical_prefix);
361 : 198 : }
362 : :
363 : : void
364 : 306 : ResolveExpr::visit (AST::ArrayExpr &expr)
365 : : {
366 : 306 : expr.get_array_elems ()->accept_vis (*this);
367 : 306 : }
368 : :
369 : : void
370 : 433 : ResolveExpr::visit (AST::ArrayIndexExpr &expr)
371 : : {
372 : 433 : ResolveExpr::go (expr.get_array_expr ().get (), prefix, canonical_prefix);
373 : 433 : ResolveExpr::go (expr.get_index_expr ().get (), prefix, canonical_prefix);
374 : 433 : }
375 : :
376 : : void
377 : 108 : ResolveExpr::visit (AST::ArrayElemsCopied &expr)
378 : : {
379 : 108 : ResolveExpr::go (expr.get_num_copies ().get (), prefix, canonical_prefix);
380 : 108 : ResolveExpr::go (expr.get_elem_to_copy ().get (), prefix, canonical_prefix);
381 : 108 : }
382 : :
383 : : // this this an empty struct constructor like 'S {}'
384 : : void
385 : 51 : ResolveExpr::visit (AST::StructExprStruct &struct_expr)
386 : : {
387 : 51 : ResolveExpr::go (&struct_expr.get_struct_name (), prefix, canonical_prefix);
388 : 51 : }
389 : :
390 : : // this this a struct constructor with fields
391 : : void
392 : 820 : ResolveExpr::visit (AST::StructExprStructFields &struct_expr)
393 : : {
394 : 820 : ResolveExpr::go (&struct_expr.get_struct_name (), prefix, canonical_prefix);
395 : :
396 : 820 : if (struct_expr.has_struct_base ())
397 : : {
398 : 63 : AST::StructBase &base = struct_expr.get_struct_base ();
399 : 63 : ResolveExpr::go (base.get_base_struct ().get (), prefix,
400 : : canonical_prefix);
401 : : }
402 : :
403 : 820 : auto const &struct_fields = struct_expr.get_fields ();
404 : 2365 : for (auto &struct_field : struct_fields)
405 : : {
406 : 1545 : ResolveStructExprField::go (struct_field.get (), prefix,
407 : : canonical_prefix);
408 : : }
409 : 820 : }
410 : :
411 : : void
412 : 160 : ResolveExpr::visit (AST::GroupedExpr &expr)
413 : : {
414 : 160 : ResolveExpr::go (expr.get_expr_in_parens ().get (), prefix, canonical_prefix);
415 : 160 : }
416 : :
417 : : void
418 : 1407 : ResolveExpr::visit (AST::FieldAccessExpr &expr)
419 : : {
420 : 1407 : ResolveExpr::go (expr.get_receiver_expr ().get (), prefix, canonical_prefix);
421 : 1407 : }
422 : :
423 : : void
424 : 90 : ResolveExpr::visit (AST::LoopExpr &expr)
425 : : {
426 : 90 : if (expr.has_loop_label ())
427 : : {
428 : 28 : auto label = expr.get_loop_label ();
429 : 28 : if (label.get_lifetime ().get_lifetime_type ()
430 : : != AST::Lifetime::LifetimeType::NAMED)
431 : : {
432 : 0 : rust_error_at (label.get_locus (),
433 : : "Labels must be a named lifetime value");
434 : 0 : return;
435 : : }
436 : :
437 : 28 : auto label_name = label.get_lifetime ().get_lifetime_name ();
438 : 28 : auto label_lifetime_node_id = label.get_lifetime ().get_node_id ();
439 : 84 : resolver->get_label_scope ().insert (
440 : 56 : CanonicalPath::new_seg (expr.get_node_id (), label_name),
441 : : label_lifetime_node_id, label.get_locus (), false, Rib::ItemType::Label,
442 : 28 : [&] (const CanonicalPath &, NodeId, location_t locus) -> void {
443 : 0 : rust_error_at (label.get_locus (), "label redefined multiple times");
444 : 0 : rust_error_at (locus, "was defined here");
445 : 0 : });
446 : 28 : }
447 : 90 : ResolveExpr::go (expr.get_loop_block ().get (), prefix, canonical_prefix);
448 : : }
449 : :
450 : : void
451 : 60 : ResolveExpr::visit (AST::BreakExpr &expr)
452 : : {
453 : 60 : if (expr.has_label ())
454 : : {
455 : 16 : auto label = expr.get_label ().get_lifetime ();
456 : 16 : if (label.get_lifetime_type () != AST::Lifetime::LifetimeType::NAMED)
457 : : {
458 : 0 : rust_error_at (label.get_locus (),
459 : : "Labels must be a named lifetime value");
460 : 0 : return;
461 : : }
462 : :
463 : 16 : NodeId resolved_node = UNKNOWN_NODEID;
464 : 32 : if (!resolver->get_label_scope ().lookup (
465 : 32 : CanonicalPath::new_seg (label.get_node_id (),
466 : 32 : label.get_lifetime_name ()),
467 : : &resolved_node))
468 : : {
469 : 1 : rust_error_at (label.get_locus (), ErrorCode::E0426,
470 : : "use of undeclared label %qs in %<break%>",
471 : 1 : label.get_lifetime_name ().c_str ());
472 : 1 : return;
473 : : }
474 : 15 : resolver->insert_resolved_label (label.get_node_id (), resolved_node);
475 : 16 : }
476 : :
477 : 59 : if (expr.has_break_expr ())
478 : : {
479 : 20 : bool funny_error = false;
480 : 20 : AST::Expr &break_expr = *expr.get_break_expr ().get ();
481 : 20 : if (break_expr.get_ast_kind () == AST::Kind::IDENTIFIER)
482 : : {
483 : : /* This is a break with an expression, and the expression is just a
484 : : single identifier. See if the identifier is either "rust" or
485 : : "gcc", in which case we have "break rust" or "break gcc", and so
486 : : may need to emit our funny error. We cannot yet emit the error
487 : : here though, because the identifier may still be in scope, and
488 : : ICE'ing on valid programs would not be very funny. */
489 : 11 : std::string ident
490 : 11 : = static_cast<AST::IdentifierExpr &> (break_expr).as_string ();
491 : 11 : if (ident == "rust" || ident == "gcc")
492 : : funny_error = true;
493 : 11 : }
494 : 20 : ResolveExpr::go (&break_expr, prefix, canonical_prefix, funny_error);
495 : : }
496 : : }
497 : :
498 : : void
499 : 35 : ResolveExpr::visit (AST::WhileLoopExpr &expr)
500 : : {
501 : 35 : if (expr.has_loop_label ())
502 : : {
503 : 1 : auto label = expr.get_loop_label ();
504 : 1 : if (label.get_lifetime ().get_lifetime_type ()
505 : : != AST::Lifetime::LifetimeType::NAMED)
506 : : {
507 : 0 : rust_error_at (label.get_locus (),
508 : : "Labels must be a named lifetime value");
509 : 0 : return;
510 : : }
511 : :
512 : 1 : auto label_name = label.get_lifetime ().get_lifetime_name ();
513 : 1 : auto label_lifetime_node_id = label.get_lifetime ().get_node_id ();
514 : 2 : resolver->get_label_scope ().insert (
515 : 2 : CanonicalPath::new_seg (label.get_node_id (), label_name),
516 : : label_lifetime_node_id, label.get_locus (), false, Rib::ItemType::Label,
517 : 1 : [&] (const CanonicalPath &, NodeId, location_t locus) -> void {
518 : 0 : rust_error_at (label.get_locus (), "label redefined multiple times");
519 : 0 : rust_error_at (locus, "was defined here");
520 : 0 : });
521 : 1 : }
522 : :
523 : 35 : ResolveExpr::go (expr.get_predicate_expr ().get (), prefix, canonical_prefix);
524 : 35 : ResolveExpr::go (expr.get_loop_block ().get (), prefix, canonical_prefix);
525 : : }
526 : :
527 : : void
528 : 0 : ResolveExpr::visit (AST::ForLoopExpr &expr)
529 : : {
530 : 0 : if (expr.has_loop_label ())
531 : : {
532 : 0 : auto label = expr.get_loop_label ();
533 : 0 : if (label.get_lifetime ().get_lifetime_type ()
534 : : != AST::Lifetime::LifetimeType::NAMED)
535 : : {
536 : 0 : rust_error_at (label.get_locus (),
537 : : "Labels must be a named lifetime value");
538 : 0 : return;
539 : : }
540 : :
541 : 0 : auto label_name = label.get_lifetime ().get_lifetime_name ();
542 : 0 : auto label_lifetime_node_id = label.get_lifetime ().get_node_id ();
543 : 0 : resolver->get_label_scope ().insert (
544 : 0 : CanonicalPath::new_seg (label.get_node_id (), label_name),
545 : : label_lifetime_node_id, label.get_locus (), false, Rib::ItemType::Label,
546 : 0 : [&] (const CanonicalPath &, NodeId, location_t locus) -> void {
547 : 0 : rust_error_at (label.get_locus (), "label redefined multiple times");
548 : 0 : rust_error_at (locus, "was defined here");
549 : 0 : });
550 : 0 : }
551 : :
552 : : // this needs a new rib to contain the pattern
553 : 0 : NodeId scope_node_id = expr.get_node_id ();
554 : 0 : resolver->get_name_scope ().push (scope_node_id);
555 : 0 : resolver->get_type_scope ().push (scope_node_id);
556 : 0 : resolver->get_label_scope ().push (scope_node_id);
557 : 0 : resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
558 : 0 : resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
559 : 0 : resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
560 : :
561 : : // resolve the expression
562 : 0 : PatternDeclaration::go (expr.get_pattern ().get (), Rib::ItemType::Var);
563 : 0 : ResolveExpr::go (expr.get_iterator_expr ().get (), prefix, canonical_prefix);
564 : 0 : ResolveExpr::go (expr.get_loop_block ().get (), prefix, canonical_prefix);
565 : :
566 : : // done
567 : 0 : resolver->get_name_scope ().pop ();
568 : 0 : resolver->get_type_scope ().pop ();
569 : 0 : resolver->get_label_scope ().pop ();
570 : : }
571 : :
572 : : void
573 : 10 : ResolveExpr::visit (AST::ContinueExpr &expr)
574 : : {
575 : 10 : if (expr.has_label ())
576 : : {
577 : 1 : auto label = expr.get_label ();
578 : 1 : if (label.get_lifetime_type () != AST::Lifetime::LifetimeType::NAMED)
579 : : {
580 : 0 : rust_error_at (label.get_locus (),
581 : : "Labels must be a named lifetime value");
582 : 0 : return;
583 : : }
584 : :
585 : 1 : NodeId resolved_node = UNKNOWN_NODEID;
586 : 2 : if (!resolver->get_label_scope ().lookup (
587 : 2 : CanonicalPath::new_seg (label.get_node_id (),
588 : 2 : label.get_lifetime_name ()),
589 : : &resolved_node))
590 : : {
591 : 1 : rust_error_at (expr.get_label ().get_locus (), ErrorCode::E0426,
592 : : "use of undeclared label %qs in %<continue%>",
593 : 1 : label.get_lifetime_name ().c_str ());
594 : 1 : return;
595 : : }
596 : 0 : resolver->insert_resolved_label (label.get_node_id (), resolved_node);
597 : 1 : }
598 : : }
599 : :
600 : : void
601 : 913 : ResolveExpr::visit (AST::BorrowExpr &expr)
602 : : {
603 : 913 : ResolveExpr::go (expr.get_borrowed_expr ().get (), prefix, canonical_prefix);
604 : 913 : }
605 : :
606 : : void
607 : 1232 : ResolveExpr::visit (AST::DereferenceExpr &expr)
608 : : {
609 : 1232 : ResolveExpr::go (expr.get_dereferenced_expr ().get (), prefix,
610 : : canonical_prefix);
611 : 1232 : }
612 : :
613 : : void
614 : 196 : ResolveExpr::visit (AST::MatchExpr &expr)
615 : : {
616 : 196 : ResolveExpr::go (expr.get_scrutinee_expr ().get (), prefix, canonical_prefix);
617 : 688 : for (auto &match_case : expr.get_match_cases ())
618 : : {
619 : : // each arm is in its own scope
620 : 492 : NodeId scope_node_id = match_case.get_node_id ();
621 : 492 : resolver->get_name_scope ().push (scope_node_id);
622 : 492 : resolver->get_type_scope ().push (scope_node_id);
623 : 492 : resolver->get_label_scope ().push (scope_node_id);
624 : 492 : resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
625 : 492 : resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
626 : 492 : resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
627 : :
628 : : // resolve
629 : 492 : AST::MatchArm &arm = match_case.get_arm ();
630 : 492 : if (arm.has_match_arm_guard ())
631 : 1 : ResolveExpr::go (arm.get_guard_expr ().get (), prefix,
632 : : canonical_prefix);
633 : :
634 : : // We know expr.get_patterns () has one pattern at most
635 : : // so there's no reason to handle it like an AltPattern.
636 : 492 : std::vector<PatternBinding> bindings
637 : 984 : = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())};
638 : :
639 : : // insert any possible new patterns
640 : 984 : for (auto &pattern : arm.get_patterns ())
641 : : {
642 : 492 : PatternDeclaration::go (pattern.get (), Rib::ItemType::Var, bindings);
643 : : }
644 : :
645 : : // resolve the body
646 : 492 : ResolveExpr::go (match_case.get_expr ().get (), prefix, canonical_prefix);
647 : :
648 : : // done
649 : 492 : resolver->get_name_scope ().pop ();
650 : 492 : resolver->get_type_scope ().pop ();
651 : 492 : resolver->get_label_scope ().pop ();
652 : 492 : }
653 : 196 : }
654 : :
655 : : void
656 : 50 : ResolveExpr::visit (AST::RangeFromToExpr &expr)
657 : : {
658 : 50 : ResolveExpr::go (expr.get_from_expr ().get (), prefix, canonical_prefix);
659 : 50 : ResolveExpr::go (expr.get_to_expr ().get (), prefix, canonical_prefix);
660 : 50 : }
661 : :
662 : : void
663 : 7 : ResolveExpr::visit (AST::RangeFromExpr &expr)
664 : : {
665 : 7 : ResolveExpr::go (expr.get_from_expr ().get (), prefix, canonical_prefix);
666 : 7 : }
667 : :
668 : : void
669 : 7 : ResolveExpr::visit (AST::RangeToExpr &expr)
670 : : {
671 : 7 : ResolveExpr::go (expr.get_to_expr ().get (), prefix, canonical_prefix);
672 : 7 : }
673 : :
674 : : void
675 : 0 : ResolveExpr::visit (AST::RangeFullExpr &)
676 : : {
677 : : // nothing to do
678 : 0 : }
679 : :
680 : : void
681 : 7 : ResolveExpr::visit (AST::RangeFromToInclExpr &expr)
682 : : {
683 : 7 : ResolveExpr::go (expr.get_from_expr ().get (), prefix, canonical_prefix);
684 : 7 : ResolveExpr::go (expr.get_to_expr ().get (), prefix, canonical_prefix);
685 : 7 : }
686 : :
687 : : void
688 : 24 : ResolveExpr::visit (AST::ClosureExprInner &expr)
689 : : {
690 : 24 : NodeId scope_node_id = expr.get_node_id ();
691 : 24 : resolver->get_name_scope ().push (scope_node_id);
692 : 24 : resolver->get_type_scope ().push (scope_node_id);
693 : 24 : resolver->get_label_scope ().push (scope_node_id);
694 : 24 : resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
695 : 24 : resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
696 : 24 : resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
697 : :
698 : 24 : std::vector<PatternBinding> bindings
699 : 48 : = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())};
700 : :
701 : 42 : for (auto &p : expr.get_params ())
702 : : {
703 : 18 : resolve_closure_param (p, bindings);
704 : : }
705 : :
706 : 24 : resolver->push_closure_context (expr.get_node_id ());
707 : :
708 : 24 : ResolveExpr::go (expr.get_definition_expr ().get (), prefix,
709 : : canonical_prefix);
710 : :
711 : 24 : resolver->pop_closure_context ();
712 : :
713 : 24 : resolver->get_name_scope ().pop ();
714 : 24 : resolver->get_type_scope ().pop ();
715 : 24 : resolver->get_label_scope ().pop ();
716 : 24 : }
717 : :
718 : : void
719 : 30 : ResolveExpr::visit (AST::ClosureExprInnerTyped &expr)
720 : : {
721 : 30 : NodeId scope_node_id = expr.get_node_id ();
722 : 30 : resolver->get_name_scope ().push (scope_node_id);
723 : 30 : resolver->get_type_scope ().push (scope_node_id);
724 : 30 : resolver->get_label_scope ().push (scope_node_id);
725 : 30 : resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
726 : 30 : resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
727 : 30 : resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
728 : :
729 : 30 : std::vector<PatternBinding> bindings
730 : 60 : = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())};
731 : :
732 : 67 : for (auto &p : expr.get_params ())
733 : : {
734 : 37 : resolve_closure_param (p, bindings);
735 : : }
736 : :
737 : 30 : ResolveType::go (expr.get_return_type ().get ());
738 : :
739 : 30 : resolver->push_closure_context (expr.get_node_id ());
740 : :
741 : 30 : ResolveExpr::go (expr.get_definition_block ().get (), prefix,
742 : : canonical_prefix);
743 : :
744 : 30 : resolver->pop_closure_context ();
745 : :
746 : 30 : resolver->get_name_scope ().pop ();
747 : 30 : resolver->get_type_scope ().pop ();
748 : 30 : resolver->get_label_scope ().pop ();
749 : 30 : }
750 : :
751 : : void
752 : 55 : ResolveExpr::resolve_closure_param (AST::ClosureParam ¶m,
753 : : std::vector<PatternBinding> &bindings)
754 : : {
755 : 55 : PatternDeclaration::go (param.get_pattern ().get (), Rib::ItemType::Param,
756 : : bindings);
757 : :
758 : 55 : if (param.has_type_given ())
759 : 51 : ResolveType::go (param.get_type ().get ());
760 : 55 : }
761 : :
762 : 75910 : ResolveExpr::ResolveExpr (const CanonicalPath &prefix,
763 : : const CanonicalPath &canonical_prefix,
764 : 75910 : bool funny_error)
765 : 75910 : : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix),
766 : 75910 : funny_error (funny_error)
767 : 75910 : {}
768 : :
769 : : } // namespace Resolver
770 : : } // namespace Rust
|