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 45059 : IdentifierMode (bool is_ref, bool is_mut) : is_ref (is_ref), is_mut (is_mut)
146 : {}
147 :
148 61 : bool operator== (const IdentifierMode &other)
149 : {
150 61 : return other.is_ref == is_ref && other.is_mut == is_mut;
151 : }
152 :
153 244 : bool operator!= (const IdentifierMode &other) { return !(*this == other); }
154 : };
155 :
156 641780 : 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 107224 : 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 425830 : 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 73241 : 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 68095 : CanonicalPathRecordWithParent (NodeId parent_node_id)
239 68095 : : parent_node_id (parent_node_id)
240 : {}
241 :
242 2047265 : NodeId get_parent () { return parent_node_id; }
243 :
244 1952447 : bool is_root () const override final { return false; }
245 :
246 : private:
247 : NodeId parent_node_id;
248 : };
249 :
250 : class CanonicalPathRecordCrateRoot : public CanonicalPathRecord
251 : {
252 : public:
253 5146 : CanonicalPathRecordCrateRoot (NodeId node_id, std::string seg)
254 5146 : : node_id (node_id), seg (std::move (seg))
255 : {
256 5146 : rust_assert (Analysis::Mappings::get ().crate.node_is_crate (node_id));
257 5146 : crate_num
258 5146 : = Analysis::Mappings::get ().crate.lookup_crate_num (node_id).value ();
259 5146 : }
260 :
261 : Resolver::CanonicalPath as_path (const NameResolutionContext &,
262 : Namespace ns) override;
263 :
264 33670 : bool is_root () const override final { return true; }
265 :
266 : private:
267 : NodeId node_id;
268 : CrateNum crate_num;
269 : std::string seg;
270 : };
271 :
272 : class CanonicalPathRecordNormal : public CanonicalPathRecordWithParent
273 : {
274 : public:
275 53369 : CanonicalPathRecordNormal (NodeId parent_node_id, NodeId node_id,
276 : std::string seg)
277 53369 : : CanonicalPathRecordWithParent (parent_node_id), node_id (node_id),
278 53369 : seg (std::move (seg))
279 : {
280 53369 : rust_assert (!Analysis::Mappings::get ().crate.node_is_crate (node_id));
281 53369 : }
282 :
283 : Resolver::CanonicalPath as_path (const NameResolutionContext &,
284 : Namespace ns) override;
285 :
286 : private:
287 : NodeId node_id;
288 : std::string seg;
289 : };
290 :
291 : class CanonicalPathRecordLookup : public CanonicalPathRecord
292 : {
293 : public:
294 14726 : CanonicalPathRecordLookup (NodeId lookup_id)
295 14726 : : lookup_id (lookup_id), cache (nullptr)
296 : {}
297 :
298 : Resolver::CanonicalPath as_path (const NameResolutionContext &,
299 : Namespace ns) override;
300 :
301 0 : bool is_root () const override final { return true; }
302 :
303 : private:
304 : NodeId lookup_id;
305 : CanonicalPathRecord *cache;
306 : };
307 :
308 : class CanonicalPathRecordImpl : public CanonicalPathRecordWithParent
309 : {
310 : public:
311 1544 : CanonicalPathRecordImpl (NodeId parent_node_id, NodeId impl_id,
312 : NodeId type_id)
313 1544 : : CanonicalPathRecordWithParent (parent_node_id), impl_id (impl_id),
314 1544 : type_record (type_id)
315 : {}
316 :
317 : Resolver::CanonicalPath as_path (const NameResolutionContext &,
318 : Namespace ns) override;
319 :
320 : private:
321 : NodeId impl_id;
322 : CanonicalPathRecordLookup type_record;
323 : };
324 :
325 : class CanonicalPathRecordTraitImpl : public CanonicalPathRecordWithParent
326 : {
327 : public:
328 13182 : CanonicalPathRecordTraitImpl (NodeId parent_node_id, NodeId impl_id,
329 : NodeId type_id, NodeId trait_path_id)
330 13182 : : CanonicalPathRecordWithParent (parent_node_id), impl_id (impl_id),
331 13182 : type_record (type_id), trait_path_record (trait_path_id)
332 : {}
333 :
334 : Resolver::CanonicalPath as_path (const NameResolutionContext &,
335 : Namespace ns) override;
336 :
337 : private:
338 : NodeId impl_id;
339 : CanonicalPathRecordLookup type_record;
340 : CanonicalPathRecordLookup trait_path_record;
341 : };
342 :
343 : class CanonicalPathCtx
344 : {
345 : public:
346 5098 : CanonicalPathCtx (const NameResolutionContext &ctx)
347 5098 : : current_record (UNKNOWN_NODEID), nr_ctx (&ctx)
348 : {}
349 :
350 41764 : Resolver::CanonicalPath get_path (NodeId id, Namespace ns) const
351 : {
352 41764 : return get_record (id).as_path (*nr_ctx, ns);
353 : }
354 :
355 136582 : CanonicalPathRecord &get_record (NodeId id) const
356 : {
357 136582 : auto it = records.find (id);
358 136582 : rust_assert (it != records.end ());
359 136582 : return *it->second;
360 : }
361 :
362 10823 : tl::optional<CanonicalPathRecord *> get_record_opt (NodeId id) const
363 : {
364 10823 : auto it = records.find (id);
365 10823 : if (it == records.end ())
366 5214 : return tl::nullopt;
367 : else
368 5609 : return it->second.get ();
369 : }
370 :
371 : void insert_record (NodeId id, const Identifier &ident)
372 : {
373 : insert_record (id, ident.as_string ());
374 : }
375 :
376 : void insert_record (NodeId id, std::string seg)
377 : {
378 : rust_assert (current_record != UNKNOWN_NODEID);
379 :
380 : auto it = records.find (id);
381 : if (it == records.end ())
382 : {
383 : auto record
384 : = new CanonicalPathRecordNormal (current_record, id, std::move (seg));
385 : bool ok
386 : = records.emplace (id, std::unique_ptr<CanonicalPathRecord> (record))
387 : .second;
388 : rust_assert (ok);
389 : }
390 : }
391 :
392 1418820 : template <typename F> void scope (NodeId id, const Identifier &ident, F &&f)
393 : {
394 2837640 : scope (id, ident.as_string (), std::forward<F> (f));
395 1418818 : }
396 :
397 1418820 : template <typename F> void scope (NodeId id, std::string seg, F &&f)
398 : {
399 1418820 : rust_assert (current_record != UNKNOWN_NODEID);
400 :
401 1472189 : scope_inner (id, std::forward<F> (f), [this, id, &seg] () {
402 53369 : return new CanonicalPathRecordNormal (current_record, id,
403 53369 : std::move (seg));
404 : });
405 1418818 : }
406 :
407 29590 : template <typename F> void scope_impl (AST::InherentImpl &impl, F &&f)
408 : {
409 29590 : rust_assert (current_record != UNKNOWN_NODEID);
410 :
411 29590 : NodeId id = impl.get_node_id ();
412 29590 : scope_inner (id, std::forward<F> (f), [this, id, &impl] () {
413 1544 : return new CanonicalPathRecordImpl (current_record, id,
414 1544 : impl.get_type ().get_node_id ());
415 : });
416 29590 : }
417 :
418 504037 : template <typename F> void scope_impl (AST::TraitImpl &impl, F &&f)
419 : {
420 504037 : rust_assert (current_record != UNKNOWN_NODEID);
421 :
422 504037 : NodeId id = impl.get_node_id ();
423 504037 : scope_inner (id, std::forward<F> (f), [this, id, &impl] () {
424 13182 : return new CanonicalPathRecordTraitImpl (
425 13182 : current_record, id, impl.get_type ().get_node_id (),
426 13182 : impl.get_trait_path ().get_node_id ());
427 : });
428 504037 : }
429 :
430 : template <typename F>
431 33670 : void scope_crate (NodeId node_id, std::string crate_name, F &&f)
432 : {
433 38816 : scope_inner (node_id, std::forward<F> (f), [node_id, &crate_name] () {
434 5146 : return new CanonicalPathRecordCrateRoot (node_id, std::move (crate_name));
435 : });
436 : }
437 :
438 : /** Merge another CanonicalPathCtx within this one. Intended to be used when
439 : * merging crate name resolution context.
440 : */
441 48 : void merge (CanonicalPathCtx &&other)
442 : {
443 48 : records.insert (std::make_move_iterator (other.records.begin ()),
444 : std::make_move_iterator (other.records.end ()));
445 48 : }
446 :
447 : private:
448 : template <typename FCreate, typename FCallback>
449 1986117 : void scope_inner (NodeId id, FCallback &&f_callback, FCreate &&f_create)
450 : {
451 1986117 : auto it = records.find (id);
452 2059358 : if (it == records.end ())
453 : {
454 73241 : CanonicalPathRecord *record = std::forward<FCreate> (f_create) ();
455 73241 : it = records.emplace (id, std::unique_ptr<CanonicalPathRecord> (record))
456 : .first;
457 : }
458 :
459 1986117 : rust_assert (it->second->is_root ()
460 : || static_cast<CanonicalPathRecordWithParent &> (*it->second)
461 : .get_parent ()
462 : == current_record);
463 :
464 1986117 : NodeId stash = it->first;
465 1986117 : std::swap (stash, current_record);
466 :
467 1986115 : std::forward<FCallback> (f_callback) ();
468 :
469 1986113 : std::swap (stash, current_record);
470 1986113 : }
471 :
472 : std::unordered_map<NodeId, std::unique_ptr<CanonicalPathRecord>> records;
473 : NodeId current_record;
474 :
475 : const NameResolutionContext *nr_ctx;
476 : };
477 :
478 : // Now our resolver, which keeps track of all the `ForeverStack`s we could want
479 : class NameResolutionContext
480 : {
481 : public:
482 : NameResolutionContext ();
483 :
484 : /**
485 : * Insert a new value in the current rib.
486 : *
487 : * @param name Name of the value to insert.
488 : * @param id This value's ID, e.g the function definition's node ID.
489 : * @param ns Namespace in which to insert the value.
490 : */
491 : tl::expected<NodeId, DuplicateNameError> insert (Identifier name, NodeId id,
492 : Namespace ns);
493 :
494 : tl::expected<NodeId, DuplicateNameError>
495 : insert_variant (Identifier name, NodeId id, bool is_also_value);
496 :
497 : tl::expected<NodeId, DuplicateNameError>
498 : insert_shadowable (Identifier name, NodeId id, Namespace ns);
499 :
500 : tl::expected<NodeId, DuplicateNameError>
501 : insert_globbed (Identifier name, NodeId id, Namespace ns);
502 :
503 : /**
504 : * Run a lambda in a "scoped" context, meaning that a new `Rib` will be pushed
505 : * before executing the lambda and then popped. This is useful for all kinds
506 : * of scope in the language, such as a block expression or when entering a
507 : * function. This variant of the function enters a new scope in *all*
508 : * namespaces, while the second variant enters a scope in *one* namespace.
509 : *
510 : * @param rib_kind New `Rib` to create when entering this scope. A function
511 : * `Rib`, or an item `Rib`... etc
512 : * @param scope_id node ID of the scope we are entering, e.g the block's
513 : * `NodeId`.
514 : * @param lambda Function to run within that scope
515 : * @param path Optional path of the scope. This is useful for scopes which
516 : * affect path resolution, such as modules. Defaults to an empty
517 : * option.
518 : */
519 : // FIXME: Do we want to handle something in particular for expected within the
520 : // scoped lambda?
521 : void scoped (Rib::Kind rib_kind, NodeId scope_id,
522 : std::function<void (void)> lambda,
523 : tl::optional<Identifier> path = {});
524 : void scoped (Rib::Kind rib_kind, Namespace ns, NodeId scope_id,
525 : std::function<void (void)> lambda,
526 : tl::optional<Identifier> path = {});
527 :
528 : using Node = ForeverStackBase::Node;
529 :
530 : std::unique_ptr<Node> root;
531 : std::unique_ptr<Node> lang_prelude;
532 : std::unique_ptr<Node> extern_prelude;
533 :
534 : ForeverStack<Namespace::Values> values;
535 : ForeverStack<Namespace::Types> types;
536 : ForeverStack<Namespace::Macros> macros;
537 : ForeverStack<Namespace::Labels> labels;
538 :
539 : Analysis::Mappings &mappings;
540 : StackedContexts<BindingLayer> bindings;
541 :
542 : CanonicalPathCtx canonical_ctx;
543 :
544 : /**
545 : * The result type for a multi-namespace call to
546 : * NameResolutionContext::lookup()
547 : */
548 : struct NSLookup
549 : {
550 : NodeId id;
551 : Namespace ns;
552 :
553 207772 : NSLookup (NodeId id, Namespace ns) : id (id), ns (ns) {}
554 : };
555 :
556 : /**
557 : * These functions are mostly useful for the FinalizedNameResolutionContext
558 : * and used in later passes of the pipeline. They don't need to know as much
559 : * about a definition, hence why they don't use the NamespacedDefinition which
560 : * returns a Rib::Definition.
561 : */
562 : void map_usage (Usage usage, Definition definition, Namespace ns);
563 : tl::optional<NodeId> lookup (NodeId usage, Namespace ns) const;
564 :
565 : /**
566 : * The order of namespaces is important - if the usage resolves in the first
567 : * namespace, then it will be returned. Collisions are not guarded against and
568 : * should NOT happen. This is for looking up usages once name resolution is
569 : * done and we are in later stages of the pipeline.
570 : */
571 : tl::optional<NSLookup> lookup (NodeId usage, Namespace ns1,
572 : Namespace ns2) const;
573 : tl::optional<NSLookup> lookup (NodeId usage, Namespace ns1, Namespace ns2,
574 : Namespace ns3) const;
575 :
576 : Resolver::CanonicalPath to_canonical_path (NodeId id, Namespace ns) const
577 : {
578 : return canonical_ctx.get_path (id, ns);
579 : }
580 :
581 : /**
582 : * The return value when the namespace in which a definition was resolved
583 : * matters
584 : */
585 1903237 : struct NamespacedDefinition
586 : {
587 321675 : explicit NamespacedDefinition (Rib::Definition definition, Namespace ns)
588 55697 : : definition (definition), ns (ns)
589 : {}
590 :
591 : static tl::optional<NamespacedDefinition>
592 329058 : Maybe (tl::optional<Rib::Definition> definition, Namespace ns)
593 : {
594 924094 : return definition.map ([ns] (Rib::Definition definition) {
595 265978 : return NamespacedDefinition (definition, ns);
596 329058 : });
597 : }
598 :
599 : Rib::Definition definition;
600 : Namespace ns;
601 : };
602 :
603 : tl::optional<NamespacedDefinition>
604 303254 : resolve_path (const ResolutionPath &path, ResolutionMode mode,
605 : std::vector<Error> &collect_errors, Namespace ns)
606 : {
607 303254 : std::function<void (Usage, Definition, Namespace)> insert_segment_resolution
608 303254 : = [this] (Usage seg_id, Definition id, Namespace ns) {
609 390036 : map_usage (seg_id, id, ns);
610 303254 : };
611 :
612 303254 : tl::optional<NamespacedDefinition> resolved = tl::nullopt;
613 :
614 303254 : switch (ns)
615 : {
616 114031 : case Namespace::Values:
617 228062 : resolved = NamespacedDefinition::Maybe (
618 228062 : resolve_path (values, path, mode, insert_segment_resolution,
619 : collect_errors),
620 114031 : ns);
621 114031 : break;
622 172941 : case Namespace::Types:
623 345882 : resolved = NamespacedDefinition::Maybe (
624 345882 : resolve_path (types, path, mode, insert_segment_resolution,
625 : collect_errors),
626 172941 : ns);
627 172941 : break;
628 16282 : case Namespace::Macros:
629 32564 : resolved = NamespacedDefinition::Maybe (
630 32564 : resolve_path (macros, path, mode, insert_segment_resolution,
631 : collect_errors),
632 16282 : ns);
633 16282 : break;
634 0 : case Namespace::Labels:
635 0 : resolved = NamespacedDefinition::Maybe (
636 0 : resolve_path (labels, path, mode, insert_segment_resolution,
637 : collect_errors),
638 0 : ns);
639 0 : break;
640 0 : default:
641 0 : rust_unreachable ();
642 : }
643 :
644 : // If it fails, switch to std prelude resolution if it exists
645 303254 : if (prelude && !resolved)
646 : {
647 : // TODO: Factor this with the above
648 25804 : switch (ns)
649 : {
650 7966 : case Namespace::Values:
651 7966 : return NamespacedDefinition::Maybe (
652 15932 : resolve_path (values, path, mode, insert_segment_resolution,
653 7966 : collect_errors, *prelude),
654 7966 : ns);
655 12299 : case Namespace::Types:
656 12299 : return NamespacedDefinition::Maybe (
657 24598 : resolve_path (types, path, mode, insert_segment_resolution,
658 12299 : collect_errors, *prelude),
659 12299 : ns);
660 5539 : case Namespace::Macros:
661 5539 : return NamespacedDefinition::Maybe (
662 11078 : resolve_path (macros, path, mode, insert_segment_resolution,
663 5539 : collect_errors, *prelude),
664 5539 : ns);
665 0 : case Namespace::Labels:
666 0 : return NamespacedDefinition::Maybe (
667 0 : resolve_path (labels, path, mode, insert_segment_resolution,
668 0 : collect_errors, *prelude),
669 0 : ns);
670 : default:
671 : rust_unreachable ();
672 : }
673 : }
674 :
675 277450 : return resolved;
676 303254 : }
677 :
678 294836 : class ResolutionBuilder
679 : {
680 : public:
681 294836 : ResolutionBuilder (NameResolutionContext &ctx) : ctx (&ctx) {}
682 :
683 : template <typename S>
684 294422 : void set_path (const std::vector<S> &path_segments, NodeId node_id,
685 : bool has_opening_scope)
686 : {
687 294422 : path = ResolutionPath (path_segments, node_id);
688 294422 : mode = ResolutionMode::Normal;
689 294422 : if (has_opening_scope)
690 : {
691 2367 : if (get_rust_edition () == Edition::E2015)
692 751 : mode = ResolutionMode::FromRoot;
693 : else
694 1616 : mode = ResolutionMode::FromExtern;
695 : }
696 294422 : has_path_set = true;
697 294422 : }
698 :
699 : template <typename S>
700 414 : void set_path (const std::vector<S> &path_segments, NodeId node_id,
701 : ResolutionMode mode)
702 : {
703 414 : path = ResolutionPath (path_segments, node_id);
704 414 : this->mode = mode;
705 414 : has_path_set = true;
706 414 : }
707 :
708 : void set_path (const AST::SimplePath &path)
709 : {
710 : set_path (path.get_segments (), path.get_node_id (),
711 : path.has_opening_scope_resolution ());
712 : }
713 :
714 : void set_path (const AST::PathInExpression &path)
715 : {
716 : set_path (path.get_segments (), path.get_node_id (),
717 : path.opening_scope_resolution ());
718 : }
719 :
720 : void set_path (const AST::TypePath &path)
721 : {
722 : set_path (path.get_segments (), path.get_node_id (),
723 : path.has_opening_scope_resolution_op ());
724 : }
725 :
726 : void set_mode (ResolutionMode mode) { this->mode = mode; }
727 :
728 400025 : void add_namespaces (Namespace ns) { namespace_list.push_back (ns); }
729 :
730 105189 : template <typename... Args> void add_namespaces (Namespace ns, Args... rest)
731 : {
732 105189 : add_namespaces (ns);
733 105189 : add_namespaces (rest...);
734 105189 : }
735 :
736 26526 : void set_collect_errors (tl::optional<std::vector<Error> &> collect_errors)
737 : {
738 26526 : this->collect_errors = collect_errors;
739 : }
740 :
741 294836 : tl::optional<NamespacedDefinition> resolve ()
742 : {
743 294836 : rust_assert (has_path_set);
744 :
745 332112 : for (auto ns : namespace_list)
746 : {
747 303254 : std::vector<Error> collect_errors_inner;
748 303254 : if (auto ret
749 303254 : = ctx->resolve_path (path, mode, collect_errors_inner, ns))
750 303254 : return ret;
751 37276 : if (!collect_errors_inner.empty ())
752 : {
753 12 : if (collect_errors.has_value ())
754 : {
755 6 : std::move (collect_errors_inner.begin (),
756 : collect_errors_inner.end (),
757 : std::back_inserter (collect_errors.value ()));
758 : }
759 : else
760 : {
761 12 : for (auto &e : collect_errors_inner)
762 6 : e.emit ();
763 : }
764 : }
765 303254 : }
766 :
767 28858 : return tl::nullopt;
768 : }
769 :
770 : private:
771 : ResolutionPath path;
772 : ResolutionMode mode;
773 : bool has_path_set;
774 :
775 : std::vector<Namespace> namespace_list;
776 :
777 : tl::optional<std::vector<Error> &> collect_errors;
778 :
779 : NameResolutionContext *ctx;
780 : };
781 :
782 : template <typename S, typename... Args>
783 : tl::optional<NamespacedDefinition>
784 : resolve_path (const std::vector<S> &path_segments, ResolutionMode mode,
785 : tl::optional<std::vector<Error> &> collect_errors,
786 : Namespace ns_first, Args... ns_args)
787 : {
788 : ResolutionBuilder builder (*this);
789 : builder.set_path (path_segments, UNKNOWN_NODEID, mode);
790 : builder.add_namespaces (ns_first, ns_args...);
791 : builder.set_collect_errors (collect_errors);
792 :
793 : return builder.resolve ();
794 : }
795 :
796 : template <typename S, typename... Args>
797 : tl::optional<NamespacedDefinition>
798 26526 : resolve_path (const std::vector<S> &path_segments,
799 : bool has_opening_scope_resolution,
800 : tl::optional<std::vector<Error> &> collect_errors,
801 : Namespace ns_first, Args... ns_args)
802 : {
803 26526 : ResolutionBuilder builder (*this);
804 26526 : builder.set_path (path_segments, UNKNOWN_NODEID,
805 : has_opening_scope_resolution);
806 26526 : builder.add_namespaces (ns_first, ns_args...);
807 26526 : builder.set_collect_errors (collect_errors);
808 :
809 26526 : return builder.resolve ();
810 26526 : }
811 :
812 : template <typename S, typename... Args>
813 : tl::optional<NamespacedDefinition>
814 267896 : resolve_path (const std::vector<S> &path_segments,
815 : bool has_opening_scope_resolution, Namespace ns_first,
816 : Args... ns_args)
817 : {
818 267896 : ResolutionBuilder builder (*this);
819 267896 : builder.set_path (path_segments, UNKNOWN_NODEID,
820 : has_opening_scope_resolution);
821 267896 : builder.add_namespaces (ns_first, ns_args...);
822 :
823 267896 : return builder.resolve ();
824 267896 : }
825 :
826 : template <typename S, typename... Args>
827 : tl::optional<NamespacedDefinition>
828 414 : resolve_path (const std::vector<S> &path_segments, ResolutionMode mode,
829 : Namespace ns_first, Args... ns_args)
830 : {
831 414 : ResolutionBuilder builder (*this);
832 414 : builder.set_path (path_segments, UNKNOWN_NODEID, mode);
833 414 : builder.add_namespaces (ns_first, ns_args...);
834 :
835 414 : return builder.resolve ();
836 414 : }
837 :
838 : template <typename... Args>
839 38169 : tl::optional<NamespacedDefinition> resolve_path (const AST::SimplePath &path,
840 : Args &&...args)
841 : {
842 26526 : return resolve_path (path.get_segments (),
843 : path.has_opening_scope_resolution (),
844 38169 : std::forward<Args> (args)...);
845 : }
846 :
847 : template <typename... Args>
848 : tl::optional<NamespacedDefinition>
849 107411 : resolve_path (const AST::PathInExpression &path, Args &&...args)
850 : {
851 : return resolve_path (path.get_segments (), path.opening_scope_resolution (),
852 107411 : std::forward<Args> (args)...);
853 : }
854 :
855 : template <typename... Args>
856 148842 : tl::optional<NamespacedDefinition> resolve_path (const AST::TypePath &path,
857 : Args &&...args)
858 : {
859 : return resolve_path (path.get_segments (),
860 : path.has_opening_scope_resolution_op (),
861 148842 : std::forward<Args> (args)...);
862 : }
863 :
864 : /*
865 : * Merge a name resolution context within another one at a given location.
866 : *
867 : * @param other The other name resolution context to merge within the current
868 : * one.
869 : * @param at The node id of the container were the nr context should be
870 : * merged. Usually an extern crate node.
871 : */
872 : void merge (NameResolutionContext &other, NodeId at);
873 :
874 : // We disable this function for now as it causes regressions, but I think it
875 : // is important for a more proper final nameres context - need to investigate
876 : #if 0
877 : /**
878 : * We've now collected every definition and import, and errored out when
879 : * necessary if multiple definitions are colliding. Do a final flattening of
880 : * the name resolution context to make it easier to digest for the late name
881 : * resolution and type-checker. This basically turns the `resolved_nodes`
882 : * map from a linked-list-like map to a regular, flat hashmap.
883 : *
884 : * FIXME: The documentation is wrong, this needs to also run after all
885 : * usages have been *resolved* so after Late as well!!!
886 : *
887 : * TODO: Should this return something like the FinalizedNameResolutionCtx?
888 : * Or set it up at least? And instead of mutating the `resolved_nodes` map,
889 : * create a new one for the FinalizedNameResolutionCtx?
890 : * Actually, since Late uses the NRCtx directly we should mutate this. Most
891 : * later passes don't look at this map. So let's go for side-effects in a
892 : * void function, yipee.
893 : */
894 : void flatten ();
895 : #endif
896 :
897 : /* If declared with #[prelude_import], the current standard library module
898 : */
899 : tl::optional<NodeId> prelude;
900 :
901 : private:
902 : template <Namespace N>
903 : bool
904 : should_search_prelude (const typename ForeverStack<N>::Node *current_node,
905 : const typename ForeverStack<N>::SegIterator &iterator,
906 : const std::vector<ResolutionPath::Segment> &segments);
907 :
908 : /**
909 : * Resolve a path to its definition
910 : *
911 : * // TODO: Add documentation for `segments`
912 : *
913 : * @return a valid option with the Definition if the path is present in the
914 : * current map, an empty one otherwise.
915 : */
916 : template <Namespace N>
917 : tl::optional<Rib::Definition>
918 : resolve_path (ForeverStack<N> &stack, const ResolutionPath &path,
919 : ResolutionMode mode,
920 : std::function<void (Usage, Definition, Namespace)>
921 : insert_segment_resolution,
922 : std::vector<Error> &collect_errors);
923 :
924 : template <Namespace N>
925 : tl::optional<Rib::Definition>
926 : resolve_path (ForeverStack<N> &stack, const ResolutionPath &path,
927 : ResolutionMode mode,
928 : std::function<void (Usage, Definition, Namespace)>
929 : insert_segment_resolution,
930 : std::vector<Error> &collect_errors, NodeId starting_point_id);
931 :
932 : template <Namespace N>
933 : tl::optional<Rib::Definition> resolve_path (
934 : ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode,
935 : std::function<void (Usage, Definition, Namespace)>
936 : insert_segment_resolution,
937 : std::vector<Error> &collect_errors,
938 : std::reference_wrapper<typename ForeverStack<N>::Node> starting_point);
939 :
940 : template <Namespace N>
941 : tl::optional<typename ForeverStack<N>::Node &>
942 : resolve_segments (ForeverStack<N> &stack,
943 : typename ForeverStack<N>::Node &starting_point,
944 : const std::vector<ResolutionPath::Segment> &segments,
945 : typename ForeverStack<N>::SegIterator iterator,
946 : std::function<void (Usage, Definition, Namespace)>
947 : insert_segment_resolution,
948 : std::vector<Error> &collect_errors);
949 :
950 : template <Namespace N>
951 : tl::optional<Rib::Definition>
952 : resolve_final_segment (ForeverStack<N> &stack,
953 : typename ForeverStack<N>::Node &final_node,
954 : std::string &seg_name, bool is_lower_self);
955 : };
956 :
957 : } // namespace Resolver2_0
958 : } // namespace Rust
959 :
960 : #include "rust-name-resolution-context.hxx"
961 :
962 : #endif // ! RUST_NAME_RESOLVER_2_0_CTX_H
|