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

Generated by: LCOV version 2.5.0-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.