Line data Source code
1 : // Copyright (C) 2020-2026 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 : #ifndef RUST_NAME_RESOLVER_2_0_CTX_H
20 : #define RUST_NAME_RESOLVER_2_0_CTX_H
21 :
22 : #include "optional.h"
23 : #include "rust-forever-stack.h"
24 : #include "rust-hir-map.h"
25 : #include "rust-rib.h"
26 : #include "rust-stacked-contexts.h"
27 : #include "rust-item.h"
28 : #include "rust-name-resolution.h"
29 :
30 : namespace Rust {
31 : namespace Resolver2_0 {
32 :
33 : // TODO: Add missing mappings and data structures
34 :
35 : /**
36 : The data structures we need to develop need to fill in a few roles - like the
37 : original name resolver, they need to be accessible at multiple points during the
38 : pipeline to allow compiler passes such as macro expansion or typechecking to
39 : benefit from them. Unlike the original name resolution, these data structures
40 : need to be created by multiple compiler passes: Whereas the original name
41 : resolution of gccrs tries to perform name resolution in a single pass, it fails
42 : at properly handling more complex name resolution cases such as macro name
43 : resolution, imports in general, and glob imports in particular. The goal of this
44 : new name resolution algorithm is to split the name resolution in at least two
45 : passes - `Early` name resolution, which takes care of macro name resolution and
46 : import resolution, and `Late` name resolution - your typical name resolution,
47 : for types, functions, variables...
48 :
49 : 1. `Early`
50 :
51 : The Early name resolution is tied in snuggly with macro expansion: macro
52 : expansion cannot happen without some form of name resolution (pointing an
53 : invocation to its definition) but may also *depend* on name resolution (a macro
54 : generating another macro... or importing items... and funny other cases like
55 : these). It needs to work in a fixed-point fashion alongside macro expansion:
56 : While there are imports to resolve, or macros to expand, we need to keep going
57 : and resolve them. This is achieved, among other things, by a top-level name
58 : resolution pass in charge of collection use statements and macro definitions (as
59 : well as Items, which will be useful for later passes of the name resolution).
60 :
61 : This top-level pass exists because Rust enables you to call a function
62 : before having declared it (at a lexical level, i.e calling `f(15)` at line 3
63 : while the `f` function is declared at line 1499).
64 :
65 : This Early pass needs to build the first part of our "resolution map", which
66 : will then be used in multiple contexts:
67 :
68 : 1. The MacroExpander, in a read-only fashion: fetching macro definitions for
69 : each invocation and performing the expansion.
70 : 2. `Late`, which will write more data inside that resolution map, and use it
71 : to perform its name resolution too.
72 :
73 : This is where the first challenge of this data structure lies: The existing
74 : data structures and name resolution algorithm relies on the name resolution pass
75 : happening just once. In typical name resolution fashion, when it sees a lexical
76 : scope (a new module, a function's block, a block expression...), it "pushes" a
77 : new "Scope" to a stack of these scopes, and "pops" it when exiting said lexical
78 : scope. However, because we are splitting the name resolution into two passes, we
79 : would like to avoid re-doing a bunch of work we've already done - which is why
80 : this data structure needs to allow "re-entrancy", or to at least not keep as
81 : much state as the existing one, and allow for viewing the same module multiple
82 : times without throwing a fit.
83 :
84 : We will be implementing a "forever stack" of scopes, which allows the user the
85 : pushing of new scopes onto the stack, but only simulates the popping of a scope:
86 : When pushing new scopes, more space is allocated on our stack, and we keep
87 : track of this scope as being the current one - however, when popping this scope,
88 : we do not actually delete the memory associated with it: we simply mark the
89 : previous scope (parent) as the current one.
90 :
91 : In the example below, each number indicates the "state" of our resolution map,
92 : and the carret is used to point to the current lexical scope.
93 :
94 : ```rust
95 : // []
96 : //
97 : fn main() { // [ `main` scope: {} ]
98 : // ^
99 : let a = 15; // [ `main` scope: { Decl(a) } ]
100 : // ^
101 : { _PUSH_ // [ `main` scope: { Decl(a) }, anonymous scope: {} ]
102 : // ^
103 : let a = 16; // [ `main` scope: { Decl(a) }, anonymous scope: { Decl(a) } ]
104 : // ^
105 : f(a); // [ `main` scope: { Decl(a) }, anonymous scope: { Decl(a) } ]
106 : // ^
107 : } _POP_ // [ `main` scope: { Decl(a) }, anonymous scope: { Decl(a) } ]
108 : // ^
109 : f(a); // [ `main` scope: { Decl(a) }, anonymous scope: { Decl(a) } ]
110 : // ^
111 : }
112 : ```
113 :
114 : This allows us to revisit scopes previously visited in later phases of the name
115 : resolution, and add more information if necessary.
116 :
117 : 2. `Late`
118 :
119 : `Late` name resolution possesses some unique challenges since Rust's name
120 : resolution rules are extremely complex - variable shadowing, variable capture in
121 : closures (but not inner functions!)... You can have a look at a fucked up
122 : example here:
123 :
124 : https://rustc-dev-guide.rust-lang.org/name-resolution.html#scopes-and-ribs
125 :
126 : This requires us to think about what exactly to put in our `Scope`s and what to
127 : do with our `Rib`s - and how it affects our data structures. For example, in the
128 : above example, `rustc` demonstrates how multiple `Rib`s can be created inside of
129 : a single lexical scope for variables, as the Rust programming language allows
130 : shadowing.
131 :
132 : TODO: Mention macro hygiene and that it is the same
133 : TODO: How does this affect our data structures?
134 : TODO: Last challenge - reuse the same APIs to allow the typechecker to not
135 : change?
136 : TODO: Mention that ForeverStack is templated to make sure that behavior is
137 : correct
138 : */
139 :
140 : struct IdentifierMode
141 : {
142 : bool is_ref;
143 : bool is_mut;
144 :
145 24747 : IdentifierMode (bool is_ref, bool is_mut) : is_ref (is_ref), is_mut (is_mut)
146 : {}
147 :
148 58 : bool operator== (const IdentifierMode &other)
149 : {
150 58 : return other.is_ref == is_ref && other.is_mut == is_mut;
151 : }
152 :
153 232 : bool operator!= (const IdentifierMode &other) { return !(*this == other); }
154 : };
155 :
156 209732 : struct Binding
157 : {
158 : enum class Kind
159 : {
160 : Product,
161 : Or,
162 : } kind;
163 :
164 : // used to check the correctness of or-bindings
165 : bool has_expected_bindings;
166 :
167 : std::unordered_map<std::string, std::pair<location_t, IdentifierMode>> idents;
168 :
169 35153 : Binding (Binding::Kind kind) : kind (kind), has_expected_bindings (false) {}
170 : };
171 :
172 : /**
173 : * Used to identify the source of a binding, and emit the correct error message.
174 : */
175 : enum class BindingSource
176 : {
177 : Match,
178 : Let,
179 : IfLet,
180 : WhileLet,
181 : For,
182 : /* Closure param or function param */
183 : Param
184 : };
185 :
186 138250 : class BindingLayer
187 : {
188 : BindingSource source;
189 : std::vector<Binding> bindings;
190 :
191 : bool bind_test (Identifier ident, Binding::Kind kind);
192 :
193 : public:
194 : void push (Binding::Kind kind);
195 :
196 : BindingLayer (BindingSource source);
197 :
198 : /**
199 : * Identifies if the identifier has been used in a product binding context.
200 : * eg. `let (a, a) = test();`
201 : */
202 : bool is_and_bound (Identifier ident);
203 :
204 : /**
205 : * Identifies if the identifier has been used in a or context.
206 : * eg. `let (a, 1) | (a, 2) = test()`
207 : */
208 : bool is_or_bound (Identifier ident);
209 :
210 : void insert_ident (std::string ident, location_t locus, bool is_ref,
211 : bool is_mut);
212 :
213 : void merge ();
214 :
215 : BindingSource get_source () const;
216 : };
217 :
218 : class NameResolutionContext;
219 : /*
220 : * Used to handle canonical paths
221 : * Similar to ForeverStack, but namespace independent and more specialized
222 : */
223 41581 : class CanonicalPathRecord
224 : {
225 : public:
226 : virtual Resolver::CanonicalPath as_path (const NameResolutionContext &,
227 : Namespace ns)
228 : = 0;
229 :
230 : virtual bool is_root () const = 0;
231 :
232 : virtual ~CanonicalPathRecord () = default;
233 : };
234 :
235 : class CanonicalPathRecordWithParent : public CanonicalPathRecord
236 : {
237 : public:
238 36786 : CanonicalPathRecordWithParent (CanonicalPathRecord &parent) : parent (&parent)
239 : {}
240 :
241 412019 : CanonicalPathRecord &get_parent () { return *parent; }
242 :
243 245715 : bool is_root () const override final { return false; }
244 :
245 : private:
246 : CanonicalPathRecord *parent;
247 : };
248 :
249 : class CanonicalPathRecordCrateRoot : public CanonicalPathRecord
250 : {
251 : public:
252 4795 : CanonicalPathRecordCrateRoot (NodeId node_id, std::string seg)
253 4795 : : node_id (node_id), seg (std::move (seg))
254 : {
255 4795 : rust_assert (Analysis::Mappings::get ().node_is_crate (node_id));
256 4795 : crate_num = Analysis::Mappings::get ().lookup_crate_num (node_id).value ();
257 4795 : }
258 :
259 : Resolver::CanonicalPath as_path (const NameResolutionContext &,
260 : Namespace ns) override;
261 :
262 31646 : bool is_root () const override final { return true; }
263 :
264 : private:
265 : NodeId node_id;
266 : CrateNum crate_num;
267 : std::string seg;
268 : };
269 :
270 : class CanonicalPathRecordNormal : public CanonicalPathRecordWithParent
271 : {
272 : public:
273 30975 : CanonicalPathRecordNormal (CanonicalPathRecord &parent, NodeId node_id,
274 : std::string seg)
275 30975 : : CanonicalPathRecordWithParent (parent), node_id (node_id),
276 30975 : seg (std::move (seg))
277 : {
278 30975 : rust_assert (!Analysis::Mappings::get ().node_is_crate (node_id));
279 30975 : }
280 :
281 : Resolver::CanonicalPath as_path (const NameResolutionContext &,
282 : Namespace ns) override;
283 :
284 : private:
285 : NodeId node_id;
286 : std::string seg;
287 : };
288 :
289 : class CanonicalPathRecordLookup : public CanonicalPathRecord
290 : {
291 : public:
292 5811 : CanonicalPathRecordLookup (NodeId lookup_id)
293 5811 : : lookup_id (lookup_id), cache (nullptr)
294 : {}
295 :
296 : Resolver::CanonicalPath as_path (const NameResolutionContext &,
297 : Namespace ns) override;
298 :
299 0 : bool is_root () const override final { return true; }
300 :
301 : private:
302 : NodeId lookup_id;
303 : CanonicalPathRecord *cache;
304 : };
305 :
306 : class CanonicalPathRecordImpl : public CanonicalPathRecordWithParent
307 : {
308 : public:
309 999 : CanonicalPathRecordImpl (CanonicalPathRecord &parent, NodeId impl_id,
310 : NodeId type_id)
311 999 : : CanonicalPathRecordWithParent (parent), impl_id (impl_id),
312 999 : type_record (type_id)
313 : {}
314 :
315 : Resolver::CanonicalPath as_path (const NameResolutionContext &,
316 : Namespace ns) override;
317 :
318 : private:
319 : NodeId impl_id;
320 : CanonicalPathRecordLookup type_record;
321 : };
322 :
323 : class CanonicalPathRecordTraitImpl : public CanonicalPathRecordWithParent
324 : {
325 : public:
326 4812 : CanonicalPathRecordTraitImpl (CanonicalPathRecord &parent, NodeId impl_id,
327 : NodeId type_id, NodeId trait_path_id)
328 4812 : : CanonicalPathRecordWithParent (parent), impl_id (impl_id),
329 4812 : type_record (type_id), trait_path_record (trait_path_id)
330 : {}
331 :
332 : Resolver::CanonicalPath as_path (const NameResolutionContext &,
333 : Namespace ns) override;
334 :
335 : private:
336 : NodeId impl_id;
337 : CanonicalPathRecordLookup type_record;
338 : CanonicalPathRecordLookup trait_path_record;
339 : };
340 :
341 : class CanonicalPathCtx
342 : {
343 : public:
344 4771 : CanonicalPathCtx (const NameResolutionContext &ctx)
345 4771 : : current_record (nullptr), nr_ctx (&ctx)
346 : {}
347 :
348 60392 : Resolver::CanonicalPath get_path (NodeId id, Namespace ns) const
349 : {
350 60392 : return get_record (id).as_path (*nr_ctx, ns);
351 : }
352 :
353 60392 : CanonicalPathRecord &get_record (NodeId id) const
354 : {
355 60392 : auto it = records.find (id);
356 60392 : rust_assert (it != records.end ());
357 60392 : return *it->second;
358 : }
359 :
360 9370 : tl::optional<CanonicalPathRecord *> get_record_opt (NodeId id) const
361 : {
362 9370 : auto it = records.find (id);
363 9370 : if (it == records.end ())
364 4348 : return tl::nullopt;
365 : else
366 5022 : return it->second.get ();
367 : }
368 :
369 : void insert_record (NodeId id, const Identifier &ident)
370 : {
371 : insert_record (id, ident.as_string ());
372 : }
373 :
374 : void insert_record (NodeId id, std::string seg)
375 : {
376 : rust_assert (current_record != nullptr);
377 :
378 : auto it = records.find (id);
379 : if (it == records.end ())
380 : {
381 : auto record = new CanonicalPathRecordNormal (*current_record, id,
382 : std::move (seg));
383 : bool ok
384 : = records.emplace (id, std::unique_ptr<CanonicalPathRecord> (record))
385 : .second;
386 : rust_assert (ok);
387 : }
388 : }
389 :
390 207088 : template <typename F> void scope (NodeId id, const Identifier &ident, F &&f)
391 : {
392 414176 : scope (id, ident.as_string (), std::forward<F> (f));
393 207086 : }
394 :
395 207088 : template <typename F> void scope (NodeId id, std::string seg, F &&f)
396 : {
397 207088 : rust_assert (current_record != nullptr);
398 :
399 238063 : scope_inner (id, std::forward<F> (f), [this, id, &seg] () {
400 30975 : return new CanonicalPathRecordNormal (*current_record, id,
401 30975 : std::move (seg));
402 : });
403 207086 : }
404 :
405 6488 : template <typename F> void scope_impl (AST::InherentImpl &impl, F &&f)
406 : {
407 6488 : rust_assert (current_record != nullptr);
408 :
409 6488 : NodeId id = impl.get_node_id ();
410 6488 : scope_inner (id, std::forward<F> (f), [this, id, &impl] () {
411 999 : return new CanonicalPathRecordImpl (*current_record, id,
412 999 : impl.get_type ().get_node_id ());
413 : });
414 6488 : }
415 :
416 32139 : template <typename F> void scope_impl (AST::TraitImpl &impl, F &&f)
417 : {
418 32139 : rust_assert (current_record != nullptr);
419 :
420 32139 : NodeId id = impl.get_node_id ();
421 32139 : scope_inner (id, std::forward<F> (f), [this, id, &impl] () {
422 4812 : return new CanonicalPathRecordTraitImpl (
423 4812 : *current_record, id, impl.get_type ().get_node_id (),
424 4812 : impl.get_trait_path ().get_node_id ());
425 : });
426 32139 : }
427 :
428 : template <typename F>
429 31646 : void scope_crate (NodeId node_id, std::string crate_name, F &&f)
430 : {
431 36441 : scope_inner (node_id, std::forward<F> (f), [node_id, &crate_name] () {
432 4795 : return new CanonicalPathRecordCrateRoot (node_id, std::move (crate_name));
433 : });
434 : }
435 :
436 : private:
437 : template <typename FCreate, typename FCallback>
438 277361 : void scope_inner (NodeId id, FCallback &&f_callback, FCreate &&f_create)
439 : {
440 277361 : auto it = records.find (id);
441 277361 : if (it == records.end ())
442 : {
443 41581 : CanonicalPathRecord *record = std::forward<FCreate> (f_create) ();
444 41581 : it = records.emplace (id, std::unique_ptr<CanonicalPathRecord> (record))
445 : .first;
446 : }
447 :
448 277361 : rust_assert (it->second->is_root ()
449 : || &static_cast<CanonicalPathRecordWithParent &> (*it->second)
450 : .get_parent ()
451 : == current_record);
452 :
453 277361 : CanonicalPathRecord *stash = it->second.get ();
454 277361 : std::swap (stash, current_record);
455 :
456 277357 : std::forward<FCallback> (f_callback) ();
457 :
458 277357 : std::swap (stash, current_record);
459 277357 : }
460 :
461 : std::unordered_map<NodeId, std::unique_ptr<CanonicalPathRecord>> records;
462 : CanonicalPathRecord *current_record;
463 :
464 : const NameResolutionContext *nr_ctx;
465 : };
466 :
467 : // Now our resolver, which keeps track of all the `ForeverStack`s we could want
468 : class NameResolutionContext
469 : {
470 : public:
471 : NameResolutionContext ();
472 :
473 : /**
474 : * Insert a new value in the current rib.
475 : *
476 : * @param name Name of the value to insert.
477 : * @param id This value's ID, e.g the function definition's node ID.
478 : * @param ns Namespace in which to insert the value.
479 : */
480 : tl::expected<NodeId, DuplicateNameError> insert (Identifier name, NodeId id,
481 : Namespace ns);
482 :
483 : tl::expected<NodeId, DuplicateNameError>
484 : insert_variant (Identifier name, NodeId id, bool is_also_value);
485 :
486 : tl::expected<NodeId, DuplicateNameError>
487 : insert_shadowable (Identifier name, NodeId id, Namespace ns);
488 :
489 : tl::expected<NodeId, DuplicateNameError>
490 : insert_globbed (Identifier name, NodeId id, Namespace ns);
491 :
492 : /**
493 : * Run a lambda in a "scoped" context, meaning that a new `Rib` will be pushed
494 : * before executing the lambda and then popped. This is useful for all kinds
495 : * of scope in the language, such as a block expression or when entering a
496 : * function. This variant of the function enters a new scope in *all*
497 : * namespaces, while the second variant enters a scope in *one* namespace.
498 : *
499 : * @param rib_kind New `Rib` to create when entering this scope. A function
500 : * `Rib`, or an item `Rib`... etc
501 : * @param scope_id node ID of the scope we are entering, e.g the block's
502 : * `NodeId`.
503 : * @param lambda Function to run within that scope
504 : * @param path Optional path of the scope. This is useful for scopes which
505 : * affect path resolution, such as modules. Defaults to an empty
506 : * option.
507 : */
508 : // FIXME: Do we want to handle something in particular for expected within the
509 : // scoped lambda?
510 : void scoped (Rib::Kind rib_kind, NodeId scope_id,
511 : std::function<void (void)> lambda,
512 : tl::optional<Identifier> path = {});
513 : void scoped (Rib::Kind rib_kind, Namespace ns, NodeId scope_id,
514 : std::function<void (void)> lambda,
515 : tl::optional<Identifier> path = {});
516 :
517 : ForeverStack<Namespace::Values> values;
518 : ForeverStack<Namespace::Types> types;
519 : ForeverStack<Namespace::Macros> macros;
520 : ForeverStack<Namespace::Labels> labels;
521 :
522 : Analysis::Mappings &mappings;
523 : StackedContexts<BindingLayer> bindings;
524 :
525 : CanonicalPathCtx canonical_ctx;
526 :
527 : /**
528 : * The result type for a multi-namespace call to
529 : * NameResolutionContext::lookup()
530 : */
531 : struct NSLookup
532 : {
533 : NodeId id;
534 : Namespace ns;
535 :
536 186409 : NSLookup (NodeId id, Namespace ns) : id (id), ns (ns) {}
537 : };
538 :
539 : /**
540 : * These functions are mostly useful for the FinalizedNameResolutionContext
541 : * and used in later passes of the pipeline. They don't need to know as much
542 : * about a definition, hence why they don't use the NamespacedDefinition which
543 : * returns a Rib::Definition.
544 : */
545 : void map_usage (Usage usage, Definition definition, Namespace ns);
546 : tl::optional<NodeId> lookup (NodeId usage, Namespace ns) const;
547 :
548 : /**
549 : * The order of namespaces is important - if the usage resolves in the first
550 : * namespace, then it will be returned. Collisions are not guarded against and
551 : * should NOT happen. This is for looking up usages once name resolution is
552 : * done and we are in later stages of the pipeline.
553 : */
554 : tl::optional<NSLookup> lookup (NodeId usage, Namespace ns1,
555 : Namespace ns2) const;
556 : tl::optional<NSLookup> lookup (NodeId usage, Namespace ns1, Namespace ns2,
557 : Namespace ns3) const;
558 :
559 : Resolver::CanonicalPath to_canonical_path (NodeId id, Namespace ns) const
560 : {
561 : return canonical_ctx.get_path (id, ns);
562 : }
563 :
564 : /**
565 : * The return value when the namespace in which a definition was resolved
566 : * matters
567 : */
568 504062 : struct NamespacedDefinition
569 : {
570 83159 : explicit NamespacedDefinition (Rib::Definition definition, Namespace ns)
571 2807 : : definition (definition), ns (ns)
572 : {}
573 :
574 : static tl::optional<NamespacedDefinition>
575 87063 : Maybe (tl::optional<Rib::Definition> definition, Namespace ns)
576 : {
577 254478 : return definition.map ([ns] (Rib::Definition definition) {
578 80352 : return NamespacedDefinition (definition, ns);
579 87063 : });
580 : }
581 :
582 : Rib::Definition definition;
583 : Namespace ns;
584 : };
585 :
586 : tl::optional<NamespacedDefinition>
587 87063 : resolve_path (const ResolutionPath &path, ResolutionMode mode,
588 : std::vector<Error> &collect_errors, Namespace ns)
589 : {
590 87063 : std::function<void (Usage, Definition, Namespace)> insert_segment_resolution
591 87063 : = [this] (Usage seg_id, Definition id, Namespace ns) {
592 99519 : map_usage (seg_id, id, ns);
593 87063 : };
594 :
595 87063 : tl::optional<NamespacedDefinition> resolved = tl::nullopt;
596 :
597 87063 : switch (ns)
598 : {
599 25586 : case Namespace::Values:
600 51172 : resolved = NamespacedDefinition::Maybe (
601 51172 : resolve_path (values, path, mode, insert_segment_resolution,
602 : collect_errors),
603 25586 : ns);
604 25586 : break;
605 59962 : case Namespace::Types:
606 119924 : resolved = NamespacedDefinition::Maybe (
607 119924 : resolve_path (types, path, mode, insert_segment_resolution,
608 : collect_errors),
609 59962 : ns);
610 59962 : break;
611 1515 : case Namespace::Macros:
612 3030 : resolved = NamespacedDefinition::Maybe (
613 3030 : resolve_path (macros, path, mode, insert_segment_resolution,
614 : collect_errors),
615 1515 : ns);
616 1515 : break;
617 0 : case Namespace::Labels:
618 0 : resolved = NamespacedDefinition::Maybe (
619 0 : resolve_path (labels, path, mode, insert_segment_resolution,
620 : collect_errors),
621 0 : ns);
622 0 : break;
623 0 : default:
624 0 : rust_unreachable ();
625 : }
626 :
627 : // If it fails, switch to std prelude resolution if it exists
628 87063 : if (prelude && !resolved)
629 : {
630 : // TODO: Factor this with the above
631 0 : switch (ns)
632 : {
633 0 : case Namespace::Values:
634 0 : return NamespacedDefinition::Maybe (
635 0 : resolve_path (values, path, mode, insert_segment_resolution,
636 0 : collect_errors, *prelude),
637 0 : ns);
638 0 : case Namespace::Types:
639 0 : return NamespacedDefinition::Maybe (
640 0 : resolve_path (types, path, mode, insert_segment_resolution,
641 0 : collect_errors, *prelude),
642 0 : ns);
643 0 : case Namespace::Macros:
644 0 : return NamespacedDefinition::Maybe (
645 0 : resolve_path (macros, path, mode, insert_segment_resolution,
646 0 : collect_errors, *prelude),
647 0 : ns);
648 0 : case Namespace::Labels:
649 0 : return NamespacedDefinition::Maybe (
650 0 : resolve_path (labels, path, mode, insert_segment_resolution,
651 0 : collect_errors, *prelude),
652 0 : ns);
653 : default:
654 : rust_unreachable ();
655 : }
656 : }
657 :
658 87063 : return resolved;
659 87063 : }
660 :
661 85445 : class ResolutionBuilder
662 : {
663 : public:
664 85445 : ResolutionBuilder (NameResolutionContext &ctx) : ctx (&ctx) {}
665 :
666 : template <typename S>
667 85380 : void set_path (const std::vector<S> &path_segments, NodeId node_id,
668 : bool has_opening_scope)
669 : {
670 85380 : path = ResolutionPath (path_segments, node_id);
671 85380 : mode = ResolutionMode::Normal;
672 85380 : if (has_opening_scope)
673 : {
674 739 : if (get_rust_edition () == Edition::E2015)
675 739 : mode = ResolutionMode::FromRoot;
676 : else
677 0 : mode = ResolutionMode::FromExtern;
678 : }
679 85380 : has_path_set = true;
680 85380 : }
681 :
682 : template <typename S>
683 65 : void set_path (const std::vector<S> &path_segments, NodeId node_id,
684 : ResolutionMode mode)
685 : {
686 65 : path = ResolutionPath (path_segments, node_id);
687 65 : this->mode = mode;
688 65 : has_path_set = true;
689 65 : }
690 :
691 : void set_path (const AST::SimplePath &path)
692 : {
693 : set_path (path.get_segments (), path.get_node_id (),
694 : path.has_opening_scope_resolution ());
695 : }
696 :
697 : void set_path (const AST::PathInExpression &path)
698 : {
699 : set_path (path.get_segments (), path.get_node_id (),
700 : path.opening_scope_resolution ());
701 : }
702 :
703 : void set_path (const AST::TypePath &path)
704 : {
705 : set_path (path.get_segments (), path.get_node_id (),
706 : path.has_opening_scope_resolution_op ());
707 : }
708 :
709 : void set_mode (ResolutionMode mode) { this->mode = mode; }
710 :
711 109885 : void add_namespaces (Namespace ns) { namespace_list.push_back (ns); }
712 :
713 24440 : template <typename... Args> void add_namespaces (Namespace ns, Args... rest)
714 : {
715 24440 : add_namespaces (ns);
716 24440 : add_namespaces (rest...);
717 24440 : }
718 :
719 3438 : void set_collect_errors (tl::optional<std::vector<Error> &> collect_errors)
720 : {
721 3438 : this->collect_errors = collect_errors;
722 : }
723 :
724 85445 : tl::optional<NamespacedDefinition> resolve ()
725 : {
726 85445 : rust_assert (has_path_set);
727 :
728 92156 : for (auto ns : namespace_list)
729 : {
730 87063 : std::vector<Error> collect_errors_inner;
731 87063 : if (auto ret
732 87063 : = ctx->resolve_path (path, mode, collect_errors_inner, ns))
733 87063 : return ret;
734 6711 : if (!collect_errors_inner.empty ())
735 : {
736 12 : if (collect_errors.has_value ())
737 : {
738 6 : std::move (collect_errors_inner.begin (),
739 : collect_errors_inner.end (),
740 : std::back_inserter (collect_errors.value ()));
741 : }
742 : else
743 : {
744 12 : for (auto &e : collect_errors_inner)
745 6 : e.emit ();
746 : }
747 : }
748 87063 : }
749 :
750 5093 : return tl::nullopt;
751 : }
752 :
753 : private:
754 : ResolutionPath path;
755 : ResolutionMode mode;
756 : bool has_path_set;
757 :
758 : std::vector<Namespace> namespace_list;
759 :
760 : tl::optional<std::vector<Error> &> collect_errors;
761 :
762 : NameResolutionContext *ctx;
763 : };
764 :
765 : template <typename S, typename... Args>
766 : tl::optional<NamespacedDefinition>
767 : resolve_path (const std::vector<S> &path_segments, ResolutionMode mode,
768 : tl::optional<std::vector<Error> &> collect_errors,
769 : Namespace ns_first, Args... ns_args)
770 : {
771 : ResolutionBuilder builder (*this);
772 : builder.set_path (path_segments, UNKNOWN_NODEID, mode);
773 : builder.add_namespaces (ns_first, ns_args...);
774 : builder.set_collect_errors (collect_errors);
775 :
776 : return builder.resolve ();
777 : }
778 :
779 : template <typename S, typename... Args>
780 : tl::optional<NamespacedDefinition>
781 3438 : resolve_path (const std::vector<S> &path_segments,
782 : bool has_opening_scope_resolution,
783 : tl::optional<std::vector<Error> &> collect_errors,
784 : Namespace ns_first, Args... ns_args)
785 : {
786 3438 : ResolutionBuilder builder (*this);
787 3438 : builder.set_path (path_segments, UNKNOWN_NODEID,
788 : has_opening_scope_resolution);
789 3438 : builder.add_namespaces (ns_first, ns_args...);
790 3438 : builder.set_collect_errors (collect_errors);
791 :
792 3438 : return builder.resolve ();
793 3438 : }
794 :
795 : template <typename S, typename... Args>
796 : tl::optional<NamespacedDefinition>
797 81942 : resolve_path (const std::vector<S> &path_segments,
798 : bool has_opening_scope_resolution, Namespace ns_first,
799 : Args... ns_args)
800 : {
801 81942 : ResolutionBuilder builder (*this);
802 81942 : builder.set_path (path_segments, UNKNOWN_NODEID,
803 : has_opening_scope_resolution);
804 81942 : builder.add_namespaces (ns_first, ns_args...);
805 :
806 81942 : return builder.resolve ();
807 81942 : }
808 :
809 : template <typename S, typename... Args>
810 : tl::optional<NamespacedDefinition>
811 65 : resolve_path (const std::vector<S> &path_segments, ResolutionMode mode,
812 : Namespace ns_first, Args... ns_args)
813 : {
814 65 : ResolutionBuilder builder (*this);
815 65 : builder.set_path (path_segments, UNKNOWN_NODEID, mode);
816 65 : builder.add_namespaces (ns_first, ns_args...);
817 :
818 65 : return builder.resolve ();
819 65 : }
820 :
821 : template <typename... Args>
822 3937 : tl::optional<NamespacedDefinition> resolve_path (const AST::SimplePath &path,
823 : Args &&...args)
824 : {
825 3438 : return resolve_path (path.get_segments (),
826 3937 : path.has_opening_scope_resolution (),
827 3937 : std::forward<Args> (args)...);
828 : }
829 :
830 : template <typename... Args>
831 : tl::optional<NamespacedDefinition>
832 25894 : resolve_path (const AST::PathInExpression &path, Args &&...args)
833 : {
834 25894 : return resolve_path (path.get_segments (), path.opening_scope_resolution (),
835 25894 : std::forward<Args> (args)...);
836 : }
837 :
838 : template <typename... Args>
839 55549 : tl::optional<NamespacedDefinition> resolve_path (const AST::TypePath &path,
840 : Args &&...args)
841 : {
842 : return resolve_path (path.get_segments (),
843 55549 : path.has_opening_scope_resolution_op (),
844 55549 : std::forward<Args> (args)...);
845 : }
846 :
847 : // We disable this function for now as it causes regressions, but I think it
848 : // is important for a more proper final nameres context - need to investigate
849 : #if 0
850 : /**
851 : * We've now collected every definition and import, and errored out when
852 : * necessary if multiple definitions are colliding. Do a final flattening of
853 : * the name resolution context to make it easier to digest for the late name
854 : * resolution and type-checker. This basically turns the `resolved_nodes`
855 : * map from a linked-list-like map to a regular, flat hashmap.
856 : *
857 : * FIXME: The documentation is wrong, this needs to also run after all
858 : * usages have been *resolved* so after Late as well!!!
859 : *
860 : * TODO: Should this return something like the FinalizedNameResolutionCtx?
861 : * Or set it up at least? And instead of mutating the `resolved_nodes` map,
862 : * create a new one for the FinalizedNameResolutionCtx?
863 : * Actually, since Late uses the NRCtx directly we should mutate this. Most
864 : * later passes don't look at this map. So let's go for side-effects in a
865 : * void function, yipee.
866 : */
867 : void flatten ();
868 : #endif
869 :
870 : /* If declared with #[prelude_import], the current standard library module
871 : */
872 : tl::optional<NodeId> prelude;
873 :
874 : private:
875 : template <Namespace N>
876 : bool
877 : should_search_prelude (const typename ForeverStack<N>::Node *current_node,
878 : const typename ForeverStack<N>::SegIterator &iterator,
879 : const std::vector<ResolutionPath::Segment> &segments);
880 :
881 : /**
882 : * Resolve a path to its definition
883 : *
884 : * // TODO: Add documentation for `segments`
885 : *
886 : * @return a valid option with the Definition if the path is present in the
887 : * current map, an empty one otherwise.
888 : */
889 : template <Namespace N>
890 : tl::optional<Rib::Definition>
891 : resolve_path (ForeverStack<N> &stack, const ResolutionPath &path,
892 : ResolutionMode mode,
893 : std::function<void (Usage, Definition, Namespace)>
894 : insert_segment_resolution,
895 : std::vector<Error> &collect_errors);
896 :
897 : template <Namespace N>
898 : tl::optional<Rib::Definition>
899 : resolve_path (ForeverStack<N> &stack, const ResolutionPath &path,
900 : ResolutionMode mode,
901 : std::function<void (Usage, Definition, Namespace)>
902 : insert_segment_resolution,
903 : std::vector<Error> &collect_errors, NodeId starting_point_id);
904 :
905 : template <Namespace N>
906 : tl::optional<Rib::Definition> resolve_path (
907 : ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode,
908 : std::function<void (Usage, Definition, Namespace)>
909 : insert_segment_resolution,
910 : std::vector<Error> &collect_errors,
911 : std::reference_wrapper<typename ForeverStack<N>::Node> starting_point);
912 :
913 : template <Namespace N>
914 : tl::optional<typename ForeverStack<N>::Node &>
915 : resolve_segments (ForeverStack<N> &stack,
916 : typename ForeverStack<N>::Node &starting_point,
917 : const std::vector<ResolutionPath::Segment> &segments,
918 : typename ForeverStack<N>::SegIterator iterator,
919 : std::function<void (Usage, Definition, Namespace)>
920 : insert_segment_resolution,
921 : std::vector<Error> &collect_errors);
922 :
923 : template <Namespace N>
924 : tl::optional<Rib::Definition>
925 : resolve_final_segment (ForeverStack<N> &stack,
926 : typename ForeverStack<N>::Node &final_node,
927 : std::string &seg_name, bool is_lower_self);
928 : };
929 :
930 : } // namespace Resolver2_0
931 : } // namespace Rust
932 :
933 : #include "rust-name-resolution-context.hxx"
934 :
935 : #endif // ! RUST_NAME_RESOLVER_2_0_CTX_H
|