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

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.