LCOV - code coverage report
Current view: top level - gcc/rust/resolve - rust-name-resolution-context.h (source / functions) Coverage Total Hit
Test: gcc.info Lines: 89.1 % 192 171
Test Date: 2026-04-20 14:57:17 Functions: 98.9 % 90 89
Legend: Lines:     hit not hit

            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        24442 :   IdentifierMode (bool is_ref, bool is_mut) : is_ref (is_ref), is_mut (is_mut)
     146              :   {}
     147              : 
     148           58 :   bool operator== (const IdentifierMode &other)
     149              :   {
     150           58 :     return other.is_ref == is_ref && other.is_mut == is_mut;
     151              :   }
     152              : 
     153          232 :   bool operator!= (const IdentifierMode &other) { return !(*this == other); }
     154              : };
     155              : 
     156       206636 : 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        34637 :   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       136185 : 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        40900 : class CanonicalPathRecord
     224              : {
     225              : public:
     226              :   virtual Resolver::CanonicalPath as_path (const NameResolutionContext &) = 0;
     227              : 
     228              :   virtual bool is_root () const = 0;
     229              : 
     230              :   virtual ~CanonicalPathRecord () = default;
     231              : };
     232              : 
     233              : class CanonicalPathRecordWithParent : public CanonicalPathRecord
     234              : {
     235              : public:
     236        36192 :   CanonicalPathRecordWithParent (CanonicalPathRecord &parent) : parent (&parent)
     237              :   {}
     238              : 
     239       407043 :   CanonicalPathRecord &get_parent () { return *parent; }
     240              : 
     241       242141 :   bool is_root () const override final { return false; }
     242              : 
     243              : private:
     244              :   CanonicalPathRecord *parent;
     245              : };
     246              : 
     247              : class CanonicalPathRecordCrateRoot : public CanonicalPathRecord
     248              : {
     249              : public:
     250         4708 :   CanonicalPathRecordCrateRoot (NodeId node_id, std::string seg)
     251         4708 :     : node_id (node_id), seg (std::move (seg))
     252              :   {
     253         4708 :     rust_assert (Analysis::Mappings::get ().node_is_crate (node_id));
     254         4708 :     crate_num = Analysis::Mappings::get ().lookup_crate_num (node_id).value ();
     255         4708 :   }
     256              : 
     257              :   Resolver::CanonicalPath as_path (const NameResolutionContext &) override;
     258              : 
     259        31117 :   bool is_root () const override final { return true; }
     260              : 
     261              : private:
     262              :   NodeId node_id;
     263              :   CrateNum crate_num;
     264              :   std::string seg;
     265              : };
     266              : 
     267              : class CanonicalPathRecordNormal : public CanonicalPathRecordWithParent
     268              : {
     269              : public:
     270        30477 :   CanonicalPathRecordNormal (CanonicalPathRecord &parent, NodeId node_id,
     271              :                              std::string seg)
     272        30477 :     : CanonicalPathRecordWithParent (parent), node_id (node_id),
     273        30477 :       seg (std::move (seg))
     274              :   {
     275        30477 :     rust_assert (!Analysis::Mappings::get ().node_is_crate (node_id));
     276        30477 :   }
     277              : 
     278              :   Resolver::CanonicalPath as_path (const NameResolutionContext &) override;
     279              : 
     280              : private:
     281              :   NodeId node_id;
     282              :   std::string seg;
     283              : };
     284              : 
     285              : class CanonicalPathRecordLookup : public CanonicalPathRecord
     286              : {
     287              : public:
     288         5715 :   CanonicalPathRecordLookup (NodeId lookup_id)
     289         5715 :     : lookup_id (lookup_id), cache (nullptr)
     290              :   {}
     291              : 
     292              :   Resolver::CanonicalPath as_path (const NameResolutionContext &) override;
     293              : 
     294            0 :   bool is_root () const override final { return true; }
     295              : 
     296              : private:
     297              :   NodeId lookup_id;
     298              :   CanonicalPathRecord *cache;
     299              : };
     300              : 
     301              : class CanonicalPathRecordImpl : public CanonicalPathRecordWithParent
     302              : {
     303              : public:
     304          973 :   CanonicalPathRecordImpl (CanonicalPathRecord &parent, NodeId impl_id,
     305              :                            NodeId type_id)
     306          973 :     : CanonicalPathRecordWithParent (parent), impl_id (impl_id),
     307          973 :       type_record (type_id)
     308              :   {}
     309              : 
     310              :   Resolver::CanonicalPath as_path (const NameResolutionContext &) override;
     311              : 
     312              : private:
     313              :   NodeId impl_id;
     314              :   CanonicalPathRecordLookup type_record;
     315              : };
     316              : 
     317              : class CanonicalPathRecordTraitImpl : public CanonicalPathRecordWithParent
     318              : {
     319              : public:
     320         4742 :   CanonicalPathRecordTraitImpl (CanonicalPathRecord &parent, NodeId impl_id,
     321              :                                 NodeId type_id, NodeId trait_path_id)
     322         4742 :     : CanonicalPathRecordWithParent (parent), impl_id (impl_id),
     323         4742 :       type_record (type_id), trait_path_record (trait_path_id)
     324              :   {}
     325              : 
     326              :   Resolver::CanonicalPath as_path (const NameResolutionContext &) override;
     327              : 
     328              : private:
     329              :   NodeId impl_id;
     330              :   CanonicalPathRecordLookup type_record;
     331              :   CanonicalPathRecordLookup trait_path_record;
     332              : };
     333              : 
     334              : class CanonicalPathCtx
     335              : {
     336              : public:
     337         4684 :   CanonicalPathCtx (const NameResolutionContext &ctx)
     338         4684 :     : current_record (nullptr), nr_ctx (&ctx)
     339              :   {}
     340              : 
     341        59700 :   Resolver::CanonicalPath get_path (NodeId id) const
     342              :   {
     343        59700 :     return get_record (id).as_path (*nr_ctx);
     344              :   }
     345              : 
     346        59700 :   CanonicalPathRecord &get_record (NodeId id) const
     347              :   {
     348        59700 :     auto it = records.find (id);
     349        59700 :     rust_assert (it != records.end ());
     350        59700 :     return *it->second;
     351              :   }
     352              : 
     353        16063 :   tl::optional<CanonicalPathRecord *> get_record_opt (NodeId id) const
     354              :   {
     355        16063 :     auto it = records.find (id);
     356        16063 :     if (it == records.end ())
     357        11085 :       return tl::nullopt;
     358              :     else
     359         4978 :       return it->second.get ();
     360              :   }
     361              : 
     362              :   void insert_record (NodeId id, const Identifier &ident)
     363              :   {
     364              :     insert_record (id, ident.as_string ());
     365              :   }
     366              : 
     367              :   void insert_record (NodeId id, std::string seg)
     368              :   {
     369              :     rust_assert (current_record != nullptr);
     370              : 
     371              :     auto it = records.find (id);
     372              :     if (it == records.end ())
     373              :       {
     374              :         auto record = new CanonicalPathRecordNormal (*current_record, id,
     375              :                                                      std::move (seg));
     376              :         bool ok
     377              :           = records.emplace (id, std::unique_ptr<CanonicalPathRecord> (record))
     378              :               .second;
     379              :         rust_assert (ok);
     380              :       }
     381              :   }
     382              : 
     383       204090 :   template <typename F> void scope (NodeId id, const Identifier &ident, F &&f)
     384              :   {
     385       408180 :     scope (id, ident.as_string (), std::forward<F> (f));
     386       204089 :   }
     387              : 
     388       204090 :   template <typename F> void scope (NodeId id, std::string seg, F &&f)
     389              :   {
     390       204090 :     rust_assert (current_record != nullptr);
     391              : 
     392       234567 :     scope_inner (id, std::forward<F> (f), [this, id, &seg] () {
     393        30477 :       return new CanonicalPathRecordNormal (*current_record, id,
     394        30477 :                                             std::move (seg));
     395              :     });
     396       204089 :   }
     397              : 
     398         6332 :   template <typename F> void scope_impl (AST::InherentImpl &impl, F &&f)
     399              :   {
     400         6332 :     rust_assert (current_record != nullptr);
     401              : 
     402         6332 :     NodeId id = impl.get_node_id ();
     403         6332 :     scope_inner (id, std::forward<F> (f), [this, id, &impl] () {
     404          973 :       return new CanonicalPathRecordImpl (*current_record, id,
     405          973 :                                           impl.get_type ().get_node_id ());
     406              :     });
     407         6332 :   }
     408              : 
     409        31719 :   template <typename F> void scope_impl (AST::TraitImpl &impl, F &&f)
     410              :   {
     411        31719 :     rust_assert (current_record != nullptr);
     412              : 
     413        31719 :     NodeId id = impl.get_node_id ();
     414        31719 :     scope_inner (id, std::forward<F> (f), [this, id, &impl] () {
     415         4742 :       return new CanonicalPathRecordTraitImpl (
     416         4742 :         *current_record, id, impl.get_type ().get_node_id (),
     417         4742 :         impl.get_trait_path ().get_node_id ());
     418              :     });
     419        31719 :   }
     420              : 
     421              :   template <typename F>
     422        31117 :   void scope_crate (NodeId node_id, std::string crate_name, F &&f)
     423              :   {
     424        35825 :     scope_inner (node_id, std::forward<F> (f), [node_id, &crate_name] () {
     425         4708 :       return new CanonicalPathRecordCrateRoot (node_id, std::move (crate_name));
     426              :     });
     427              :   }
     428              : 
     429              : private:
     430              :   template <typename FCreate, typename FCallback>
     431       273258 :   void scope_inner (NodeId id, FCallback &&f_callback, FCreate &&f_create)
     432              :   {
     433       273258 :     auto it = records.find (id);
     434       273258 :     if (it == records.end ())
     435              :       {
     436        40900 :         CanonicalPathRecord *record = std::forward<FCreate> (f_create) ();
     437        40900 :         it = records.emplace (id, std::unique_ptr<CanonicalPathRecord> (record))
     438              :                .first;
     439              :       }
     440              : 
     441       273258 :     rust_assert (it->second->is_root ()
     442              :                  || &static_cast<CanonicalPathRecordWithParent &> (*it->second)
     443              :                         .get_parent ()
     444              :                       == current_record);
     445              : 
     446       273258 :     CanonicalPathRecord *stash = it->second.get ();
     447       273258 :     std::swap (stash, current_record);
     448              : 
     449       273256 :     std::forward<FCallback> (f_callback) ();
     450              : 
     451       273256 :     std::swap (stash, current_record);
     452       273256 :   }
     453              : 
     454              :   std::unordered_map<NodeId, std::unique_ptr<CanonicalPathRecord>> records;
     455              :   CanonicalPathRecord *current_record;
     456              : 
     457              :   const NameResolutionContext *nr_ctx;
     458              : };
     459              : 
     460              : // Now our resolver, which keeps track of all the `ForeverStack`s we could want
     461              : class NameResolutionContext
     462              : {
     463              : public:
     464              :   NameResolutionContext ();
     465              : 
     466              :   /**
     467              :    * Insert a new value in the current rib.
     468              :    *
     469              :    * @param name Name of the value to insert.
     470              :    * @param id This value's ID, e.g the function definition's node ID.
     471              :    * @param ns Namespace in which to insert the value.
     472              :    */
     473              :   tl::expected<NodeId, DuplicateNameError> insert (Identifier name, NodeId id,
     474              :                                                    Namespace ns);
     475              : 
     476              :   tl::expected<NodeId, DuplicateNameError>
     477              :   insert_variant (Identifier name, NodeId id, bool is_also_value);
     478              : 
     479              :   tl::expected<NodeId, DuplicateNameError>
     480              :   insert_shadowable (Identifier name, NodeId id, Namespace ns);
     481              : 
     482              :   tl::expected<NodeId, DuplicateNameError>
     483              :   insert_globbed (Identifier name, NodeId id, Namespace ns);
     484              : 
     485              :   /**
     486              :    * Run a lambda in a "scoped" context, meaning that a new `Rib` will be pushed
     487              :    * before executing the lambda and then popped. This is useful for all kinds
     488              :    * of scope in the language, such as a block expression or when entering a
     489              :    * function. This variant of the function enters a new scope in *all*
     490              :    * namespaces, while the second variant enters a scope in *one* namespace.
     491              :    *
     492              :    * @param rib_kind New `Rib` to create when entering this scope. A function
     493              :    *        `Rib`, or an item `Rib`... etc
     494              :    * @param scope_id node ID of the scope we are entering, e.g the block's
     495              :    *        `NodeId`.
     496              :    * @param lambda Function to run within that scope
     497              :    * @param path Optional path of the scope. This is useful for scopes which
     498              :    *        affect path resolution, such as modules. Defaults to an empty
     499              :    *        option.
     500              :    */
     501              :   // FIXME: Do we want to handle something in particular for expected within the
     502              :   // scoped lambda?
     503              :   void scoped (Rib::Kind rib_kind, NodeId scope_id,
     504              :                std::function<void (void)> lambda,
     505              :                tl::optional<Identifier> path = {});
     506              :   void scoped (Rib::Kind rib_kind, Namespace ns, NodeId scope_id,
     507              :                std::function<void (void)> lambda,
     508              :                tl::optional<Identifier> path = {});
     509              : 
     510              :   ForeverStack<Namespace::Values> values;
     511              :   ForeverStack<Namespace::Types> types;
     512              :   ForeverStack<Namespace::Macros> macros;
     513              :   ForeverStack<Namespace::Labels> labels;
     514              : 
     515              :   Analysis::Mappings &mappings;
     516              :   StackedContexts<BindingLayer> bindings;
     517              : 
     518              :   CanonicalPathCtx canonical_ctx;
     519              : 
     520              :   // TODO: Rename
     521              :   // TODO: Use newtype pattern for Usage and Definition
     522              :   void map_usage (Usage usage, Definition definition);
     523              : 
     524              :   tl::optional<NodeId> lookup (NodeId usage) const;
     525              : 
     526        59700 :   Resolver::CanonicalPath to_canonical_path (NodeId id) const
     527              :   {
     528        59700 :     return canonical_ctx.get_path (id);
     529              :   }
     530              : 
     531              :   tl::optional<Rib::Definition>
     532        94054 :   resolve_path (const ResolutionPath &path, ResolutionMode mode,
     533              :                 std::vector<Error> &collect_errors, Namespace ns)
     534              :   {
     535        94054 :     std::function<void (Usage, Definition)> insert_segment_resolution
     536        94054 :       = [this] (Usage seg_id, Definition id) {
     537       110815 :           if (resolved_nodes.find (seg_id) == resolved_nodes.end ())
     538        91324 :             map_usage (seg_id, id);
     539       204869 :         };
     540              : 
     541        94054 :     tl::optional<Rib::Definition> resolved = tl::nullopt;
     542              : 
     543        94054 :     switch (ns)
     544              :       {
     545        27336 :       case Namespace::Values:
     546        54672 :         resolved = values.resolve_path (path, mode, insert_segment_resolution,
     547        27336 :                                         collect_errors);
     548        27336 :         break;
     549        63300 :       case Namespace::Types:
     550       126600 :         resolved = types.resolve_path (path, mode, insert_segment_resolution,
     551        63300 :                                        collect_errors);
     552        63300 :         break;
     553         3418 :       case Namespace::Macros:
     554         6836 :         resolved = macros.resolve_path (path, mode, insert_segment_resolution,
     555         3418 :                                         collect_errors);
     556         3418 :         break;
     557            0 :       case Namespace::Labels:
     558            0 :         resolved = labels.resolve_path (path, mode, insert_segment_resolution,
     559            0 :                                         collect_errors);
     560            0 :         break;
     561            0 :       default:
     562            0 :         rust_unreachable ();
     563              :       }
     564              : 
     565              :     // If it fails, switch to std prelude resolution if it exists
     566        94054 :     if (prelude && !resolved)
     567              :       {
     568              :         // TODO: Factor this with the above
     569            0 :         switch (ns)
     570              :           {
     571            0 :           case Namespace::Values:
     572            0 :             return values.resolve_path (path, mode, insert_segment_resolution,
     573            0 :                                         collect_errors, *prelude);
     574            0 :           case Namespace::Types:
     575            0 :             return types.resolve_path (path, mode, insert_segment_resolution,
     576            0 :                                        collect_errors, *prelude);
     577            0 :           case Namespace::Macros:
     578            0 :             return macros.resolve_path (path, mode, insert_segment_resolution,
     579            0 :                                         collect_errors, *prelude);
     580            0 :           case Namespace::Labels:
     581            0 :             return labels.resolve_path (path, mode, insert_segment_resolution,
     582            0 :                                         collect_errors, *prelude);
     583              :           default:
     584              :             rust_unreachable ();
     585              :           }
     586              :       }
     587              : 
     588        94054 :     return resolved;
     589        94054 :   }
     590              : 
     591        90175 :   class ResolutionBuilder
     592              :   {
     593              :   public:
     594        90175 :     ResolutionBuilder (NameResolutionContext &ctx) : ctx (&ctx) {}
     595              : 
     596              :     template <typename S>
     597        90110 :     void set_path (const std::vector<S> &path_segments, NodeId node_id,
     598              :                    bool has_opening_scope)
     599              :     {
     600        90110 :       path = ResolutionPath (path_segments, node_id);
     601        90110 :       mode = ResolutionMode::Normal;
     602        90110 :       if (has_opening_scope)
     603              :         {
     604          738 :           if (get_rust_edition () == Edition::E2015)
     605          738 :             mode = ResolutionMode::FromRoot;
     606              :           else
     607            0 :             mode = ResolutionMode::FromExtern;
     608              :         }
     609        90110 :       has_path_set = true;
     610        90110 :     }
     611              : 
     612              :     template <typename S>
     613           65 :     void set_path (const std::vector<S> &path_segments, NodeId node_id,
     614              :                    ResolutionMode mode)
     615              :     {
     616           65 :       path = ResolutionPath (path_segments, node_id);
     617           65 :       this->mode = mode;
     618           65 :       has_path_set = true;
     619           65 :     }
     620              : 
     621              :     void set_path (const AST::SimplePath &path)
     622              :     {
     623              :       set_path (path.get_segments (), path.get_node_id (),
     624              :                 path.has_opening_scope_resolution ());
     625              :     }
     626              : 
     627              :     void set_path (const AST::PathInExpression &path)
     628              :     {
     629              :       set_path (path.get_segments (), path.get_node_id (),
     630              :                 path.opening_scope_resolution ());
     631              :     }
     632              : 
     633              :     void set_path (const AST::TypePath &path)
     634              :     {
     635              :       set_path (path.get_segments (), path.get_node_id (),
     636              :                 path.has_opening_scope_resolution_op ());
     637              :     }
     638              : 
     639              :     void set_mode (ResolutionMode mode) { this->mode = mode; }
     640              : 
     641       114456 :     void add_namespaces (Namespace ns) { namespace_list.push_back (ns); }
     642              : 
     643        24281 :     template <typename... Args> void add_namespaces (Namespace ns, Args... rest)
     644              :     {
     645        24281 :       add_namespaces (ns);
     646        24281 :       add_namespaces (rest...);
     647        24281 :     }
     648              : 
     649         9165 :     void set_collect_errors (tl::optional<std::vector<Error> &> collect_errors)
     650              :     {
     651         9165 :       this->collect_errors = collect_errors;
     652              :     }
     653              : 
     654        90175 :     tl::optional<Rib::Definition> resolve ()
     655              :     {
     656        90175 :       rust_assert (has_path_set);
     657              : 
     658       102546 :       for (auto ns : namespace_list)
     659              :         {
     660        94054 :           std::vector<Error> collect_errors_inner;
     661        94054 :           if (auto ret
     662        94054 :               = ctx->resolve_path (path, mode, collect_errors_inner, ns))
     663        94054 :             return ret;
     664        12371 :           if (!collect_errors_inner.empty ())
     665              :             {
     666           12 :               if (collect_errors.has_value ())
     667              :                 {
     668            6 :                   std::move (collect_errors_inner.begin (),
     669              :                              collect_errors_inner.end (),
     670              :                              std::back_inserter (collect_errors.value ()));
     671              :                 }
     672              :               else
     673              :                 {
     674           12 :                   for (auto &e : collect_errors_inner)
     675            6 :                     e.emit ();
     676              :                 }
     677              :             }
     678        94054 :         }
     679              : 
     680         8492 :       return tl::nullopt;
     681              :     }
     682              : 
     683              :   private:
     684              :     ResolutionPath path;
     685              :     ResolutionMode mode;
     686              :     bool has_path_set;
     687              : 
     688              :     std::vector<Namespace> namespace_list;
     689              : 
     690              :     tl::optional<std::vector<Error> &> collect_errors;
     691              : 
     692              :     NameResolutionContext *ctx;
     693              :   };
     694              : 
     695              :   template <typename S, typename... Args>
     696              :   tl::optional<Rib::Definition>
     697              :   resolve_path (const std::vector<S> &path_segments, ResolutionMode mode,
     698              :                 tl::optional<std::vector<Error> &> collect_errors,
     699              :                 Namespace ns_first, Args... ns_args)
     700              :   {
     701              :     ResolutionBuilder builder (*this);
     702              :     builder.set_path (path_segments, UNKNOWN_NODEID, mode);
     703              :     builder.add_namespaces (ns_first, ns_args...);
     704              :     builder.set_collect_errors (collect_errors);
     705              : 
     706              :     return builder.resolve ();
     707              :   }
     708              : 
     709              :   template <typename S, typename... Args>
     710              :   tl::optional<Rib::Definition>
     711         9165 :   resolve_path (const std::vector<S> &path_segments,
     712              :                 bool has_opening_scope_resolution,
     713              :                 tl::optional<std::vector<Error> &> collect_errors,
     714              :                 Namespace ns_first, Args... ns_args)
     715              :   {
     716         9165 :     ResolutionBuilder builder (*this);
     717         9165 :     builder.set_path (path_segments, UNKNOWN_NODEID,
     718              :                       has_opening_scope_resolution);
     719         9165 :     builder.add_namespaces (ns_first, ns_args...);
     720         9165 :     builder.set_collect_errors (collect_errors);
     721              : 
     722         9165 :     return builder.resolve ();
     723         9165 :   }
     724              : 
     725              :   template <typename S, typename... Args>
     726              :   tl::optional<Rib::Definition>
     727        80945 :   resolve_path (const std::vector<S> &path_segments,
     728              :                 bool has_opening_scope_resolution, Namespace ns_first,
     729              :                 Args... ns_args)
     730              :   {
     731        80945 :     ResolutionBuilder builder (*this);
     732        80945 :     builder.set_path (path_segments, UNKNOWN_NODEID,
     733              :                       has_opening_scope_resolution);
     734        80945 :     builder.add_namespaces (ns_first, ns_args...);
     735              : 
     736        80945 :     return builder.resolve ();
     737        80945 :   }
     738              : 
     739              :   template <typename S, typename... Args>
     740              :   tl::optional<Rib::Definition>
     741           65 :   resolve_path (const std::vector<S> &path_segments, ResolutionMode mode,
     742              :                 Namespace ns_first, Args... ns_args)
     743              :   {
     744           65 :     ResolutionBuilder builder (*this);
     745           65 :     builder.set_path (path_segments, UNKNOWN_NODEID, mode);
     746           65 :     builder.add_namespaces (ns_first, ns_args...);
     747              : 
     748           65 :     return builder.resolve ();
     749           65 :   }
     750              : 
     751              :   template <typename... Args>
     752         9650 :   tl::optional<Rib::Definition> resolve_path (const AST::SimplePath &path,
     753              :                                               Args &&...args)
     754              :   {
     755         9165 :     return resolve_path (path.get_segments (),
     756         9650 :                          path.has_opening_scope_resolution (),
     757         9650 :                          std::forward<Args> (args)...);
     758              :   }
     759              : 
     760              :   template <typename... Args>
     761        25697 :   tl::optional<Rib::Definition> resolve_path (const AST::PathInExpression &path,
     762              :                                               Args &&...args)
     763              :   {
     764        25697 :     return resolve_path (path.get_segments (), path.opening_scope_resolution (),
     765        25697 :                          std::forward<Args> (args)...);
     766              :   }
     767              : 
     768              :   template <typename... Args>
     769        54763 :   tl::optional<Rib::Definition> resolve_path (const AST::TypePath &path,
     770              :                                               Args &&...args)
     771              :   {
     772              :     return resolve_path (path.get_segments (),
     773        54763 :                          path.has_opening_scope_resolution_op (),
     774        54763 :                          std::forward<Args> (args)...);
     775              :   }
     776              : 
     777              :   /* If declared with #[prelude_import], the current standard library module */
     778              :   tl::optional<NodeId> prelude;
     779              : 
     780              : private:
     781              :   /* Map of "usage" nodes which have been resolved to a "definition" node */
     782              :   std::map<Usage, Definition> resolved_nodes;
     783              : };
     784              : 
     785              : } // namespace Resolver2_0
     786              : } // namespace Rust
     787              : 
     788              : #endif // ! RUST_NAME_RESOLVER_2_0_CTX_H
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.