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