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: 85.6 % 209 179
Test Date: 2026-07-11 15:47:05 Functions: 98.9 % 90 89
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
       2              : 
       3              : // This file is part of GCC.
       4              : 
       5              : // GCC is free software; you can redistribute it and/or modify it under
       6              : // the terms of the GNU General Public License as published by the Free
       7              : // Software Foundation; either version 3, or (at your option) any later
       8              : // version.
       9              : 
      10              : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11              : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12              : // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13              : // for more details.
      14              : 
      15              : // You should have received a copy of the GNU General Public License
      16              : // along with GCC; see the file COPYING3.  If not see
      17              : // <http://www.gnu.org/licenses/>.
      18              : 
      19              : #ifndef RUST_NAME_RESOLVER_2_0_CTX_H
      20              : #define RUST_NAME_RESOLVER_2_0_CTX_H
      21              : 
      22              : #include "optional.h"
      23              : #include "rust-forever-stack.h"
      24              : #include "rust-hir-map.h"
      25              : #include "rust-rib.h"
      26              : #include "rust-stacked-contexts.h"
      27              : #include "rust-item.h"
      28              : #include "rust-name-resolution.h"
      29              : 
      30              : namespace Rust {
      31              : namespace Resolver2_0 {
      32              : 
      33              : // TODO: Add missing mappings and data structures
      34              : 
      35              : /**
      36              : The data structures we need to develop need to fill in a few roles - like the
      37              : original name resolver, they need to be accessible at multiple points during the
      38              : pipeline to allow compiler passes such as macro expansion or typechecking to
      39              : benefit from them. Unlike the original name resolution, these data structures
      40              : need to be created by multiple compiler passes: Whereas the original name
      41              : resolution of gccrs tries to perform name resolution in a single pass, it fails
      42              : at properly handling more complex name resolution cases such as macro name
      43              : resolution, imports in general, and glob imports in particular. The goal of this
      44              : new name resolution algorithm is to split the name resolution in at least two
      45              : passes - `Early` name resolution, which takes care of macro name resolution and
      46              : import resolution, and `Late` name resolution - your typical name resolution,
      47              : for types, functions, variables...
      48              : 
      49              :   1. `Early`
      50              : 
      51              :   The Early name resolution is tied in snuggly with macro expansion: macro
      52              : expansion cannot happen without some form of name resolution (pointing an
      53              : invocation to its definition) but may also *depend* on name resolution (a macro
      54              : generating another macro... or importing items... and funny other cases like
      55              : these). It needs to work in a fixed-point fashion alongside macro expansion:
      56              : While there are imports to resolve, or macros to expand, we need to keep going
      57              : and resolve them. This is achieved, among other things, by a top-level name
      58              : resolution pass in charge of collection use statements and macro definitions (as
      59              : well as Items, which will be useful for later passes of the name resolution).
      60              : 
      61              :     This top-level pass exists because Rust enables you to call a function
      62              : before having declared it (at a lexical level, i.e calling `f(15)` at line 3
      63              : while the `f` function is declared at line 1499).
      64              : 
      65              :   This Early pass needs to build the first part of our "resolution map", which
      66              : will then be used in multiple contexts:
      67              : 
      68              :   1. The MacroExpander, in a read-only fashion: fetching macro definitions for
      69              : each invocation and performing the expansion.
      70              :   2. `Late`, which will write more data inside that resolution map, and use it
      71              : to perform its name resolution too.
      72              : 
      73              :   This is where the first challenge of this data structure lies: The existing
      74              : data structures and name resolution algorithm relies on the name resolution pass
      75              : happening just once. In typical name resolution fashion, when it sees a lexical
      76              : scope (a new module, a function's block, a block expression...), it "pushes" a
      77              : new "Scope" to a stack of these scopes, and "pops" it when exiting said lexical
      78              : scope. However, because we are splitting the name resolution into two passes, we
      79              : would like to avoid re-doing a bunch of work we've already done - which is why
      80              : this data structure needs to allow "re-entrancy", or to at least not keep as
      81              : much state as the existing one, and allow for viewing the same module multiple
      82              : times without throwing a fit.
      83              : 
      84              :   We will be implementing a "forever stack" of scopes, which allows the user the
      85              : pushing of new scopes onto the stack, but only simulates the popping of a scope:
      86              : When pushing new scopes, more space is allocated on our stack, and we keep
      87              : track of this scope as being the current one - however, when popping this scope,
      88              : we do not actually delete the memory associated with it: we simply mark the
      89              : previous scope (parent) as the current one.
      90              : 
      91              : In the example below, each number indicates the "state" of our resolution map,
      92              : and the carret is used to point to the current lexical scope.
      93              : 
      94              : ```rust
      95              :                 // []
      96              :                 //
      97              : fn main() {     // [ `main` scope: {} ]
      98              :                 //         ^
      99              :   let a = 15;   // [ `main` scope: { Decl(a) } ]
     100              :                 //         ^
     101              :   {  _PUSH_     // [ `main` scope: { Decl(a) }, anonymous scope: {} ]
     102              :                 //                                        ^
     103              :     let a = 16; // [ `main` scope: { Decl(a) }, anonymous scope: { Decl(a) } ]
     104              :                 //                                        ^
     105              :     f(a);       // [ `main` scope: { Decl(a) }, anonymous scope: { Decl(a) } ]
     106              :                 //                                        ^
     107              :   }   _POP_     // [ `main` scope: { Decl(a) }, anonymous scope: { Decl(a) } ]
     108              :                 //         ^
     109              :   f(a);         // [ `main` scope: { Decl(a) }, anonymous scope: { Decl(a) } ]
     110              :                 //         ^
     111              : }
     112              : ```
     113              : 
     114              : This allows us to revisit scopes previously visited in later phases of the name
     115              : resolution, and add more information if necessary.
     116              : 
     117              :   2. `Late`
     118              : 
     119              :   `Late` name resolution possesses some unique challenges since Rust's name
     120              : resolution rules are extremely complex - variable shadowing, variable capture in
     121              : closures (but not inner functions!)... You can have a look at a fucked up
     122              : example here:
     123              : 
     124              : https://rustc-dev-guide.rust-lang.org/name-resolution.html#scopes-and-ribs
     125              : 
     126              : This requires us to think about what exactly to put in our `Scope`s and what to
     127              : do with our `Rib`s - and how it affects our data structures. For example, in the
     128              : above example, `rustc` demonstrates how multiple `Rib`s can be created inside of
     129              : a single lexical scope for variables, as the Rust programming language allows
     130              : shadowing.
     131              : 
     132              :     TODO: Mention macro hygiene and that it is the same
     133              :     TODO: How does this affect our data structures?
     134              :     TODO: Last challenge - reuse the same APIs to allow the typechecker to not
     135              : change?
     136              :     TODO: Mention that ForeverStack is templated to make sure that behavior is
     137              : correct
     138              : */
     139              : 
     140              : struct IdentifierMode
     141              : {
     142              :   bool is_ref;
     143              :   bool is_mut;
     144              : 
     145        24747 :   IdentifierMode (bool is_ref, bool is_mut) : is_ref (is_ref), is_mut (is_mut)
     146              :   {}
     147              : 
     148           58 :   bool operator== (const IdentifierMode &other)
     149              :   {
     150           58 :     return other.is_ref == is_ref && other.is_mut == is_mut;
     151              :   }
     152              : 
     153          232 :   bool operator!= (const IdentifierMode &other) { return !(*this == other); }
     154              : };
     155              : 
     156       209732 : 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        35153 :   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       138250 : 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        41581 : 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        36786 :   CanonicalPathRecordWithParent (CanonicalPathRecord &parent) : parent (&parent)
     239              :   {}
     240              : 
     241       412019 :   CanonicalPathRecord &get_parent () { return *parent; }
     242              : 
     243       245715 :   bool is_root () const override final { return false; }
     244              : 
     245              : private:
     246              :   CanonicalPathRecord *parent;
     247              : };
     248              : 
     249              : class CanonicalPathRecordCrateRoot : public CanonicalPathRecord
     250              : {
     251              : public:
     252         4795 :   CanonicalPathRecordCrateRoot (NodeId node_id, std::string seg)
     253         4795 :     : node_id (node_id), seg (std::move (seg))
     254              :   {
     255         4795 :     rust_assert (Analysis::Mappings::get ().node_is_crate (node_id));
     256         4795 :     crate_num = Analysis::Mappings::get ().lookup_crate_num (node_id).value ();
     257         4795 :   }
     258              : 
     259              :   Resolver::CanonicalPath as_path (const NameResolutionContext &,
     260              :                                    Namespace ns) override;
     261              : 
     262        31646 :   bool is_root () const override final { return true; }
     263              : 
     264              : private:
     265              :   NodeId node_id;
     266              :   CrateNum crate_num;
     267              :   std::string seg;
     268              : };
     269              : 
     270              : class CanonicalPathRecordNormal : public CanonicalPathRecordWithParent
     271              : {
     272              : public:
     273        30975 :   CanonicalPathRecordNormal (CanonicalPathRecord &parent, NodeId node_id,
     274              :                              std::string seg)
     275        30975 :     : CanonicalPathRecordWithParent (parent), node_id (node_id),
     276        30975 :       seg (std::move (seg))
     277              :   {
     278        30975 :     rust_assert (!Analysis::Mappings::get ().node_is_crate (node_id));
     279        30975 :   }
     280              : 
     281              :   Resolver::CanonicalPath as_path (const NameResolutionContext &,
     282              :                                    Namespace ns) override;
     283              : 
     284              : private:
     285              :   NodeId node_id;
     286              :   std::string seg;
     287              : };
     288              : 
     289              : class CanonicalPathRecordLookup : public CanonicalPathRecord
     290              : {
     291              : public:
     292         5811 :   CanonicalPathRecordLookup (NodeId lookup_id)
     293         5811 :     : lookup_id (lookup_id), cache (nullptr)
     294              :   {}
     295              : 
     296              :   Resolver::CanonicalPath as_path (const NameResolutionContext &,
     297              :                                    Namespace ns) override;
     298              : 
     299            0 :   bool is_root () const override final { return true; }
     300              : 
     301              : private:
     302              :   NodeId lookup_id;
     303              :   CanonicalPathRecord *cache;
     304              : };
     305              : 
     306              : class CanonicalPathRecordImpl : public CanonicalPathRecordWithParent
     307              : {
     308              : public:
     309          999 :   CanonicalPathRecordImpl (CanonicalPathRecord &parent, NodeId impl_id,
     310              :                            NodeId type_id)
     311          999 :     : CanonicalPathRecordWithParent (parent), impl_id (impl_id),
     312          999 :       type_record (type_id)
     313              :   {}
     314              : 
     315              :   Resolver::CanonicalPath as_path (const NameResolutionContext &,
     316              :                                    Namespace ns) override;
     317              : 
     318              : private:
     319              :   NodeId impl_id;
     320              :   CanonicalPathRecordLookup type_record;
     321              : };
     322              : 
     323              : class CanonicalPathRecordTraitImpl : public CanonicalPathRecordWithParent
     324              : {
     325              : public:
     326         4812 :   CanonicalPathRecordTraitImpl (CanonicalPathRecord &parent, NodeId impl_id,
     327              :                                 NodeId type_id, NodeId trait_path_id)
     328         4812 :     : CanonicalPathRecordWithParent (parent), impl_id (impl_id),
     329         4812 :       type_record (type_id), trait_path_record (trait_path_id)
     330              :   {}
     331              : 
     332              :   Resolver::CanonicalPath as_path (const NameResolutionContext &,
     333              :                                    Namespace ns) override;
     334              : 
     335              : private:
     336              :   NodeId impl_id;
     337              :   CanonicalPathRecordLookup type_record;
     338              :   CanonicalPathRecordLookup trait_path_record;
     339              : };
     340              : 
     341              : class CanonicalPathCtx
     342              : {
     343              : public:
     344         4771 :   CanonicalPathCtx (const NameResolutionContext &ctx)
     345         4771 :     : current_record (nullptr), nr_ctx (&ctx)
     346              :   {}
     347              : 
     348        60392 :   Resolver::CanonicalPath get_path (NodeId id, Namespace ns) const
     349              :   {
     350        60392 :     return get_record (id).as_path (*nr_ctx, ns);
     351              :   }
     352              : 
     353        60392 :   CanonicalPathRecord &get_record (NodeId id) const
     354              :   {
     355        60392 :     auto it = records.find (id);
     356        60392 :     rust_assert (it != records.end ());
     357        60392 :     return *it->second;
     358              :   }
     359              : 
     360         9370 :   tl::optional<CanonicalPathRecord *> get_record_opt (NodeId id) const
     361              :   {
     362         9370 :     auto it = records.find (id);
     363         9370 :     if (it == records.end ())
     364         4348 :       return tl::nullopt;
     365              :     else
     366         5022 :       return it->second.get ();
     367              :   }
     368              : 
     369              :   void insert_record (NodeId id, const Identifier &ident)
     370              :   {
     371              :     insert_record (id, ident.as_string ());
     372              :   }
     373              : 
     374              :   void insert_record (NodeId id, std::string seg)
     375              :   {
     376              :     rust_assert (current_record != nullptr);
     377              : 
     378              :     auto it = records.find (id);
     379              :     if (it == records.end ())
     380              :       {
     381              :         auto record = new CanonicalPathRecordNormal (*current_record, id,
     382              :                                                      std::move (seg));
     383              :         bool ok
     384              :           = records.emplace (id, std::unique_ptr<CanonicalPathRecord> (record))
     385              :               .second;
     386              :         rust_assert (ok);
     387              :       }
     388              :   }
     389              : 
     390       207088 :   template <typename F> void scope (NodeId id, const Identifier &ident, F &&f)
     391              :   {
     392       414176 :     scope (id, ident.as_string (), std::forward<F> (f));
     393       207086 :   }
     394              : 
     395       207088 :   template <typename F> void scope (NodeId id, std::string seg, F &&f)
     396              :   {
     397       207088 :     rust_assert (current_record != nullptr);
     398              : 
     399       238063 :     scope_inner (id, std::forward<F> (f), [this, id, &seg] () {
     400        30975 :       return new CanonicalPathRecordNormal (*current_record, id,
     401        30975 :                                             std::move (seg));
     402              :     });
     403       207086 :   }
     404              : 
     405         6488 :   template <typename F> void scope_impl (AST::InherentImpl &impl, F &&f)
     406              :   {
     407         6488 :     rust_assert (current_record != nullptr);
     408              : 
     409         6488 :     NodeId id = impl.get_node_id ();
     410         6488 :     scope_inner (id, std::forward<F> (f), [this, id, &impl] () {
     411          999 :       return new CanonicalPathRecordImpl (*current_record, id,
     412          999 :                                           impl.get_type ().get_node_id ());
     413              :     });
     414         6488 :   }
     415              : 
     416        32139 :   template <typename F> void scope_impl (AST::TraitImpl &impl, F &&f)
     417              :   {
     418        32139 :     rust_assert (current_record != nullptr);
     419              : 
     420        32139 :     NodeId id = impl.get_node_id ();
     421        32139 :     scope_inner (id, std::forward<F> (f), [this, id, &impl] () {
     422         4812 :       return new CanonicalPathRecordTraitImpl (
     423         4812 :         *current_record, id, impl.get_type ().get_node_id (),
     424         4812 :         impl.get_trait_path ().get_node_id ());
     425              :     });
     426        32139 :   }
     427              : 
     428              :   template <typename F>
     429        31646 :   void scope_crate (NodeId node_id, std::string crate_name, F &&f)
     430              :   {
     431        36441 :     scope_inner (node_id, std::forward<F> (f), [node_id, &crate_name] () {
     432         4795 :       return new CanonicalPathRecordCrateRoot (node_id, std::move (crate_name));
     433              :     });
     434              :   }
     435              : 
     436              : private:
     437              :   template <typename FCreate, typename FCallback>
     438       277361 :   void scope_inner (NodeId id, FCallback &&f_callback, FCreate &&f_create)
     439              :   {
     440       277361 :     auto it = records.find (id);
     441       277361 :     if (it == records.end ())
     442              :       {
     443        41581 :         CanonicalPathRecord *record = std::forward<FCreate> (f_create) ();
     444        41581 :         it = records.emplace (id, std::unique_ptr<CanonicalPathRecord> (record))
     445              :                .first;
     446              :       }
     447              : 
     448       277361 :     rust_assert (it->second->is_root ()
     449              :                  || &static_cast<CanonicalPathRecordWithParent &> (*it->second)
     450              :                         .get_parent ()
     451              :                       == current_record);
     452              : 
     453       277361 :     CanonicalPathRecord *stash = it->second.get ();
     454       277361 :     std::swap (stash, current_record);
     455              : 
     456       277357 :     std::forward<FCallback> (f_callback) ();
     457              : 
     458       277357 :     std::swap (stash, current_record);
     459       277357 :   }
     460              : 
     461              :   std::unordered_map<NodeId, std::unique_ptr<CanonicalPathRecord>> records;
     462              :   CanonicalPathRecord *current_record;
     463              : 
     464              :   const NameResolutionContext *nr_ctx;
     465              : };
     466              : 
     467              : // Now our resolver, which keeps track of all the `ForeverStack`s we could want
     468              : class NameResolutionContext
     469              : {
     470              : public:
     471              :   NameResolutionContext ();
     472              : 
     473              :   /**
     474              :    * Insert a new value in the current rib.
     475              :    *
     476              :    * @param name Name of the value to insert.
     477              :    * @param id This value's ID, e.g the function definition's node ID.
     478              :    * @param ns Namespace in which to insert the value.
     479              :    */
     480              :   tl::expected<NodeId, DuplicateNameError> insert (Identifier name, NodeId id,
     481              :                                                    Namespace ns);
     482              : 
     483              :   tl::expected<NodeId, DuplicateNameError>
     484              :   insert_variant (Identifier name, NodeId id, bool is_also_value);
     485              : 
     486              :   tl::expected<NodeId, DuplicateNameError>
     487              :   insert_shadowable (Identifier name, NodeId id, Namespace ns);
     488              : 
     489              :   tl::expected<NodeId, DuplicateNameError>
     490              :   insert_globbed (Identifier name, NodeId id, Namespace ns);
     491              : 
     492              :   /**
     493              :    * Run a lambda in a "scoped" context, meaning that a new `Rib` will be pushed
     494              :    * before executing the lambda and then popped. This is useful for all kinds
     495              :    * of scope in the language, such as a block expression or when entering a
     496              :    * function. This variant of the function enters a new scope in *all*
     497              :    * namespaces, while the second variant enters a scope in *one* namespace.
     498              :    *
     499              :    * @param rib_kind New `Rib` to create when entering this scope. A function
     500              :    *        `Rib`, or an item `Rib`... etc
     501              :    * @param scope_id node ID of the scope we are entering, e.g the block's
     502              :    *        `NodeId`.
     503              :    * @param lambda Function to run within that scope
     504              :    * @param path Optional path of the scope. This is useful for scopes which
     505              :    *        affect path resolution, such as modules. Defaults to an empty
     506              :    *        option.
     507              :    */
     508              :   // FIXME: Do we want to handle something in particular for expected within the
     509              :   // scoped lambda?
     510              :   void scoped (Rib::Kind rib_kind, NodeId scope_id,
     511              :                std::function<void (void)> lambda,
     512              :                tl::optional<Identifier> path = {});
     513              :   void scoped (Rib::Kind rib_kind, Namespace ns, NodeId scope_id,
     514              :                std::function<void (void)> lambda,
     515              :                tl::optional<Identifier> path = {});
     516              : 
     517              :   ForeverStack<Namespace::Values> values;
     518              :   ForeverStack<Namespace::Types> types;
     519              :   ForeverStack<Namespace::Macros> macros;
     520              :   ForeverStack<Namespace::Labels> labels;
     521              : 
     522              :   Analysis::Mappings &mappings;
     523              :   StackedContexts<BindingLayer> bindings;
     524              : 
     525              :   CanonicalPathCtx canonical_ctx;
     526              : 
     527              :   /**
     528              :    * The result type for a multi-namespace call to
     529              :    * NameResolutionContext::lookup()
     530              :    */
     531              :   struct NSLookup
     532              :   {
     533              :     NodeId id;
     534              :     Namespace ns;
     535              : 
     536       186409 :     NSLookup (NodeId id, Namespace ns) : id (id), ns (ns) {}
     537              :   };
     538              : 
     539              :   /**
     540              :    * These functions are mostly useful for the FinalizedNameResolutionContext
     541              :    * and used in later passes of the pipeline. They don't need to know as much
     542              :    * about a definition, hence why they don't use the NamespacedDefinition which
     543              :    * returns a Rib::Definition.
     544              :    */
     545              :   void map_usage (Usage usage, Definition definition, Namespace ns);
     546              :   tl::optional<NodeId> lookup (NodeId usage, Namespace ns) const;
     547              : 
     548              :   /**
     549              :    * The order of namespaces is important - if the usage resolves in the first
     550              :    * namespace, then it will be returned. Collisions are not guarded against and
     551              :    * should NOT happen. This is for looking up usages once name resolution is
     552              :    * done and we are in later stages of the pipeline.
     553              :    */
     554              :   tl::optional<NSLookup> lookup (NodeId usage, Namespace ns1,
     555              :                                  Namespace ns2) const;
     556              :   tl::optional<NSLookup> lookup (NodeId usage, Namespace ns1, Namespace ns2,
     557              :                                  Namespace ns3) const;
     558              : 
     559              :   Resolver::CanonicalPath to_canonical_path (NodeId id, Namespace ns) const
     560              :   {
     561              :     return canonical_ctx.get_path (id, ns);
     562              :   }
     563              : 
     564              :   /**
     565              :    * The return value when the namespace in which a definition was resolved
     566              :    * matters
     567              :    */
     568       504062 :   struct NamespacedDefinition
     569              :   {
     570        83159 :     explicit NamespacedDefinition (Rib::Definition definition, Namespace ns)
     571         2807 :       : definition (definition), ns (ns)
     572              :     {}
     573              : 
     574              :     static tl::optional<NamespacedDefinition>
     575        87063 :     Maybe (tl::optional<Rib::Definition> definition, Namespace ns)
     576              :     {
     577       254478 :       return definition.map ([ns] (Rib::Definition definition) {
     578        80352 :         return NamespacedDefinition (definition, ns);
     579        87063 :       });
     580              :     }
     581              : 
     582              :     Rib::Definition definition;
     583              :     Namespace ns;
     584              :   };
     585              : 
     586              :   tl::optional<NamespacedDefinition>
     587        87063 :   resolve_path (const ResolutionPath &path, ResolutionMode mode,
     588              :                 std::vector<Error> &collect_errors, Namespace ns)
     589              :   {
     590        87063 :     std::function<void (Usage, Definition, Namespace)> insert_segment_resolution
     591        87063 :       = [this] (Usage seg_id, Definition id, Namespace ns) {
     592        99519 :           map_usage (seg_id, id, ns);
     593        87063 :         };
     594              : 
     595        87063 :     tl::optional<NamespacedDefinition> resolved = tl::nullopt;
     596              : 
     597        87063 :     switch (ns)
     598              :       {
     599        25586 :       case Namespace::Values:
     600        51172 :         resolved = NamespacedDefinition::Maybe (
     601        51172 :           resolve_path (values, path, mode, insert_segment_resolution,
     602              :                         collect_errors),
     603        25586 :           ns);
     604        25586 :         break;
     605        59962 :       case Namespace::Types:
     606       119924 :         resolved = NamespacedDefinition::Maybe (
     607       119924 :           resolve_path (types, path, mode, insert_segment_resolution,
     608              :                         collect_errors),
     609        59962 :           ns);
     610        59962 :         break;
     611         1515 :       case Namespace::Macros:
     612         3030 :         resolved = NamespacedDefinition::Maybe (
     613         3030 :           resolve_path (macros, path, mode, insert_segment_resolution,
     614              :                         collect_errors),
     615         1515 :           ns);
     616         1515 :         break;
     617            0 :       case Namespace::Labels:
     618            0 :         resolved = NamespacedDefinition::Maybe (
     619            0 :           resolve_path (labels, path, mode, insert_segment_resolution,
     620              :                         collect_errors),
     621            0 :           ns);
     622            0 :         break;
     623            0 :       default:
     624            0 :         rust_unreachable ();
     625              :       }
     626              : 
     627              :     // If it fails, switch to std prelude resolution if it exists
     628        87063 :     if (prelude && !resolved)
     629              :       {
     630              :         // TODO: Factor this with the above
     631            0 :         switch (ns)
     632              :           {
     633            0 :           case Namespace::Values:
     634            0 :             return NamespacedDefinition::Maybe (
     635            0 :               resolve_path (values, path, mode, insert_segment_resolution,
     636            0 :                             collect_errors, *prelude),
     637            0 :               ns);
     638            0 :           case Namespace::Types:
     639            0 :             return NamespacedDefinition::Maybe (
     640            0 :               resolve_path (types, path, mode, insert_segment_resolution,
     641            0 :                             collect_errors, *prelude),
     642            0 :               ns);
     643            0 :           case Namespace::Macros:
     644            0 :             return NamespacedDefinition::Maybe (
     645            0 :               resolve_path (macros, path, mode, insert_segment_resolution,
     646            0 :                             collect_errors, *prelude),
     647            0 :               ns);
     648            0 :           case Namespace::Labels:
     649            0 :             return NamespacedDefinition::Maybe (
     650            0 :               resolve_path (labels, path, mode, insert_segment_resolution,
     651            0 :                             collect_errors, *prelude),
     652            0 :               ns);
     653              :           default:
     654              :             rust_unreachable ();
     655              :           }
     656              :       }
     657              : 
     658        87063 :     return resolved;
     659        87063 :   }
     660              : 
     661        85445 :   class ResolutionBuilder
     662              :   {
     663              :   public:
     664        85445 :     ResolutionBuilder (NameResolutionContext &ctx) : ctx (&ctx) {}
     665              : 
     666              :     template <typename S>
     667        85380 :     void set_path (const std::vector<S> &path_segments, NodeId node_id,
     668              :                    bool has_opening_scope)
     669              :     {
     670        85380 :       path = ResolutionPath (path_segments, node_id);
     671        85380 :       mode = ResolutionMode::Normal;
     672        85380 :       if (has_opening_scope)
     673              :         {
     674          739 :           if (get_rust_edition () == Edition::E2015)
     675          739 :             mode = ResolutionMode::FromRoot;
     676              :           else
     677            0 :             mode = ResolutionMode::FromExtern;
     678              :         }
     679        85380 :       has_path_set = true;
     680        85380 :     }
     681              : 
     682              :     template <typename S>
     683           65 :     void set_path (const std::vector<S> &path_segments, NodeId node_id,
     684              :                    ResolutionMode mode)
     685              :     {
     686           65 :       path = ResolutionPath (path_segments, node_id);
     687           65 :       this->mode = mode;
     688           65 :       has_path_set = true;
     689           65 :     }
     690              : 
     691              :     void set_path (const AST::SimplePath &path)
     692              :     {
     693              :       set_path (path.get_segments (), path.get_node_id (),
     694              :                 path.has_opening_scope_resolution ());
     695              :     }
     696              : 
     697              :     void set_path (const AST::PathInExpression &path)
     698              :     {
     699              :       set_path (path.get_segments (), path.get_node_id (),
     700              :                 path.opening_scope_resolution ());
     701              :     }
     702              : 
     703              :     void set_path (const AST::TypePath &path)
     704              :     {
     705              :       set_path (path.get_segments (), path.get_node_id (),
     706              :                 path.has_opening_scope_resolution_op ());
     707              :     }
     708              : 
     709              :     void set_mode (ResolutionMode mode) { this->mode = mode; }
     710              : 
     711       109885 :     void add_namespaces (Namespace ns) { namespace_list.push_back (ns); }
     712              : 
     713        24440 :     template <typename... Args> void add_namespaces (Namespace ns, Args... rest)
     714              :     {
     715        24440 :       add_namespaces (ns);
     716        24440 :       add_namespaces (rest...);
     717        24440 :     }
     718              : 
     719         3438 :     void set_collect_errors (tl::optional<std::vector<Error> &> collect_errors)
     720              :     {
     721         3438 :       this->collect_errors = collect_errors;
     722              :     }
     723              : 
     724        85445 :     tl::optional<NamespacedDefinition> resolve ()
     725              :     {
     726        85445 :       rust_assert (has_path_set);
     727              : 
     728        92156 :       for (auto ns : namespace_list)
     729              :         {
     730        87063 :           std::vector<Error> collect_errors_inner;
     731        87063 :           if (auto ret
     732        87063 :               = ctx->resolve_path (path, mode, collect_errors_inner, ns))
     733        87063 :             return ret;
     734         6711 :           if (!collect_errors_inner.empty ())
     735              :             {
     736           12 :               if (collect_errors.has_value ())
     737              :                 {
     738            6 :                   std::move (collect_errors_inner.begin (),
     739              :                              collect_errors_inner.end (),
     740              :                              std::back_inserter (collect_errors.value ()));
     741              :                 }
     742              :               else
     743              :                 {
     744           12 :                   for (auto &e : collect_errors_inner)
     745            6 :                     e.emit ();
     746              :                 }
     747              :             }
     748        87063 :         }
     749              : 
     750         5093 :       return tl::nullopt;
     751              :     }
     752              : 
     753              :   private:
     754              :     ResolutionPath path;
     755              :     ResolutionMode mode;
     756              :     bool has_path_set;
     757              : 
     758              :     std::vector<Namespace> namespace_list;
     759              : 
     760              :     tl::optional<std::vector<Error> &> collect_errors;
     761              : 
     762              :     NameResolutionContext *ctx;
     763              :   };
     764              : 
     765              :   template <typename S, typename... Args>
     766              :   tl::optional<NamespacedDefinition>
     767              :   resolve_path (const std::vector<S> &path_segments, ResolutionMode mode,
     768              :                 tl::optional<std::vector<Error> &> collect_errors,
     769              :                 Namespace ns_first, Args... ns_args)
     770              :   {
     771              :     ResolutionBuilder builder (*this);
     772              :     builder.set_path (path_segments, UNKNOWN_NODEID, mode);
     773              :     builder.add_namespaces (ns_first, ns_args...);
     774              :     builder.set_collect_errors (collect_errors);
     775              : 
     776              :     return builder.resolve ();
     777              :   }
     778              : 
     779              :   template <typename S, typename... Args>
     780              :   tl::optional<NamespacedDefinition>
     781         3438 :   resolve_path (const std::vector<S> &path_segments,
     782              :                 bool has_opening_scope_resolution,
     783              :                 tl::optional<std::vector<Error> &> collect_errors,
     784              :                 Namespace ns_first, Args... ns_args)
     785              :   {
     786         3438 :     ResolutionBuilder builder (*this);
     787         3438 :     builder.set_path (path_segments, UNKNOWN_NODEID,
     788              :                       has_opening_scope_resolution);
     789         3438 :     builder.add_namespaces (ns_first, ns_args...);
     790         3438 :     builder.set_collect_errors (collect_errors);
     791              : 
     792         3438 :     return builder.resolve ();
     793         3438 :   }
     794              : 
     795              :   template <typename S, typename... Args>
     796              :   tl::optional<NamespacedDefinition>
     797        81942 :   resolve_path (const std::vector<S> &path_segments,
     798              :                 bool has_opening_scope_resolution, Namespace ns_first,
     799              :                 Args... ns_args)
     800              :   {
     801        81942 :     ResolutionBuilder builder (*this);
     802        81942 :     builder.set_path (path_segments, UNKNOWN_NODEID,
     803              :                       has_opening_scope_resolution);
     804        81942 :     builder.add_namespaces (ns_first, ns_args...);
     805              : 
     806        81942 :     return builder.resolve ();
     807        81942 :   }
     808              : 
     809              :   template <typename S, typename... Args>
     810              :   tl::optional<NamespacedDefinition>
     811           65 :   resolve_path (const std::vector<S> &path_segments, ResolutionMode mode,
     812              :                 Namespace ns_first, Args... ns_args)
     813              :   {
     814           65 :     ResolutionBuilder builder (*this);
     815           65 :     builder.set_path (path_segments, UNKNOWN_NODEID, mode);
     816           65 :     builder.add_namespaces (ns_first, ns_args...);
     817              : 
     818           65 :     return builder.resolve ();
     819           65 :   }
     820              : 
     821              :   template <typename... Args>
     822         3937 :   tl::optional<NamespacedDefinition> resolve_path (const AST::SimplePath &path,
     823              :                                                    Args &&...args)
     824              :   {
     825         3438 :     return resolve_path (path.get_segments (),
     826         3937 :                          path.has_opening_scope_resolution (),
     827         3937 :                          std::forward<Args> (args)...);
     828              :   }
     829              : 
     830              :   template <typename... Args>
     831              :   tl::optional<NamespacedDefinition>
     832        25894 :   resolve_path (const AST::PathInExpression &path, Args &&...args)
     833              :   {
     834        25894 :     return resolve_path (path.get_segments (), path.opening_scope_resolution (),
     835        25894 :                          std::forward<Args> (args)...);
     836              :   }
     837              : 
     838              :   template <typename... Args>
     839        55549 :   tl::optional<NamespacedDefinition> resolve_path (const AST::TypePath &path,
     840              :                                                    Args &&...args)
     841              :   {
     842              :     return resolve_path (path.get_segments (),
     843        55549 :                          path.has_opening_scope_resolution_op (),
     844        55549 :                          std::forward<Args> (args)...);
     845              :   }
     846              : 
     847              :   // We disable this function for now as it causes regressions, but I think it
     848              :   // is important for a more proper final nameres context - need to investigate
     849              : #if 0
     850              :   /**
     851              :    * We've now collected every definition and import, and errored out when
     852              :    * necessary if multiple definitions are colliding. Do a final flattening of
     853              :    * the name resolution context to make it easier to digest for the late name
     854              :    * resolution and type-checker. This basically turns the `resolved_nodes`
     855              :    * map from a linked-list-like map to a regular, flat hashmap.
     856              :    *
     857              :    * FIXME: The documentation is wrong, this needs to also run after all
     858              :    * usages have been *resolved* so after Late as well!!!
     859              :    *
     860              :    * TODO: Should this return something like the FinalizedNameResolutionCtx?
     861              :    * Or set it up at least? And instead of mutating the `resolved_nodes` map,
     862              :    * create a new one for the FinalizedNameResolutionCtx?
     863              :    * Actually, since Late uses the NRCtx directly we should mutate this. Most
     864              :    * later passes don't look at this map. So let's go for side-effects in a
     865              :    * void function, yipee.
     866              :    */
     867              :   void flatten ();
     868              : #endif
     869              : 
     870              :   /* If declared with #[prelude_import], the current standard library module
     871              :    */
     872              :   tl::optional<NodeId> prelude;
     873              : 
     874              : private:
     875              :   template <Namespace N>
     876              :   bool
     877              :   should_search_prelude (const typename ForeverStack<N>::Node *current_node,
     878              :                          const typename ForeverStack<N>::SegIterator &iterator,
     879              :                          const std::vector<ResolutionPath::Segment> &segments);
     880              : 
     881              :   /**
     882              :    * Resolve a path to its definition
     883              :    *
     884              :    * // TODO: Add documentation for `segments`
     885              :    *
     886              :    * @return a valid option with the Definition if the path is present in the
     887              :    *         current map, an empty one otherwise.
     888              :    */
     889              :   template <Namespace N>
     890              :   tl::optional<Rib::Definition>
     891              :   resolve_path (ForeverStack<N> &stack, const ResolutionPath &path,
     892              :                 ResolutionMode mode,
     893              :                 std::function<void (Usage, Definition, Namespace)>
     894              :                   insert_segment_resolution,
     895              :                 std::vector<Error> &collect_errors);
     896              : 
     897              :   template <Namespace N>
     898              :   tl::optional<Rib::Definition>
     899              :   resolve_path (ForeverStack<N> &stack, const ResolutionPath &path,
     900              :                 ResolutionMode mode,
     901              :                 std::function<void (Usage, Definition, Namespace)>
     902              :                   insert_segment_resolution,
     903              :                 std::vector<Error> &collect_errors, NodeId starting_point_id);
     904              : 
     905              :   template <Namespace N>
     906              :   tl::optional<Rib::Definition> resolve_path (
     907              :     ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode,
     908              :     std::function<void (Usage, Definition, Namespace)>
     909              :       insert_segment_resolution,
     910              :     std::vector<Error> &collect_errors,
     911              :     std::reference_wrapper<typename ForeverStack<N>::Node> starting_point);
     912              : 
     913              :   template <Namespace N>
     914              :   tl::optional<typename ForeverStack<N>::Node &>
     915              :   resolve_segments (ForeverStack<N> &stack,
     916              :                     typename ForeverStack<N>::Node &starting_point,
     917              :                     const std::vector<ResolutionPath::Segment> &segments,
     918              :                     typename ForeverStack<N>::SegIterator iterator,
     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_final_segment (ForeverStack<N> &stack,
     926              :                          typename ForeverStack<N>::Node &final_node,
     927              :                          std::string &seg_name, bool is_lower_self);
     928              : };
     929              : 
     930              : } // namespace Resolver2_0
     931              : } // namespace Rust
     932              : 
     933              : #include "rust-name-resolution-context.hxx"
     934              : 
     935              : #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.