Branch data Line data Source code
1 : : // Copyright (C) 2020-2025 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 : 1480411 : 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 : 17384181 : 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 : 110795 : 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 : 23844 : 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 : 198629 : 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 : 33299 : 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 : 130869 : 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 : 39096 : 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 : 34782 : CanonicalPathRecordWithParent (CanonicalPathRecord &parent) : parent (&parent)
258 : : {}
259 : :
260 : 396574 : CanonicalPathRecord &get_parent () { return *parent; }
261 : :
262 : 233585 : 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 : 4314 : CanonicalPathRecordCrateRoot (NodeId node_id, std::string seg)
272 : 4314 : : node_id (node_id), seg (std::move (seg))
273 : : {
274 : 4314 : rust_assert (Analysis::Mappings::get ().node_is_crate (node_id));
275 : 4314 : crate_num = Analysis::Mappings::get ().lookup_crate_num (node_id).value ();
276 : 4314 : }
277 : :
278 : : Resolver::CanonicalPath as_path (const NameResolutionContext &) override;
279 : :
280 : 28774 : 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 : 29132 : CanonicalPathRecordNormal (CanonicalPathRecord &parent, NodeId node_id,
292 : : std::string seg)
293 : 29132 : : CanonicalPathRecordWithParent (parent), node_id (node_id),
294 : 29132 : seg (std::move (seg))
295 : : {
296 : 29132 : rust_assert (!Analysis::Mappings::get ().node_is_crate (node_id));
297 : 29132 : }
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 : 5650 : CanonicalPathRecordLookup (NodeId lookup_id)
310 : 5650 : : 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 : 947 : CanonicalPathRecordImpl (CanonicalPathRecord &parent, NodeId impl_id,
326 : : NodeId type_id)
327 : 947 : : CanonicalPathRecordWithParent (parent), impl_id (impl_id),
328 : 947 : 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 : 4703 : CanonicalPathRecordTraitImpl (CanonicalPathRecord &parent, NodeId impl_id,
342 : : NodeId type_id, NodeId trait_path_id)
343 : 4703 : : CanonicalPathRecordWithParent (parent), impl_id (impl_id),
344 : 4703 : 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 : 4290 : CanonicalPathCtx (const NameResolutionContext &ctx)
359 : 4290 : : current_record (nullptr), nr_ctx (&ctx)
360 : : {}
361 : :
362 : 58567 : Resolver::CanonicalPath get_path (NodeId id) const
363 : : {
364 : 58567 : return get_record (id).as_path (*nr_ctx);
365 : : }
366 : :
367 : 58567 : CanonicalPathRecord &get_record (NodeId id) const
368 : : {
369 : 58567 : auto it = records.find (id);
370 : 58567 : rust_assert (it != records.end ());
371 : 58567 : return *it->second;
372 : : }
373 : :
374 : 16004 : tl::optional<CanonicalPathRecord *> get_record_opt (NodeId id) const
375 : : {
376 : 16004 : auto it = records.find (id);
377 : 16004 : if (it == records.end ())
378 : 11082 : return tl::nullopt;
379 : : else
380 : 4922 : 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 : 195919 : template <typename F> void scope (NodeId id, const Identifier &ident, F &&f)
405 : : {
406 : 391838 : scope (id, ident.as_string (), std::forward<F> (f));
407 : 195918 : }
408 : :
409 : 195919 : template <typename F> void scope (NodeId id, std::string seg, F &&f)
410 : : {
411 : 195919 : rust_assert (current_record != nullptr);
412 : :
413 : 225051 : scope_inner (id, std::forward<F> (f), [this, id, &seg] () {
414 : 29132 : return new CanonicalPathRecordNormal (*current_record, id,
415 : 29132 : std::move (seg));
416 : : });
417 : 195918 : }
418 : :
419 : 6173 : template <typename F> void scope_impl (AST::InherentImpl &impl, F &&f)
420 : : {
421 : 6173 : rust_assert (current_record != nullptr);
422 : :
423 : 6173 : NodeId id = impl.get_node_id ();
424 : 6173 : scope_inner (id, std::forward<F> (f), [this, id, &impl] () {
425 : 947 : return new CanonicalPathRecordImpl (*current_record, id,
426 : 947 : impl.get_type ().get_node_id ());
427 : : });
428 : 6173 : }
429 : :
430 : 31493 : template <typename F> void scope_impl (AST::TraitImpl &impl, F &&f)
431 : : {
432 : 31493 : rust_assert (current_record != nullptr);
433 : :
434 : 31493 : NodeId id = impl.get_node_id ();
435 : 31493 : scope_inner (id, std::forward<F> (f), [this, id, &impl] () {
436 : 4703 : return new CanonicalPathRecordTraitImpl (
437 : 4703 : *current_record, id, impl.get_type ().get_node_id (),
438 : 4703 : impl.get_trait_path ().get_node_id ());
439 : : });
440 : 31493 : }
441 : :
442 : : template <typename F>
443 : 28774 : void scope_crate (NodeId node_id, std::string crate_name, F &&f)
444 : : {
445 : 33088 : scope_inner (node_id, std::forward<F> (f), [node_id, &crate_name] () {
446 : 4314 : return new CanonicalPathRecordCrateRoot (node_id, std::move (crate_name));
447 : : });
448 : : }
449 : :
450 : : private:
451 : : template <typename FCreate, typename FCallback>
452 : 262359 : void scope_inner (NodeId id, FCallback &&f_callback, FCreate &&f_create)
453 : : {
454 : 262359 : auto it = records.find (id);
455 : 262359 : if (it == records.end ())
456 : : {
457 : 39096 : CanonicalPathRecord *record = std::forward<FCreate> (f_create) ();
458 : 39096 : it = records.emplace (id, std::unique_ptr<CanonicalPathRecord> (record))
459 : : .first;
460 : : }
461 : :
462 : 262359 : rust_assert (it->second->is_root ()
463 : : || &static_cast<CanonicalPathRecordWithParent &> (*it->second)
464 : : .get_parent ()
465 : : == current_record);
466 : :
467 : 262359 : CanonicalPathRecord *stash = it->second.get ();
468 : 262359 : std::swap (stash, current_record);
469 : :
470 : 262357 : std::forward<FCallback> (f_callback) ();
471 : :
472 : 262357 : std::swap (stash, current_record);
473 : 262357 : }
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 : 58567 : Resolver::CanonicalPath to_canonical_path (NodeId id) const
548 : : {
549 : 58567 : return canonical_ctx.get_path (id);
550 : : }
551 : :
552 : : template <typename S>
553 : : tl::optional<Rib::Definition>
554 : 91946 : resolve_path (const std::vector<S> &segments, ResolutionMode mode,
555 : : std::vector<Error> &collect_errors, Namespace ns)
556 : : {
557 : 91946 : std::function<void (const S &, NodeId)> insert_segment_resolution
558 : 211310 : = [this] (const S &seg, NodeId id) {
559 : 51980 : auto seg_id = unwrap_segment_node_id (seg);
560 : 106114 : if (resolved_nodes.find (Usage (seg_id)) == resolved_nodes.end ())
561 : 85622 : map_usage (Usage (seg_id), Definition (id));
562 : : };
563 : 91946 : switch (ns)
564 : : {
565 : 25379 : case Namespace::Values:
566 : 25379 : return values.resolve_path (segments, mode, insert_segment_resolution,
567 : 25379 : collect_errors);
568 : 63350 : case Namespace::Types:
569 : 63350 : return types.resolve_path (segments, mode, insert_segment_resolution,
570 : 63350 : collect_errors);
571 : 3217 : case Namespace::Macros:
572 : 3217 : return macros.resolve_path (segments, mode, insert_segment_resolution,
573 : 3217 : collect_errors);
574 : 0 : case Namespace::Labels:
575 : 0 : return labels.resolve_path (segments, mode, insert_segment_resolution,
576 : 0 : collect_errors);
577 : 0 : default:
578 : 0 : rust_unreachable ();
579 : : }
580 : 91946 : }
581 : :
582 : : template <typename S, typename... Args>
583 : : tl::optional<Rib::Definition>
584 : 86371 : resolve_path (const std::vector<S> &segments, ResolutionMode mode,
585 : : tl::optional<std::vector<Error> &> collect_errors,
586 : : Namespace ns_first, Args... ns_args)
587 : : {
588 : 86371 : std::initializer_list<Namespace> namespaces = {ns_first, ns_args...};
589 : :
590 : 178317 : for (auto ns : namespaces)
591 : : {
592 : 91946 : std::vector<Error> collect_errors_inner;
593 : 91946 : if (auto ret = resolve_path (segments, mode, collect_errors_inner, ns))
594 : : return ret;
595 : 16372 : if (!collect_errors_inner.empty ())
596 : : {
597 : 11 : if (collect_errors.has_value ())
598 : : {
599 : 6 : std::move (collect_errors_inner.begin (),
600 : : collect_errors_inner.end (),
601 : : std::back_inserter (collect_errors.value ()));
602 : : }
603 : : else
604 : : {
605 : 10 : for (auto &e : collect_errors_inner)
606 : 5 : e.emit ();
607 : : }
608 : 11 : return tl::nullopt;
609 : : }
610 : : }
611 : :
612 : 10786 : return tl::nullopt;
613 : : }
614 : :
615 : : template <typename S, typename... Args>
616 : : tl::optional<Rib::Definition>
617 : 86306 : resolve_path (const std::vector<S> &path_segments,
618 : : bool has_opening_scope_resolution,
619 : : tl::optional<std::vector<Error> &> collect_errors,
620 : : Namespace ns_first, Args... ns_args)
621 : : {
622 : 86306 : auto mode = ResolutionMode::Normal;
623 : 86306 : if (has_opening_scope_resolution)
624 : : {
625 : 733 : if (get_rust_edition () == Edition::E2015)
626 : : mode = ResolutionMode::FromRoot;
627 : : else
628 : 0 : mode = ResolutionMode::FromExtern;
629 : : }
630 : : return resolve_path (path_segments, mode, collect_errors, ns_first,
631 : 86306 : ns_args...);
632 : : }
633 : :
634 : : template <typename S, typename... Args>
635 : : tl::optional<Rib::Definition>
636 : 77402 : resolve_path (const std::vector<S> &path_segments,
637 : : bool has_opening_scope_resolution, Namespace ns_first,
638 : : Args... ns_args)
639 : : {
640 : : return resolve_path (path_segments, has_opening_scope_resolution,
641 : 53600 : tl::nullopt, ns_first, ns_args...);
642 : : }
643 : :
644 : : template <typename S, typename... Args>
645 : : tl::optional<Rib::Definition>
646 : 65 : resolve_path (const std::vector<S> &path_segments, ResolutionMode mode,
647 : : Namespace ns_first, Args... ns_args)
648 : : {
649 : : return resolve_path (path_segments, mode, tl::nullopt, ns_first,
650 : 65 : ns_args...);
651 : : }
652 : :
653 : : template <typename... Args>
654 : 9170 : tl::optional<Rib::Definition> resolve_path (const AST::SimplePath &path,
655 : : Args &&...args)
656 : : {
657 : 8904 : return resolve_path (path.get_segments (),
658 : 9170 : path.has_opening_scope_resolution (),
659 : 9170 : std::forward<Args> (args)...);
660 : : }
661 : :
662 : : template <typename... Args>
663 : 23802 : tl::optional<Rib::Definition> resolve_path (const AST::PathInExpression &path,
664 : : Args &&...args)
665 : : {
666 : 23802 : return resolve_path (path.get_segments (), path.opening_scope_resolution (),
667 : 23802 : std::forward<Args> (args)...);
668 : : }
669 : :
670 : : template <typename... Args>
671 : 53334 : tl::optional<Rib::Definition> resolve_path (const AST::TypePath &path,
672 : : Args &&...args)
673 : : {
674 : : return resolve_path (path.get_segments (),
675 : 53334 : path.has_opening_scope_resolution_op (),
676 : 53334 : std::forward<Args> (args)...);
677 : : }
678 : :
679 : : private:
680 : : /* Map of "usage" nodes which have been resolved to a "definition" node */
681 : : std::map<Usage, Definition> resolved_nodes;
682 : : };
683 : :
684 : : } // namespace Resolver2_0
685 : : } // namespace Rust
686 : :
687 : : #endif // ! RUST_NAME_RESOLVER_2_0_H
|