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

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.