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_H
20 : #define RUST_NAME_RESOLVER_2_0_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 :
29 : namespace Rust {
30 : namespace Resolver2_0 {
31 :
32 : // TODO: Add missing mappings and data structures
33 :
34 : /**
35 : The data structures we need to develop need to fill in a few roles - like the
36 : original name resolver, they need to be accessible at multiple points during the
37 : pipeline to allow compiler passes such as macro expansion or typechecking to
38 : benefit from them. Unlike the original name resolution, these data structures
39 : need to be created by multiple compiler passes: Whereas the original name
40 : resolution of gccrs tries to perform name resolution in a single pass, it fails
41 : at properly handling more complex name resolution cases such as macro name
42 : resolution, imports in general, and glob imports in particular. The goal of this
43 : new name resolution algorithm is to split the name resolution in at least two
44 : passes - `Early` name resolution, which takes care of macro name resolution and
45 : import resolution, and `Late` name resolution - your typical name resolution,
46 : for types, functions, variables...
47 :
48 : 1. `Early`
49 :
50 : The Early name resolution is tied in snuggly with macro expansion: macro
51 : expansion cannot happen without some form of name resolution (pointing an
52 : invocation to its definition) but may also *depend* on name resolution (a macro
53 : generating another macro... or importing items... and funny other cases like
54 : these). It needs to work in a fixed-point fashion alongside macro expansion:
55 : While there are imports to resolve, or macros to expand, we need to keep going
56 : and resolve them. This is achieved, among other things, by a top-level name
57 : resolution pass in charge of collection use statements and macro definitions (as
58 : well as Items, which will be useful for later passes of the name resolution).
59 :
60 : This top-level pass exists because Rust enables you to call a function
61 : before having declared it (at a lexical level, i.e calling `f(15)` at line 3
62 : while the `f` function is declared at line 1499).
63 :
64 : This Early pass needs to build the first part of our "resolution map", which
65 : will then be used in multiple contexts:
66 :
67 : 1. The MacroExpander, in a read-only fashion: fetching macro definitions for
68 : each invocation and performing the expansion.
69 : 2. `Late`, which will write more data inside that resolution map, and use it
70 : to perform its name resolution too.
71 :
72 : This is where the first challenge of this data structure lies: The existing
73 : data structures and name resolution algorithm relies on the name resolution pass
74 : happening just once. In typical name resolution fashion, when it sees a lexical
75 : scope (a new module, a function's block, a block expression...), it "pushes" a
76 : new "Scope" to a stack of these scopes, and "pops" it when exiting said lexical
77 : scope. However, because we are splitting the name resolution into two passes, we
78 : would like to avoid re-doing a bunch of work we've already done - which is why
79 : this data structure needs to allow "re-entrancy", or to at least not keep as
80 : much state as the existing one, and allow for viewing the same module multiple
81 : times without throwing a fit.
82 :
83 : We will be implementing a "forever stack" of scopes, which allows the user the
84 : pushing of new scopes onto the stack, but only simulates the popping of a scope:
85 : When pushing new scopes, more space is allocated on our stack, and we keep
86 : track of this scope as being the current one - however, when popping this scope,
87 : we do not actually delete the memory associated with it: we simply mark the
88 : previous scope (parent) as the current one.
89 :
90 : In the example below, each number indicates the "state" of our resolution map,
91 : and the carret is used to point to the current lexical scope.
92 :
93 : ```rust
94 : // []
95 : //
96 : fn main() { // [ `main` scope: {} ]
97 : // ^
98 : let a = 15; // [ `main` scope: { Decl(a) } ]
99 : // ^
100 : { _PUSH_ // [ `main` scope: { Decl(a) }, anonymous scope: {} ]
101 : // ^
102 : let a = 16; // [ `main` scope: { Decl(a) }, anonymous scope: { Decl(a) } ]
103 : // ^
104 : f(a); // [ `main` scope: { Decl(a) }, anonymous scope: { Decl(a) } ]
105 : // ^
106 : } _POP_ // [ `main` scope: { Decl(a) }, anonymous scope: { Decl(a) } ]
107 : // ^
108 : f(a); // [ `main` scope: { Decl(a) }, anonymous scope: { Decl(a) } ]
109 : // ^
110 : }
111 : ```
112 :
113 : This allows us to revisit scopes previously visited in later phases of the name
114 : resolution, and add more information if necessary.
115 :
116 : 2. `Late`
117 :
118 : `Late` name resolution possesses some unique challenges since Rust's name
119 : resolution rules are extremely complex - variable shadowing, variable capture in
120 : closures (but not inner functions!)... You can have a look at a fucked up
121 : example here:
122 :
123 : https://rustc-dev-guide.rust-lang.org/name-resolution.html#scopes-and-ribs
124 :
125 : This requires us to think about what exactly to put in our `Scope`s and what to
126 : do with our `Rib`s - and how it affects our data structures. For example, in the
127 : above example, `rustc` demonstrates how multiple `Rib`s can be created inside of
128 : a single lexical scope for variables, as the Rust programming language allows
129 : shadowing.
130 :
131 : TODO: Mention macro hygiene and that it is the same
132 : TODO: How does this affect our data structures?
133 : TODO: Last challenge - reuse the same APIs to allow the typechecker to not
134 : change?
135 : TODO: Mention that ForeverStack is templated to make sure that behavior is
136 : correct
137 : */
138 :
139 : // FIXME: Documentation
140 : class Usage
141 : {
142 : public:
143 2823788 : explicit Usage (NodeId id) : id (id) {}
144 :
145 : // TODO: move to name-resolution-ctx.cc
146 : // storing it as a key in a map
147 34679997 : bool operator< (const Usage other) const { return other.id < id; }
148 :
149 : NodeId id;
150 : };
151 :
152 : // FIXME: Documentation
153 : class Definition
154 : {
155 : public:
156 112757 : explicit Definition (NodeId id) : id (id) {}
157 :
158 : NodeId id;
159 : };
160 :
161 : struct IdentifierMode
162 : {
163 : bool is_ref;
164 : bool is_mut;
165 :
166 24288 : IdentifierMode (bool is_ref, bool is_mut) : is_ref (is_ref), is_mut (is_mut)
167 : {}
168 :
169 58 : bool operator== (const IdentifierMode &other)
170 : {
171 58 : return other.is_ref == is_ref && other.is_mut == is_mut;
172 : }
173 :
174 232 : bool operator!= (const IdentifierMode &other) { return !(*this == other); }
175 : };
176 :
177 203612 : struct Binding
178 : {
179 : enum class Kind
180 : {
181 : Product,
182 : Or,
183 : } kind;
184 :
185 : // used to check the correctness of or-bindings
186 : bool has_expected_bindings;
187 :
188 : std::unordered_map<std::string, std::pair<location_t, IdentifierMode>> idents;
189 :
190 34133 : Binding (Binding::Kind kind) : kind (kind), has_expected_bindings (false) {}
191 : };
192 :
193 : /**
194 : * Used to identify the source of a binding, and emit the correct error message.
195 : */
196 : enum class BindingSource
197 : {
198 : Match,
199 : Let,
200 : IfLet,
201 : WhileLet,
202 : For,
203 : /* Closure param or function param */
204 : Param
205 : };
206 :
207 134169 : class BindingLayer
208 : {
209 : BindingSource source;
210 : std::vector<Binding> bindings;
211 :
212 : bool bind_test (Identifier ident, Binding::Kind kind);
213 :
214 : public:
215 : void push (Binding::Kind kind);
216 :
217 : BindingLayer (BindingSource source);
218 :
219 : /**
220 : * Identifies if the identifier has been used in a product binding context.
221 : * eg. `let (a, a) = test();`
222 : */
223 : bool is_and_bound (Identifier ident);
224 :
225 : /**
226 : * Identifies if the identifier has been used in a or context.
227 : * eg. `let (a, 1) | (a, 2) = test()`
228 : */
229 : bool is_or_bound (Identifier ident);
230 :
231 : void insert_ident (std::string ident, location_t locus, bool is_ref,
232 : bool is_mut);
233 :
234 : void merge ();
235 :
236 : BindingSource get_source () const;
237 : };
238 :
239 : class NameResolutionContext;
240 : /*
241 : * Used to handle canonical paths
242 : * Similar to ForeverStack, but namespace independent and more specialized
243 : */
244 40052 : class CanonicalPathRecord
245 : {
246 : public:
247 : virtual Resolver::CanonicalPath as_path (const NameResolutionContext &) = 0;
248 :
249 : virtual bool is_root () const = 0;
250 :
251 : virtual ~CanonicalPathRecord () = default;
252 : };
253 :
254 : class CanonicalPathRecordWithParent : public CanonicalPathRecord
255 : {
256 : public:
257 35518 : CanonicalPathRecordWithParent (CanonicalPathRecord &parent) : parent (&parent)
258 : {}
259 :
260 402513 : CanonicalPathRecord &get_parent () { return *parent; }
261 :
262 238003 : bool is_root () const override final { return false; }
263 :
264 : private:
265 : CanonicalPathRecord *parent;
266 : };
267 :
268 : class CanonicalPathRecordCrateRoot : public CanonicalPathRecord
269 : {
270 : public:
271 4534 : CanonicalPathRecordCrateRoot (NodeId node_id, std::string seg)
272 4534 : : node_id (node_id), seg (std::move (seg))
273 : {
274 4534 : rust_assert (Analysis::Mappings::get ().node_is_crate (node_id));
275 4534 : crate_num = Analysis::Mappings::get ().lookup_crate_num (node_id).value ();
276 4534 : }
277 :
278 : Resolver::CanonicalPath as_path (const NameResolutionContext &) override;
279 :
280 30014 : bool is_root () const override final { return true; }
281 :
282 : private:
283 : NodeId node_id;
284 : CrateNum crate_num;
285 : std::string seg;
286 : };
287 :
288 : class CanonicalPathRecordNormal : public CanonicalPathRecordWithParent
289 : {
290 : public:
291 29808 : CanonicalPathRecordNormal (CanonicalPathRecord &parent, NodeId node_id,
292 : std::string seg)
293 29808 : : CanonicalPathRecordWithParent (parent), node_id (node_id),
294 29808 : seg (std::move (seg))
295 : {
296 29808 : rust_assert (!Analysis::Mappings::get ().node_is_crate (node_id));
297 29808 : }
298 :
299 : Resolver::CanonicalPath as_path (const NameResolutionContext &) override;
300 :
301 : private:
302 : NodeId node_id;
303 : std::string seg;
304 : };
305 :
306 : class CanonicalPathRecordLookup : public CanonicalPathRecord
307 : {
308 : public:
309 5710 : CanonicalPathRecordLookup (NodeId lookup_id)
310 5710 : : lookup_id (lookup_id), cache (nullptr)
311 : {}
312 :
313 : Resolver::CanonicalPath as_path (const NameResolutionContext &) override;
314 :
315 0 : bool is_root () const override final { return true; }
316 :
317 : private:
318 : NodeId lookup_id;
319 : CanonicalPathRecord *cache;
320 : };
321 :
322 : class CanonicalPathRecordImpl : public CanonicalPathRecordWithParent
323 : {
324 : public:
325 971 : CanonicalPathRecordImpl (CanonicalPathRecord &parent, NodeId impl_id,
326 : NodeId type_id)
327 971 : : CanonicalPathRecordWithParent (parent), impl_id (impl_id),
328 971 : type_record (type_id)
329 : {}
330 :
331 : Resolver::CanonicalPath as_path (const NameResolutionContext &) override;
332 :
333 : private:
334 : NodeId impl_id;
335 : CanonicalPathRecordLookup type_record;
336 : };
337 :
338 : class CanonicalPathRecordTraitImpl : public CanonicalPathRecordWithParent
339 : {
340 : public:
341 4739 : CanonicalPathRecordTraitImpl (CanonicalPathRecord &parent, NodeId impl_id,
342 : NodeId type_id, NodeId trait_path_id)
343 4739 : : CanonicalPathRecordWithParent (parent), impl_id (impl_id),
344 4739 : type_record (type_id), trait_path_record (trait_path_id)
345 : {}
346 :
347 : Resolver::CanonicalPath as_path (const NameResolutionContext &) override;
348 :
349 : private:
350 : NodeId impl_id;
351 : CanonicalPathRecordLookup type_record;
352 : CanonicalPathRecordLookup trait_path_record;
353 : };
354 :
355 : class CanonicalPathCtx
356 : {
357 : public:
358 4510 : CanonicalPathCtx (const NameResolutionContext &ctx)
359 4510 : : current_record (nullptr), nr_ctx (&ctx)
360 : {}
361 :
362 59339 : Resolver::CanonicalPath get_path (NodeId id) const
363 : {
364 59339 : return get_record (id).as_path (*nr_ctx);
365 : }
366 :
367 59339 : CanonicalPathRecord &get_record (NodeId id) const
368 : {
369 59339 : auto it = records.find (id);
370 59339 : rust_assert (it != records.end ());
371 59339 : return *it->second;
372 : }
373 :
374 16061 : tl::optional<CanonicalPathRecord *> get_record_opt (NodeId id) const
375 : {
376 16061 : auto it = records.find (id);
377 16061 : if (it == records.end ())
378 11085 : return tl::nullopt;
379 : else
380 4976 : return it->second.get ();
381 : }
382 :
383 : void insert_record (NodeId id, const Identifier &ident)
384 : {
385 : insert_record (id, ident.as_string ());
386 : }
387 :
388 : void insert_record (NodeId id, std::string seg)
389 : {
390 : rust_assert (current_record != nullptr);
391 :
392 : auto it = records.find (id);
393 : if (it == records.end ())
394 : {
395 : auto record = new CanonicalPathRecordNormal (*current_record, id,
396 : std::move (seg));
397 : bool ok
398 : = records.emplace (id, std::unique_ptr<CanonicalPathRecord> (record))
399 : .second;
400 : rust_assert (ok);
401 : }
402 : }
403 :
404 199972 : template <typename F> void scope (NodeId id, const Identifier &ident, F &&f)
405 : {
406 399944 : scope (id, ident.as_string (), std::forward<F> (f));
407 199971 : }
408 :
409 199972 : template <typename F> void scope (NodeId id, std::string seg, F &&f)
410 : {
411 199972 : rust_assert (current_record != nullptr);
412 :
413 229780 : scope_inner (id, std::forward<F> (f), [this, id, &seg] () {
414 29808 : return new CanonicalPathRecordNormal (*current_record, id,
415 29808 : std::move (seg));
416 : });
417 199971 : }
418 :
419 6320 : template <typename F> void scope_impl (AST::InherentImpl &impl, F &&f)
420 : {
421 6320 : rust_assert (current_record != nullptr);
422 :
423 6320 : NodeId id = impl.get_node_id ();
424 6320 : scope_inner (id, std::forward<F> (f), [this, id, &impl] () {
425 971 : return new CanonicalPathRecordImpl (*current_record, id,
426 971 : impl.get_type ().get_node_id ());
427 : });
428 6320 : }
429 :
430 31711 : template <typename F> void scope_impl (AST::TraitImpl &impl, F &&f)
431 : {
432 31711 : rust_assert (current_record != nullptr);
433 :
434 31711 : NodeId id = impl.get_node_id ();
435 31711 : scope_inner (id, std::forward<F> (f), [this, id, &impl] () {
436 4739 : return new CanonicalPathRecordTraitImpl (
437 4739 : *current_record, id, impl.get_type ().get_node_id (),
438 4739 : impl.get_trait_path ().get_node_id ());
439 : });
440 31711 : }
441 :
442 : template <typename F>
443 30014 : void scope_crate (NodeId node_id, std::string crate_name, F &&f)
444 : {
445 34548 : scope_inner (node_id, std::forward<F> (f), [node_id, &crate_name] () {
446 4534 : return new CanonicalPathRecordCrateRoot (node_id, std::move (crate_name));
447 : });
448 : }
449 :
450 : private:
451 : template <typename FCreate, typename FCallback>
452 268017 : void scope_inner (NodeId id, FCallback &&f_callback, FCreate &&f_create)
453 : {
454 268017 : auto it = records.find (id);
455 268017 : if (it == records.end ())
456 : {
457 40052 : CanonicalPathRecord *record = std::forward<FCreate> (f_create) ();
458 40052 : it = records.emplace (id, std::unique_ptr<CanonicalPathRecord> (record))
459 : .first;
460 : }
461 :
462 268017 : rust_assert (it->second->is_root ()
463 : || &static_cast<CanonicalPathRecordWithParent &> (*it->second)
464 : .get_parent ()
465 : == current_record);
466 :
467 268017 : CanonicalPathRecord *stash = it->second.get ();
468 268017 : std::swap (stash, current_record);
469 :
470 268015 : std::forward<FCallback> (f_callback) ();
471 :
472 268015 : std::swap (stash, current_record);
473 268015 : }
474 :
475 : std::unordered_map<NodeId, std::unique_ptr<CanonicalPathRecord>> records;
476 : CanonicalPathRecord *current_record;
477 :
478 : const NameResolutionContext *nr_ctx;
479 : };
480 :
481 : // Now our resolver, which keeps track of all the `ForeverStack`s we could want
482 : class NameResolutionContext
483 : {
484 : public:
485 : NameResolutionContext ();
486 :
487 : /**
488 : * Insert a new value in the current rib.
489 : *
490 : * @param name Name of the value to insert.
491 : * @param id This value's ID, e.g the function definition's node ID.
492 : * @param ns Namespace in which to insert the value.
493 : */
494 : tl::expected<NodeId, DuplicateNameError> insert (Identifier name, NodeId id,
495 : Namespace ns);
496 :
497 : tl::expected<NodeId, DuplicateNameError> insert_variant (Identifier name,
498 : NodeId id);
499 :
500 : tl::expected<NodeId, DuplicateNameError>
501 : insert_shadowable (Identifier name, NodeId id, Namespace ns);
502 :
503 : tl::expected<NodeId, DuplicateNameError>
504 : insert_globbed (Identifier name, NodeId id, Namespace ns);
505 :
506 : /**
507 : * Run a lambda in a "scoped" context, meaning that a new `Rib` will be pushed
508 : * before executing the lambda and then popped. This is useful for all kinds
509 : * of scope in the language, such as a block expression or when entering a
510 : * function. This variant of the function enters a new scope in *all*
511 : * namespaces, while the second variant enters a scope in *one* namespace.
512 : *
513 : * @param rib_kind New `Rib` to create when entering this scope. A function
514 : * `Rib`, or an item `Rib`... etc
515 : * @param scope_id node ID of the scope we are entering, e.g the block's
516 : * `NodeId`.
517 : * @param lambda Function to run within that scope
518 : * @param path Optional path of the scope. This is useful for scopes which
519 : * affect path resolution, such as modules. Defaults to an empty
520 : * option.
521 : */
522 : // FIXME: Do we want to handle something in particular for expected within the
523 : // scoped lambda?
524 : void scoped (Rib::Kind rib_kind, NodeId scope_id,
525 : std::function<void (void)> lambda,
526 : tl::optional<Identifier> path = {});
527 : void scoped (Rib::Kind rib_kind, Namespace ns, NodeId scope_id,
528 : std::function<void (void)> lambda,
529 : tl::optional<Identifier> path = {});
530 :
531 : ForeverStack<Namespace::Values> values;
532 : ForeverStack<Namespace::Types> types;
533 : ForeverStack<Namespace::Macros> macros;
534 : ForeverStack<Namespace::Labels> labels;
535 :
536 : Analysis::Mappings &mappings;
537 : StackedContexts<BindingLayer> bindings;
538 :
539 : CanonicalPathCtx canonical_ctx;
540 :
541 : // TODO: Rename
542 : // TODO: Use newtype pattern for Usage and Definition
543 : void map_usage (Usage usage, Definition definition);
544 :
545 : tl::optional<NodeId> lookup (NodeId usage) const;
546 :
547 59339 : Resolver::CanonicalPath to_canonical_path (NodeId id) const
548 : {
549 59339 : return canonical_ctx.get_path (id);
550 : }
551 :
552 : template <typename S>
553 : tl::optional<Rib::Definition>
554 93698 : resolve_path (const std::vector<S> &segments, ResolutionMode mode,
555 : std::vector<Error> &collect_errors, Namespace ns)
556 : {
557 93698 : std::function<void (const S &, NodeId)> insert_segment_resolution
558 219458 : = [this] (const S &seg, NodeId id) {
559 55067 : auto seg_id = unwrap_segment_node_id (seg);
560 110159 : if (resolved_nodes.find (Usage (seg_id)) == resolved_nodes.end ())
561 89318 : map_usage (Usage (seg_id), Definition (id));
562 : };
563 :
564 93698 : tl::optional<Rib::Definition> resolved = tl::nullopt;
565 :
566 93698 : switch (ns)
567 : {
568 25827 : case Namespace::Values:
569 : resolved
570 43024 : = values.resolve_path (segments, mode, insert_segment_resolution,
571 : collect_errors);
572 25827 : break;
573 64563 : case Namespace::Types:
574 : resolved
575 126571 : = types.resolve_path (segments, mode, insert_segment_resolution,
576 : collect_errors);
577 64563 : break;
578 3308 : case Namespace::Macros:
579 : resolved
580 3336 : = macros.resolve_path (segments, mode, insert_segment_resolution,
581 : collect_errors);
582 3308 : break;
583 0 : case Namespace::Labels:
584 : resolved
585 0 : = labels.resolve_path (segments, mode, insert_segment_resolution,
586 : collect_errors);
587 0 : break;
588 0 : default:
589 0 : rust_unreachable ();
590 : }
591 :
592 : // If it fails, switch to std prelude resolution if it exists
593 93698 : if (prelude && !resolved)
594 : {
595 : // TODO: Factor this with the above
596 0 : switch (ns)
597 : {
598 0 : case Namespace::Values:
599 0 : return values.resolve_path (segments, mode,
600 : insert_segment_resolution,
601 0 : collect_errors, *prelude);
602 0 : case Namespace::Types:
603 0 : return types.resolve_path (segments, mode,
604 : insert_segment_resolution,
605 0 : collect_errors, *prelude);
606 0 : case Namespace::Macros:
607 0 : return macros.resolve_path (segments, mode,
608 : insert_segment_resolution,
609 0 : collect_errors, *prelude);
610 0 : case Namespace::Labels:
611 0 : return labels.resolve_path (segments, mode,
612 : insert_segment_resolution,
613 0 : collect_errors, *prelude);
614 : default:
615 : rust_unreachable ();
616 : }
617 : }
618 :
619 93698 : return resolved;
620 93698 : }
621 :
622 : template <typename S, typename... Args>
623 : tl::optional<Rib::Definition>
624 88063 : resolve_path (const std::vector<S> &segments, ResolutionMode mode,
625 : tl::optional<std::vector<Error> &> collect_errors,
626 : Namespace ns_first, Args... ns_args)
627 : {
628 88063 : std::initializer_list<Namespace> namespaces = {ns_first, ns_args...};
629 :
630 181761 : for (auto ns : namespaces)
631 : {
632 93698 : std::vector<Error> collect_errors_inner;
633 93698 : if (auto ret = resolve_path (segments, mode, collect_errors_inner, ns))
634 : return ret;
635 14465 : if (!collect_errors_inner.empty ())
636 : {
637 11 : if (collect_errors.has_value ())
638 : {
639 6 : std::move (collect_errors_inner.begin (),
640 : collect_errors_inner.end (),
641 : std::back_inserter (collect_errors.value ()));
642 : }
643 : else
644 : {
645 10 : for (auto &e : collect_errors_inner)
646 5 : e.emit ();
647 : }
648 11 : return tl::nullopt;
649 : }
650 : }
651 :
652 8819 : return tl::nullopt;
653 : }
654 :
655 : template <typename S, typename... Args>
656 : tl::optional<Rib::Definition>
657 87998 : resolve_path (const std::vector<S> &path_segments,
658 : bool has_opening_scope_resolution,
659 : tl::optional<std::vector<Error> &> collect_errors,
660 : Namespace ns_first, Args... ns_args)
661 : {
662 87998 : auto mode = ResolutionMode::Normal;
663 87998 : if (has_opening_scope_resolution)
664 : {
665 737 : if (get_rust_edition () == Edition::E2015)
666 : mode = ResolutionMode::FromRoot;
667 : else
668 0 : mode = ResolutionMode::FromExtern;
669 : }
670 : return resolve_path (path_segments, mode, collect_errors, ns_first,
671 87998 : ns_args...);
672 : }
673 :
674 : template <typename S, typename... Args>
675 : tl::optional<Rib::Definition>
676 78842 : resolve_path (const std::vector<S> &path_segments,
677 : bool has_opening_scope_resolution, Namespace ns_first,
678 : Args... ns_args)
679 : {
680 : return resolve_path (path_segments, has_opening_scope_resolution,
681 54660 : tl::nullopt, ns_first, ns_args...);
682 : }
683 :
684 : template <typename S, typename... Args>
685 : tl::optional<Rib::Definition>
686 65 : resolve_path (const std::vector<S> &path_segments, ResolutionMode mode,
687 : Namespace ns_first, Args... ns_args)
688 : {
689 : return resolve_path (path_segments, mode, tl::nullopt, ns_first,
690 65 : ns_args...);
691 : }
692 :
693 : template <typename... Args>
694 9529 : tl::optional<Rib::Definition> resolve_path (const AST::SimplePath &path,
695 : Args &&...args)
696 : {
697 9156 : return resolve_path (path.get_segments (),
698 9529 : path.has_opening_scope_resolution (),
699 9529 : std::forward<Args> (args)...);
700 : }
701 :
702 : template <typename... Args>
703 24182 : tl::optional<Rib::Definition> resolve_path (const AST::PathInExpression &path,
704 : Args &&...args)
705 : {
706 24182 : return resolve_path (path.get_segments (), path.opening_scope_resolution (),
707 24182 : std::forward<Args> (args)...);
708 : }
709 :
710 : template <typename... Args>
711 54287 : tl::optional<Rib::Definition> resolve_path (const AST::TypePath &path,
712 : Args &&...args)
713 : {
714 : return resolve_path (path.get_segments (),
715 54287 : path.has_opening_scope_resolution_op (),
716 54287 : std::forward<Args> (args)...);
717 : }
718 :
719 : /* If declared with #[prelude_import], the current standard library module */
720 : tl::optional<NodeId> prelude;
721 :
722 : private:
723 : /* Map of "usage" nodes which have been resolved to a "definition" node */
724 : std::map<Usage, Definition> resolved_nodes;
725 : };
726 :
727 : } // namespace Resolver2_0
728 : } // namespace Rust
729 :
730 : #endif // ! RUST_NAME_RESOLVER_2_0_H
|