LCOV - code coverage report
Current view: top level - gcc/rust/resolve - rust-forever-stack.hxx (source / functions) Coverage Total Hit
Test: gcc.info Lines: 86.2 % 354 305
Test Date: 2025-11-22 14:42:49 Functions: 58.4 % 137 80
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : // Copyright (C) 2020-2025 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                 :             : #include "expected.h"
      20                 :             : #include "rust-ast.h"
      21                 :             : #include "rust-diagnostics.h"
      22                 :             : #include "rust-forever-stack.h"
      23                 :             : #include "rust-edition.h"
      24                 :             : #include "rust-rib.h"
      25                 :             : #include "rust-unwrap-segment.h"
      26                 :             : #include "optional.h"
      27                 :             : 
      28                 :             : namespace Rust {
      29                 :             : namespace Resolver2_0 {
      30                 :             : 
      31                 :             : template <Namespace N>
      32                 :             : bool
      33                 :    13123993 : ForeverStack<N>::Node::is_root () const
      34                 :             : {
      35                 :      273394 :   return !parent.has_value ();
      36                 :             : }
      37                 :             : 
      38                 :             : template <Namespace N>
      39                 :             : bool
      40                 :             : ForeverStack<N>::Node::is_prelude () const
      41                 :             : {
      42                 :             :   return rib.kind == Rib::Kind::Prelude;
      43                 :             : }
      44                 :             : 
      45                 :             : template <Namespace N>
      46                 :             : bool
      47                 :       17796 : ForeverStack<N>::Node::is_leaf () const
      48                 :             : {
      49                 :       17796 :   return children.empty ();
      50                 :             : }
      51                 :             : 
      52                 :             : template <Namespace N>
      53                 :             : void
      54                 :             : ForeverStack<N>::Node::insert_child (Link link, Node child)
      55                 :             : {
      56                 :             :   auto res = children.insert ({link, child});
      57                 :             : 
      58                 :             :   // Do we want to error if the child already exists? Probably not, right?
      59                 :             :   // That's kinda the point, isn't it. So this method always succeeds, right?
      60                 :             : }
      61                 :             : 
      62                 :             : template <Namespace N>
      63                 :             : void
      64                 :    12834429 : ForeverStack<N>::push (Rib::Kind rib_kind, NodeId id,
      65                 :             :                        tl::optional<Identifier> path)
      66                 :             : {
      67                 :    16663023 :   push_inner (rib_kind, Link (id, path));
      68                 :    12834429 : }
      69                 :             : 
      70                 :             : template <Namespace N>
      71                 :             : void
      72                 :    12834429 : ForeverStack<N>::push_inner (Rib rib, Link link)
      73                 :             : {
      74                 :    12834429 :   if (rib.kind == Rib::Kind::Prelude)
      75                 :             :     {
      76                 :             :       // If you push_inner into the prelude from outside the root, you will pop
      77                 :             :       // back into the root, which could screw up a traversal.
      78                 :       13347 :       rust_assert (&cursor_reference.get () == &root);
      79                 :             :       // Prelude doesn't have an access path
      80                 :       13347 :       rust_assert (!link.path);
      81                 :       13347 :       update_cursor (this->lang_prelude);
      82                 :       13347 :       return;
      83                 :             :     }
      84                 :             :   // If the link does not exist, we create it and emplace a new `Node` with the
      85                 :             :   // current node as its parent. `unordered_map::emplace` returns a pair with
      86                 :             :   // the iterator and a boolean. If the value already exists, the iterator
      87                 :             :   // points to it. Otherwise, it points to the newly emplaced value, so we can
      88                 :             :   // just update our cursor().
      89                 :    25642164 :   auto emplace = cursor ().children.emplace (
      90                 :    12821082 :     std::make_pair (link, Node (rib, link.id, cursor ())));
      91                 :             : 
      92                 :    12821082 :   auto it = emplace.first;
      93                 :    12821082 :   auto existed = !emplace.second;
      94                 :             : 
      95                 :    13211268 :   rust_debug ("inserting link: Link(%d [%s]): existed? %s", link.id,
      96                 :             :               link.path.has_value () ? link.path.value ().as_string ().c_str ()
      97                 :             :                                      : "<anon>",
      98                 :             :               existed ? "yes" : "no");
      99                 :             : 
     100                 :             :   // We update the cursor
     101                 :    12821082 :   update_cursor (it->second);
     102                 :             : }
     103                 :             : 
     104                 :             : template <Namespace N>
     105                 :             : void
     106                 :    12834423 : ForeverStack<N>::pop ()
     107                 :             : {
     108                 :    12834423 :   rust_assert (!cursor ().is_root ());
     109                 :             : 
     110                 :    12834423 :   rust_debug ("popping link");
     111                 :             : 
     112                 :    15659650 :   for (const auto &kv : cursor ().rib.get_values ())
     113                 :     2825227 :     rust_debug ("current_rib: k: %s, v: %s", kv.first.c_str (),
     114                 :             :                 kv.second.to_string ().c_str ());
     115                 :             : 
     116                 :    12834423 :   if (cursor ().parent.has_value ())
     117                 :   182067283 :     for (const auto &kv : cursor ().parent.value ().rib.get_values ())
     118                 :   169232860 :       rust_debug ("new cursor: k: %s, v: %s", kv.first.c_str (),
     119                 :             :                   kv.second.to_string ().c_str ());
     120                 :             : 
     121                 :    12834423 :   update_cursor (cursor ().parent.value ());
     122                 :    12834423 : }
     123                 :             : 
     124                 :             : static tl::expected<NodeId, DuplicateNameError>
     125                 :     1593161 : insert_inner (Rib &rib, std::string name, Rib::Definition definition)
     126                 :             : {
     127                 :     3186322 :   return rib.insert (name, definition);
     128                 :             : }
     129                 :             : 
     130                 :             : template <Namespace N>
     131                 :             : tl::expected<NodeId, DuplicateNameError>
     132                 :     1373315 : ForeverStack<N>::insert (Identifier name, NodeId node)
     133                 :             : {
     134                 :     1373315 :   auto &innermost_rib = peek ();
     135                 :             : 
     136                 :             :   // So what do we do here - if the Rib has already been pushed in an earlier
     137                 :             :   // pass, we might end up in a situation where it is okay to re-add new names.
     138                 :             :   // Do we just ignore that here? Do we keep track of if the Rib is new or not?
     139                 :             :   // should our cursor have info on the current node like "is it newly pushed"?
     140                 :     1373315 :   return insert_inner (innermost_rib, name.as_string (),
     141                 :     2746630 :                        Rib::Definition::NonShadowable (node));
     142                 :             : }
     143                 :             : 
     144                 :             : template <Namespace N>
     145                 :             : tl::expected<NodeId, DuplicateNameError>
     146                 :       24168 : ForeverStack<N>::insert_shadowable (Identifier name, NodeId node)
     147                 :             : {
     148                 :       24168 :   auto &innermost_rib = peek ();
     149                 :             : 
     150                 :       24168 :   return insert_inner (innermost_rib, name.as_string (),
     151                 :       48336 :                        Rib::Definition::Shadowable (node));
     152                 :             : }
     153                 :             : 
     154                 :             : template <Namespace N>
     155                 :             : tl::expected<NodeId, DuplicateNameError>
     156                 :      185011 : ForeverStack<N>::insert_globbed (Identifier name, NodeId node)
     157                 :             : {
     158                 :      185011 :   auto &innermost_rib = peek ();
     159                 :             : 
     160                 :      185011 :   return insert_inner (innermost_rib, name.as_string (),
     161                 :      370022 :                        Rib::Definition::Globbed (node));
     162                 :             : }
     163                 :             : 
     164                 :             : template <Namespace N>
     165                 :             : tl::expected<NodeId, DuplicateNameError>
     166                 :        1271 : ForeverStack<N>::insert_at_root (Identifier name, NodeId node)
     167                 :             : {
     168                 :        1271 :   auto &root_rib = root.rib;
     169                 :             : 
     170                 :             :   // inserting in the root of the crate is never a shadowing operation, even for
     171                 :             :   // macros
     172                 :        1271 :   return insert_inner (root_rib, name.as_string (),
     173                 :        2542 :                        Rib::Definition::NonShadowable (node));
     174                 :             : }
     175                 :             : 
     176                 :             : // Specialization for Macros and Labels - where we are allowed to shadow
     177                 :             : // existing definitions
     178                 :             : template <>
     179                 :             : inline tl::expected<NodeId, DuplicateNameError>
     180                 :        2939 : ForeverStack<Namespace::Macros>::insert (Identifier name, NodeId node)
     181                 :             : {
     182                 :        2939 :   return insert_inner (peek (), name.as_string (),
     183                 :        5878 :                        Rib::Definition::Shadowable (node));
     184                 :             : }
     185                 :             : 
     186                 :             : template <>
     187                 :             : inline tl::expected<NodeId, DuplicateNameError>
     188                 :          55 : ForeverStack<Namespace::Labels>::insert (Identifier name, NodeId node)
     189                 :             : {
     190                 :          55 :   return insert_inner (peek (), name.as_string (),
     191                 :         110 :                        Rib::Definition::Shadowable (node));
     192                 :             : }
     193                 :             : 
     194                 :             : template <>
     195                 :             : inline tl::expected<NodeId, DuplicateNameError>
     196                 :        6402 : ForeverStack<Namespace::Types>::insert_variant (Identifier name, NodeId node)
     197                 :             : {
     198                 :        6402 :   return insert_inner (peek (), name.as_string (),
     199                 :       12804 :                        Rib::Definition::NonShadowable (node, true));
     200                 :             : }
     201                 :             : 
     202                 :             : template <Namespace N>
     203                 :             : Rib &
     204                 :     1673219 : ForeverStack<N>::peek ()
     205                 :             : {
     206                 :     1673219 :   return cursor ().rib;
     207                 :             : }
     208                 :             : 
     209                 :             : template <Namespace N>
     210                 :             : const Rib &
     211                 :             : ForeverStack<N>::peek () const
     212                 :             : {
     213                 :             :   return cursor ().rib;
     214                 :             : }
     215                 :             : 
     216                 :             : template <Namespace N>
     217                 :             : void
     218                 :          22 : ForeverStack<N>::reverse_iter (std::function<KeepGoing (Node &)> lambda)
     219                 :             : {
     220                 :          44 :   return reverse_iter (cursor (), lambda);
     221                 :             : }
     222                 :             : 
     223                 :             : template <Namespace N>
     224                 :             : void
     225                 :             : ForeverStack<N>::reverse_iter (
     226                 :             :   std::function<KeepGoing (const Node &)> lambda) const
     227                 :             : {
     228                 :             :   return reverse_iter (cursor (), lambda);
     229                 :             : }
     230                 :             : 
     231                 :             : template <Namespace N>
     232                 :             : void
     233                 :      156189 : ForeverStack<N>::reverse_iter (Node &start,
     234                 :             :                                std::function<KeepGoing (Node &)> lambda)
     235                 :             : {
     236                 :      156189 :   auto *tmp = &start;
     237                 :             : 
     238                 :      179498 :   while (true)
     239                 :             :     {
     240                 :      335687 :       auto keep_going = lambda (*tmp);
     241                 :      335687 :       if (keep_going == KeepGoing::No)
     242                 :             :         return;
     243                 :             : 
     244                 :      210538 :       if (tmp->is_root ())
     245                 :             :         return;
     246                 :             : 
     247                 :      179498 :       tmp = &tmp->parent.value ();
     248                 :             :     }
     249                 :             : }
     250                 :             : 
     251                 :             : template <Namespace N>
     252                 :             : void
     253                 :             : ForeverStack<N>::reverse_iter (
     254                 :             :   const Node &start, std::function<KeepGoing (const Node &)> lambda) const
     255                 :             : {
     256                 :             :   auto *tmp = &start;
     257                 :             : 
     258                 :             :   while (true)
     259                 :             :     {
     260                 :             :       auto keep_going = lambda (*tmp);
     261                 :             :       if (keep_going == KeepGoing::No)
     262                 :             :         return;
     263                 :             : 
     264                 :             :       if (tmp->is_root ())
     265                 :             :         return;
     266                 :             : 
     267                 :             :       tmp = &tmp->parent.value ();
     268                 :             :     }
     269                 :             : }
     270                 :             : 
     271                 :             : template <Namespace N>
     272                 :             : typename ForeverStack<N>::Node &
     273                 :    66074836 : ForeverStack<N>::cursor ()
     274                 :             : {
     275                 :    66045568 :   return cursor_reference;
     276                 :             : }
     277                 :             : 
     278                 :             : template <Namespace N>
     279                 :             : const typename ForeverStack<N>::Node &
     280                 :             : ForeverStack<N>::cursor () const
     281                 :             : {
     282                 :             :   return cursor_reference;
     283                 :             : }
     284                 :             : 
     285                 :             : template <Namespace N>
     286                 :             : void
     287                 :    12834429 : ForeverStack<N>::update_cursor (Node &new_cursor)
     288                 :             : {
     289                 :    12834429 :   cursor_reference = new_cursor;
     290                 :             : }
     291                 :             : 
     292                 :             : template <Namespace N>
     293                 :             : tl::optional<Rib::Definition>
     294                 :      104783 : ForeverStack<N>::get (Node &start, const Identifier &name)
     295                 :             : {
     296                 :      104783 :   tl::optional<Rib::Definition> resolved_definition = tl::nullopt;
     297                 :             : 
     298                 :             :   // TODO: Can we improve the API? have `reverse_iter` return an optional?
     299                 :      388702 :   reverse_iter (start, [&resolved_definition, &name] (Node &current) {
     300                 :             :     // we can't reference associated types/functions like this
     301                 :      283919 :     if (current.rib.kind == Rib::Kind::TraitOrImpl)
     302                 :             :       return KeepGoing::Yes;
     303                 :             : 
     304                 :      261596 :     auto candidate = current.rib.get (name.as_string ());
     305                 :             : 
     306                 :      261596 :     return candidate.map_or (
     307                 :      596943 :       [&resolved_definition] (Rib::Definition found) {
     308                 :       73751 :         if (found.is_variant ())
     309                 :             :           return KeepGoing::Yes;
     310                 :             :         // for most namespaces, we do not need to care about various ribs -
     311                 :             :         // they are available from all contexts if defined in the current
     312                 :             :         // scope, or an outermore one. so if we do have a candidate, we can
     313                 :             :         // return it directly and stop iterating
     314                 :       73748 :         resolved_definition = found;
     315                 :             : 
     316                 :       73748 :         return KeepGoing::No;
     317                 :             :       },
     318                 :             :       // if there was no candidate, we keep iterating
     319                 :      261596 :       KeepGoing::Yes);
     320                 :      261596 :   });
     321                 :             : 
     322                 :      104783 :   return resolved_definition;
     323                 :             : }
     324                 :             : 
     325                 :             : template <Namespace N>
     326                 :             : tl::optional<Rib::Definition>
     327                 :       29268 : ForeverStack<N>::get (const Identifier &name)
     328                 :             : {
     329                 :       29268 :   return get (cursor (), name);
     330                 :             : }
     331                 :             : 
     332                 :             : template <Namespace N>
     333                 :             : tl::optional<Rib::Definition>
     334                 :           8 : ForeverStack<N>::get_lang_prelude (const Identifier &name)
     335                 :             : {
     336                 :           8 :   return lang_prelude.rib.get (name.as_string ());
     337                 :             : }
     338                 :             : 
     339                 :             : template <Namespace N>
     340                 :             : tl::optional<Rib::Definition>
     341                 :      114089 : ForeverStack<N>::get_lang_prelude (const std::string &name)
     342                 :             : {
     343                 :      114089 :   return lang_prelude.rib.get (name);
     344                 :             : }
     345                 :             : 
     346                 :             : template <>
     347                 :          22 : tl::optional<Rib::Definition> inline ForeverStack<Namespace::Labels>::get (
     348                 :             :   const Identifier &name)
     349                 :             : {
     350                 :          22 :   tl::optional<Rib::Definition> resolved_definition = tl::nullopt;
     351                 :             : 
     352                 :          22 :   reverse_iter ([&resolved_definition, &name] (Node &current) {
     353                 :             :     // looking up for labels cannot go through function ribs
     354                 :             :     // TODO: What other ribs?
     355                 :          22 :     if (current.rib.kind == Rib::Kind::Function)
     356                 :             :       return KeepGoing::No;
     357                 :             : 
     358                 :          22 :     auto candidate = current.rib.get (name.as_string ());
     359                 :             : 
     360                 :             :     // FIXME: Factor this in a function with the generic `get`
     361                 :          22 :     return candidate.map_or (
     362                 :          61 :       [&resolved_definition] (Rib::Definition found) {
     363                 :          17 :         resolved_definition = found;
     364                 :             : 
     365                 :          17 :         return KeepGoing::No;
     366                 :             :       },
     367                 :          22 :       KeepGoing::Yes);
     368                 :          22 :   });
     369                 :             : 
     370                 :          22 :   return resolved_definition;
     371                 :             : }
     372                 :             : 
     373                 :             : /* Check if an iterator points to the last element */
     374                 :             : template <typename I, typename C>
     375                 :             : static bool
     376                 :      414622 : is_last (const I &iterator, const C &collection)
     377                 :             : {
     378                 :      414622 :   return iterator + 1 == collection.end ();
     379                 :             : }
     380                 :             : 
     381                 :             : /* Check if an iterator points to the start of the collection */
     382                 :             : template <typename I, typename C>
     383                 :             : static bool
     384                 :      217838 : is_start (const I &iterator, const C &collection)
     385                 :             : {
     386                 :      361627 :   return iterator == collection.begin ();
     387                 :             : }
     388                 :             : 
     389                 :             : template <Namespace N>
     390                 :             : typename ForeverStack<N>::Node &
     391                 :       51384 : ForeverStack<N>::find_closest_module (Node &starting_point)
     392                 :             : {
     393                 :       51384 :   auto *closest_module = &starting_point;
     394                 :             : 
     395                 :      103130 :   reverse_iter (starting_point, [&closest_module] (Node &current) {
     396                 :       51746 :     if (current.rib.kind == Rib::Kind::Module || current.is_root ())
     397                 :             :       {
     398                 :       51384 :         closest_module = &current;
     399                 :       51384 :         return KeepGoing::No;
     400                 :             :       }
     401                 :             : 
     402                 :             :     return KeepGoing::Yes;
     403                 :             :   });
     404                 :             : 
     405                 :       51384 :   return *closest_module;
     406                 :             : }
     407                 :             : 
     408                 :             : /* If a the given condition is met, emit an error about misused leading path
     409                 :             :  * segments */
     410                 :             : template <typename S>
     411                 :             : static inline bool
     412                 :      271791 : check_leading_kw_at_start (std::vector<Error> &collect_errors, const S &segment,
     413                 :             :                            bool condition)
     414                 :             : {
     415                 :      271791 :   if (condition)
     416                 :          10 :     collect_errors.emplace_back (
     417                 :          10 :       segment.get_locus (), ErrorCode::E0433,
     418                 :             :       "%qs in paths can only be used in start position",
     419                 :          20 :       segment.as_string ().c_str ());
     420                 :             : 
     421                 :      271791 :   return condition;
     422                 :             : }
     423                 :             : 
     424                 :             : // we first need to handle the "starting" segments - `super`, `self` or
     425                 :             : // `crate`. we don't need to do anything for `self` and can just skip it. for
     426                 :             : // `crate`, we need to go back to the root of the current stack. for each
     427                 :             : // `super` segment, we go back to the cursor's parent until we reach the
     428                 :             : // correct one or the root.
     429                 :             : template <Namespace N>
     430                 :             : template <typename S>
     431                 :             : tl::optional<typename std::vector<S>::const_iterator>
     432                 :      137648 : ForeverStack<N>::find_starting_point (
     433                 :             :   const std::vector<S> &segments, std::reference_wrapper<Node> &starting_point,
     434                 :             :   std::function<void (const S &, NodeId)> insert_segment_resolution,
     435                 :             :   std::vector<Error> &collect_errors)
     436                 :             : {
     437                 :      137648 :   auto iterator = segments.begin ();
     438                 :             : 
     439                 :      153647 :   for (; !is_last (iterator, segments); iterator++)
     440                 :             :     {
     441                 :      143789 :       auto &outer_seg = *iterator;
     442                 :             : 
     443                 :      143789 :       if (unwrap_segment_get_lang_item (outer_seg).has_value ())
     444                 :             :         break;
     445                 :             : 
     446                 :      143789 :       auto &seg = unwrap_type_segment (outer_seg);
     447                 :      143789 :       bool is_self_or_crate
     448                 :      143789 :         = seg.is_crate_path_seg () || seg.is_lower_self_seg ();
     449                 :             : 
     450                 :             :       // if we're after the first path segment and meet `self` or `crate`, it's
     451                 :             :       // an error - we should only be seeing `super` keywords at this point
     452                 :      143789 :       if (check_leading_kw_at_start (collect_errors, seg,
     453                 :      143789 :                                      !is_start (iterator, segments)
     454                 :      143789 :                                        && is_self_or_crate))
     455                 :           1 :         return tl::nullopt;
     456                 :             : 
     457                 :      143788 :       if (seg.is_crate_path_seg ())
     458                 :             :         {
     459                 :       73940 :           starting_point = root;
     460                 :       73940 :           insert_segment_resolution (outer_seg, starting_point.get ().id);
     461                 :       73940 :           iterator++;
     462                 :             :           break;
     463                 :             :         }
     464                 :       69848 :       if (seg.is_lower_self_seg ())
     465                 :             :         {
     466                 :             :           // insert segment resolution and exit
     467                 :       18993 :           starting_point = find_closest_module (starting_point);
     468                 :       18993 :           insert_segment_resolution (outer_seg, starting_point.get ().id);
     469                 :       18993 :           iterator++;
     470                 :             :           break;
     471                 :             :         }
     472                 :       66854 :       if (seg.is_super_path_seg ())
     473                 :             :         {
     474                 :       16000 :           starting_point = find_closest_module (starting_point);
     475                 :       16000 :           if (starting_point.get ().is_root ())
     476                 :             :             {
     477                 :           1 :               collect_errors.emplace_back (
     478                 :           1 :                 seg.get_locus (), ErrorCode::E0433,
     479                 :             :                 "too many leading %<super%> keywords");
     480                 :           1 :               return tl::nullopt;
     481                 :             :             }
     482                 :             : 
     483                 :       15999 :           starting_point
     484                 :       15999 :             = find_closest_module (starting_point.get ().parent.value ());
     485                 :             : 
     486                 :       15999 :           insert_segment_resolution (outer_seg, starting_point.get ().id);
     487                 :             :           continue;
     488                 :             :         }
     489                 :             : 
     490                 :             :       // now we've gone through the allowed `crate`, `self` or leading `super`
     491                 :             :       // segments. we can start resolving each segment itself.
     492                 :             :       // if we do see another leading segment, then we can error out.
     493                 :             :       break;
     494                 :             :     }
     495                 :             : 
     496                 :      137646 :   return iterator;
     497                 :             : }
     498                 :             : 
     499                 :             : template <Namespace N>
     500                 :             : template <typename S>
     501                 :             : tl::optional<typename ForeverStack<N>::Node &>
     502                 :      137646 : ForeverStack<N>::resolve_segments (
     503                 :             :   Node &starting_point, const std::vector<S> &segments,
     504                 :             :   typename std::vector<S>::const_iterator iterator,
     505                 :             :   std::function<void (const S &, NodeId)> insert_segment_resolution,
     506                 :             :   std::vector<Error> &collect_errors)
     507                 :             : {
     508                 :      137646 :   Node *current_node = &starting_point;
     509                 :      265648 :   for (; !is_last (iterator, segments); iterator++)
     510                 :             :     {
     511                 :      128002 :       auto &outer_seg = *iterator;
     512                 :             : 
     513                 :      128002 :       if (auto lang_item = unwrap_segment_get_lang_item (outer_seg))
     514                 :             :         {
     515                 :           0 :           NodeId seg_id = Analysis::Mappings::get ().get_lang_item_node (
     516                 :           0 :             lang_item.value ());
     517                 :           0 :           current_node = &dfs_node (root, seg_id).value ();
     518                 :             : 
     519                 :           0 :           insert_segment_resolution (outer_seg, seg_id);
     520                 :           0 :           continue;
     521                 :           0 :         }
     522                 :             : 
     523                 :      128002 :       auto &seg = unwrap_type_segment (outer_seg);
     524                 :      128002 :       std::string str = seg.as_string ();
     525                 :      128002 :       rust_debug ("[ARTHUR]: resolving segment part: %s", str.c_str ());
     526                 :             : 
     527                 :             :       // check that we don't encounter *any* leading keywords afterwards
     528                 :      128002 :       if (check_leading_kw_at_start (collect_errors, seg,
     529                 :      128002 :                                      seg.is_crate_path_seg ()
     530                 :      128002 :                                        || seg.is_super_path_seg ()
     531                 :      255997 :                                        || seg.is_lower_self_seg ()))
     532                 :           9 :         return tl::nullopt;
     533                 :             : 
     534                 :      127993 :       tl::optional<std::reference_wrapper<Node>> child = tl::nullopt;
     535                 :             : 
     536                 :             :       /*
     537                 :             :        * On every iteration this loop either
     538                 :             :        *
     539                 :             :        * 1. terminates
     540                 :             :        *
     541                 :             :        * 2. decreases the depth of the node pointed to by current_node until
     542                 :             :        *    current_node reaches the root
     543                 :             :        *
     544                 :             :        * 3. If the root node is reached, and we were not able to resolve the
     545                 :             :        *    segment, we search the prelude rib for the segment, by setting
     546                 :             :        *    current_node to point to the prelude, and toggling the
     547                 :             :        *    searched_prelude boolean to true. If current_node is the prelude
     548                 :             :        *    rib, and searched_prelude is true, we will exit.
     549                 :             :        *
     550                 :             :        * This ensures termination.
     551                 :             :        *
     552                 :             :        */
     553                 :      127993 :       bool searched_prelude = false;
     554                 :       47356 :       while (true)
     555                 :             :         {
     556                 :      185519 :           if (is_start (iterator, segments)
     557                 :      176825 :               && current_node->rib.kind == Rib::Kind::TraitOrImpl)
     558                 :             :             {
     559                 :             :               // we can't reference associated types/functions like this
     560                 :        8694 :               current_node = &current_node->parent.value ();
     561                 :       11068 :               continue;
     562                 :             :             }
     563                 :             : 
     564                 :             :           // may set the value of child
     565                 :     2468919 :           for (auto &kv : current_node->children)
     566                 :             :             {
     567                 :     2421563 :               auto &link = kv.first;
     568                 :             : 
     569                 :     4843126 :               if (link.path.map_or (
     570                 :     6818079 :                     [&str] (Identifier path) {
     571                 :     1974953 :                       auto &path_str = path.as_string ();
     572                 :     1974953 :                       return str == path_str;
     573                 :             :                     },
     574                 :     2421563 :                     false))
     575                 :             :                 {
     576                 :      288906 :                   child = kv.second;
     577                 :             :                   break;
     578                 :             :                 }
     579                 :             :             }
     580                 :             : 
     581                 :      168131 :           if (child.has_value ())
     582                 :             :             {
     583                 :             :               break;
     584                 :             :             }
     585                 :             : 
     586                 :       92181 :           auto rib_lookup = current_node->rib.get (seg.as_string ());
     587                 :       47356 :           if (rib_lookup && !rib_lookup->is_ambiguous ())
     588                 :             :             {
     589                 :        3969 :               if (Analysis::Mappings::get ()
     590                 :        3969 :                     .lookup_glob_container (rib_lookup->get_node_id ())
     591                 :        3969 :                     .has_value ())
     592                 :             :                 {
     593                 :        2554 :                   child = dfs_node (root, rib_lookup->get_node_id ()).value ();
     594                 :             :                   break;
     595                 :             :                 }
     596                 :             :               else
     597                 :             :                 {
     598                 :        1415 :                   insert_segment_resolution (outer_seg,
     599                 :             :                                              rib_lookup->get_node_id ());
     600                 :        1415 :                   return tl::nullopt;
     601                 :             :                 }
     602                 :             :             }
     603                 :             : 
     604                 :       43387 :           if (current_node->is_root () && !searched_prelude)
     605                 :             :             {
     606                 :        2374 :               searched_prelude = true;
     607                 :        2374 :               current_node = &lang_prelude;
     608                 :             :               continue;
     609                 :             :             }
     610                 :             : 
     611                 :       41013 :           if (!is_start (iterator, segments)
     612                 :       41008 :               || current_node->rib.kind == Rib::Kind::Module
     613                 :       81148 :               || current_node->is_prelude ())
     614                 :             :             {
     615                 :        3249 :               return tl::nullopt;
     616                 :             :             }
     617                 :             : 
     618                 :       37764 :           current_node = &current_node->parent.value ();
     619                 :             :         }
     620                 :             : 
     621                 :             :       // if child didn't point to a value
     622                 :             :       // the while loop above would have returned or kept looping
     623                 :      123329 :       current_node = &child->get ();
     624                 :      123329 :       insert_segment_resolution (outer_seg, current_node->id);
     625                 :             :     }
     626                 :             : 
     627                 :      132973 :   return *current_node;
     628                 :             : }
     629                 :             : 
     630                 :             : template <>
     631                 :             : inline tl::optional<Rib::Definition>
     632                 :       48261 : ForeverStack<Namespace::Types>::resolve_final_segment (Node &final_node,
     633                 :             :                                                        std::string &seg_name,
     634                 :             :                                                        bool is_lower_self)
     635                 :             : {
     636                 :       48261 :   if (is_lower_self)
     637                 :        1639 :     return Rib::Definition::NonShadowable (final_node.id);
     638                 :             :   else
     639                 :       46622 :     return final_node.rib.get (seg_name);
     640                 :             : }
     641                 :             : 
     642                 :             : template <Namespace N>
     643                 :             : tl::optional<Rib::Definition>
     644                 :       84712 : ForeverStack<N>::resolve_final_segment (Node &final_node, std::string &seg_name,
     645                 :             :                                         bool is_lower_self)
     646                 :             : {
     647                 :       84712 :   return final_node.rib.get (seg_name);
     648                 :             : }
     649                 :             : 
     650                 :             : template <Namespace N>
     651                 :             : template <typename S>
     652                 :             : tl::optional<Rib::Definition>
     653                 :      213553 : ForeverStack<N>::resolve_path (
     654                 :             :   const std::vector<S> &segments, ResolutionMode mode,
     655                 :             :   std::function<void (const S &, NodeId)> insert_segment_resolution,
     656                 :             :   std::vector<Error> &collect_errors)
     657                 :             : {
     658                 :      213553 :   rust_assert (!segments.empty ());
     659                 :             : 
     660                 :      213553 :   std::reference_wrapper<Node> starting_point = cursor ();
     661                 :      213553 :   switch (mode)
     662                 :             :     {
     663                 :             :     case ResolutionMode::Normal:
     664                 :             :       break; // default
     665                 :        1036 :     case ResolutionMode::FromRoot:
     666                 :        1036 :       starting_point = root;
     667                 :        1036 :       break;
     668                 :           0 :     case ResolutionMode::FromExtern:
     669                 :           0 :       starting_point = extern_prelude;
     670                 :           0 :       break;
     671                 :           0 :     default:
     672                 :           0 :       rust_unreachable ();
     673                 :             :     }
     674                 :             : 
     675                 :             :   // if there's only one segment, we just use `get`
     676                 :      213553 :   if (segments.size () == 1)
     677                 :             :     {
     678                 :       75905 :       auto &outer_seg = segments.front ();
     679                 :       75905 :       if (auto lang_item = unwrap_segment_get_lang_item (outer_seg))
     680                 :             :         {
     681                 :         780 :           NodeId seg_id = Analysis::Mappings::get ().get_lang_item_node (
     682                 :         390 :             lang_item.value ());
     683                 :             : 
     684                 :         390 :           insert_segment_resolution (outer_seg, seg_id);
     685                 :             :           // TODO: does NonShadowable matter?
     686                 :         390 :           return Rib::Definition::NonShadowable (seg_id);
     687                 :             :         }
     688                 :             : 
     689                 :       75515 :       auto &seg = unwrap_type_segment (outer_seg);
     690                 :             : 
     691                 :       75515 :       tl::optional<Rib::Definition> res
     692                 :      226545 :         = get (starting_point.get (), seg.as_string ());
     693                 :             : 
     694                 :       75515 :       if (!res)
     695                 :       53095 :         res = get_lang_prelude (seg.as_string ());
     696                 :             : 
     697                 :       54666 :       if (N == Namespace::Types && !res)
     698                 :             :         {
     699                 :         269 :           if (seg.is_crate_path_seg ())
     700                 :             :             {
     701                 :          53 :               insert_segment_resolution (outer_seg, root.id);
     702                 :             :               // TODO: does NonShadowable matter?
     703                 :          53 :               return Rib::Definition::NonShadowable (root.id);
     704                 :             :             }
     705                 :         216 :           else if (seg.is_lower_self_seg ())
     706                 :             :             {
     707                 :           5 :               NodeId id = find_closest_module (starting_point.get ()).id;
     708                 :           5 :               insert_segment_resolution (outer_seg, id);
     709                 :             :               // TODO: does NonShadowable matter?
     710                 :           5 :               return Rib::Definition::NonShadowable (id);
     711                 :             :             }
     712                 :         211 :           else if (seg.is_super_path_seg ())
     713                 :             :             {
     714                 :             :               Node &closest_module
     715                 :         176 :                 = find_closest_module (starting_point.get ());
     716                 :         176 :               if (closest_module.is_root ())
     717                 :             :                 {
     718                 :           0 :                   rust_error_at (seg.get_locus (), ErrorCode::E0433,
     719                 :             :                                  "too many leading %<super%> keywords");
     720                 :           0 :                   return tl::nullopt;
     721                 :             :                 }
     722                 :             : 
     723                 :         176 :               NodeId id
     724                 :         176 :                 = find_closest_module (closest_module.parent.value ()).id;
     725                 :         176 :               insert_segment_resolution (outer_seg, id);
     726                 :             :               // TODO: does NonShadowable matter?
     727                 :         176 :               return Rib::Definition::NonShadowable (id);
     728                 :             :             }
     729                 :             :           else
     730                 :             :             {
     731                 :             :               // HACK: check for a module after we check the language prelude
     732                 :         150 :               for (auto &kv :
     733                 :          35 :                    find_closest_module (starting_point.get ()).children)
     734                 :             :                 {
     735                 :         124 :                   auto &link = kv.first;
     736                 :             : 
     737                 :         248 :                   if (link.path.map_or (
     738                 :         345 :                         [&seg] (Identifier path) {
     739                 :          97 :                           auto &path_str = path.as_string ();
     740                 :         180 :                           return path_str == seg.as_string ();
     741                 :             :                         },
     742                 :         124 :                         false))
     743                 :             :                     {
     744                 :           9 :                       insert_segment_resolution (outer_seg, kv.second.id);
     745                 :           9 :                       return Rib::Definition::NonShadowable (kv.second.id);
     746                 :             :                     }
     747                 :             :                 }
     748                 :             :             }
     749                 :             :         }
     750                 :             : 
     751                 :       75272 :       if (res && !res->is_ambiguous ())
     752                 :       73285 :         insert_segment_resolution (outer_seg, res->get_node_id ());
     753                 :       75272 :       return res;
     754                 :       75515 :     }
     755                 :             : 
     756                 :      137648 :   return find_starting_point (segments, starting_point,
     757                 :             :                               insert_segment_resolution, collect_errors)
     758                 :      137648 :     .and_then (
     759                 :      275294 :       [this, &segments, &starting_point, &insert_segment_resolution,
     760                 :             :        &collect_errors] (typename std::vector<S>::const_iterator iterator) {
     761                 :      137646 :         return resolve_segments (starting_point.get (), segments, iterator,
     762                 :      137646 :                                  insert_segment_resolution, collect_errors);
     763                 :             :       })
     764                 :      270621 :     .and_then ([this, &segments, &insert_segment_resolution] (
     765                 :             :                  Node &final_node) -> tl::optional<Rib::Definition> {
     766                 :             :       // leave resolution within impl blocks to type checker
     767                 :      132973 :       if (final_node.rib.kind == Rib::Kind::TraitOrImpl)
     768                 :           0 :         return tl::nullopt;
     769                 :             : 
     770                 :      132973 :       auto &seg = unwrap_type_segment (segments.back ());
     771                 :      122525 :       std::string seg_name = seg.as_string ();
     772                 :             : 
     773                 :             :       // assuming this can't be a lang item segment
     774                 :      132973 :       tl::optional<Rib::Definition> res
     775                 :             :         = resolve_final_segment (final_node, seg_name,
     776                 :      132973 :                                  seg.is_lower_self_seg ());
     777                 :             :       // Ok we didn't find it in the rib, Lets try the prelude...
     778                 :      132973 :       if (!res)
     779                 :       86742 :         res = get_lang_prelude (seg_name);
     780                 :             : 
     781                 :       48261 :       if (N == Namespace::Types && !res)
     782                 :             :         {
     783                 :             :           // HACK: check for a module after we check the language prelude
     784                 :      400020 :           for (auto &kv : final_node.children)
     785                 :             :             {
     786                 :      397363 :               auto &link = kv.first;
     787                 :             : 
     788                 :      794726 :               if (link.path.map_or (
     789                 :      367804 :                     [&seg_name] (Identifier path) {
     790                 :      367804 :                       auto &path_str = path.as_string ();
     791                 :      367804 :                       return path_str == seg_name;
     792                 :             :                     },
     793                 :      397363 :                     false))
     794                 :             :                 {
     795                 :       11804 :                   insert_segment_resolution (segments.back (), kv.second.id);
     796                 :       11804 :                   return Rib::Definition::NonShadowable (kv.second.id);
     797                 :             :                 }
     798                 :             :             }
     799                 :             :         }
     800                 :             : 
     801                 :      121169 :       if (res && !res->is_ambiguous ())
     802                 :       46861 :         insert_segment_resolution (segments.back (), res->get_node_id ());
     803                 :             : 
     804                 :      121169 :       return res;
     805                 :      270621 :     });
     806                 :             : }
     807                 :             : 
     808                 :             : template <Namespace N>
     809                 :             : tl::optional<typename ForeverStack<N>::DfsResult>
     810                 :             : ForeverStack<N>::dfs (ForeverStack<N>::Node &starting_point, NodeId to_find)
     811                 :             : {
     812                 :             :   auto values = starting_point.rib.get_values ();
     813                 :             : 
     814                 :             :   for (auto &kv : values)
     815                 :             :     {
     816                 :             :       for (auto id : kv.second.ids_shadowable)
     817                 :             :         if (id == to_find)
     818                 :             :           return {{starting_point, kv.first}};
     819                 :             :       for (auto id : kv.second.ids_non_shadowable)
     820                 :             :         if (id == to_find)
     821                 :             :           return {{starting_point, kv.first}};
     822                 :             :       for (auto id : kv.second.ids_globbed)
     823                 :             :         if (id == to_find)
     824                 :             :           return {{starting_point, kv.first}};
     825                 :             :     }
     826                 :             : 
     827                 :             :   for (auto &child : starting_point.children)
     828                 :             :     {
     829                 :             :       auto candidate = dfs (child.second, to_find);
     830                 :             : 
     831                 :             :       if (candidate.has_value ())
     832                 :             :         return candidate;
     833                 :             :     }
     834                 :             : 
     835                 :             :   return tl::nullopt;
     836                 :             : }
     837                 :             : 
     838                 :             : template <Namespace N>
     839                 :             : tl::optional<typename ForeverStack<N>::ConstDfsResult>
     840                 :             : ForeverStack<N>::dfs (const ForeverStack<N>::Node &starting_point,
     841                 :             :                       NodeId to_find) const
     842                 :             : {
     843                 :             :   auto values = starting_point.rib.get_values ();
     844                 :             : 
     845                 :             :   for (auto &kv : values)
     846                 :             :     {
     847                 :             :       for (auto id : kv.second.ids_shadowable)
     848                 :             :         if (id == to_find)
     849                 :             :           return {{starting_point, kv.first}};
     850                 :             :       for (auto id : kv.second.ids_non_shadowable)
     851                 :             :         if (id == to_find)
     852                 :             :           return {{starting_point, kv.first}};
     853                 :             :       for (auto id : kv.second.ids_globbed)
     854                 :             :         if (id == to_find)
     855                 :             :           return {{starting_point, kv.first}};
     856                 :             :     }
     857                 :             : 
     858                 :             :   for (auto &child : starting_point.children)
     859                 :             :     {
     860                 :             :       auto candidate = dfs (child.second, to_find);
     861                 :             : 
     862                 :             :       if (candidate.has_value ())
     863                 :             :         return candidate;
     864                 :             :     }
     865                 :             : 
     866                 :             :   return tl::nullopt;
     867                 :             : }
     868                 :             : 
     869                 :             : template <Namespace N>
     870                 :             : tl::optional<Rib &>
     871                 :        1297 : ForeverStack<N>::dfs_rib (ForeverStack<N>::Node &starting_point, NodeId to_find)
     872                 :             : {
     873                 :        1297 :   return dfs_node (starting_point, to_find).map ([] (Node &x) -> Rib & {
     874                 :           1 :     return x.rib;
     875                 :        1297 :   });
     876                 :             : }
     877                 :             : 
     878                 :             : template <Namespace N>
     879                 :             : tl::optional<const Rib &>
     880                 :          52 : ForeverStack<N>::dfs_rib (const ForeverStack<N>::Node &starting_point,
     881                 :             :                           NodeId to_find) const
     882                 :             : {
     883                 :          52 :   return dfs_node (starting_point, to_find)
     884                 :          52 :     .map ([] (const Node &x) -> const Rib & { return x.rib; });
     885                 :             : }
     886                 :             : 
     887                 :             : template <Namespace N>
     888                 :             : tl::optional<typename ForeverStack<N>::Node &>
     889                 :     3144809 : ForeverStack<N>::dfs_node (ForeverStack<N>::Node &starting_point,
     890                 :             :                            NodeId to_find)
     891                 :             : {
     892                 :     3144809 :   if (starting_point.id == to_find)
     893                 :        2555 :     return starting_point;
     894                 :             : 
     895                 :     6276608 :   for (auto &child : starting_point.children)
     896                 :             :     {
     897                 :     3140958 :       auto candidate = dfs_node (child.second, to_find);
     898                 :             : 
     899                 :     3140958 :       if (candidate.has_value ())
     900                 :        6604 :         return candidate;
     901                 :             :     }
     902                 :             : 
     903                 :     3135650 :   return tl::nullopt;
     904                 :             : }
     905                 :             : 
     906                 :             : template <Namespace N>
     907                 :             : tl::optional<const typename ForeverStack<N>::Node &>
     908                 :         939 : ForeverStack<N>::dfs_node (const ForeverStack<N>::Node &starting_point,
     909                 :             :                            NodeId to_find) const
     910                 :             : {
     911                 :         939 :   if (starting_point.id == to_find)
     912                 :          68 :     return starting_point;
     913                 :             : 
     914                 :        1493 :   for (auto &child : starting_point.children)
     915                 :             :     {
     916                 :         859 :       auto candidate = dfs_node (child.second, to_find);
     917                 :             : 
     918                 :         859 :       if (candidate.has_value ())
     919                 :         237 :         return candidate;
     920                 :             :     }
     921                 :             : 
     922                 :         634 :   return tl::nullopt;
     923                 :             : }
     924                 :             : 
     925                 :             : template <Namespace N>
     926                 :             : tl::optional<Rib &>
     927                 :             : ForeverStack<N>::to_rib (NodeId rib_id)
     928                 :             : {
     929                 :             :   return dfs_rib (root, rib_id);
     930                 :             : }
     931                 :             : 
     932                 :             : template <Namespace N>
     933                 :             : tl::optional<const Rib &>
     934                 :          52 : ForeverStack<N>::to_rib (NodeId rib_id) const
     935                 :             : {
     936                 :          52 :   return dfs_rib (root, rib_id);
     937                 :             : }
     938                 :             : 
     939                 :             : template <Namespace N>
     940                 :             : void
     941                 :           0 : ForeverStack<N>::stream_rib (std::stringstream &stream, const Rib &rib,
     942                 :             :                              const std::string &next,
     943                 :             :                              const std::string &next_next) const
     944                 :             : {
     945                 :           0 :   std::string rib_kind = Rib::kind_to_string (rib.kind);
     946                 :           0 :   stream << next << "rib [" << rib_kind << "]: {";
     947                 :           0 :   if (rib.get_values ().empty ())
     948                 :             :     {
     949                 :           0 :       stream << "}\n";
     950                 :           0 :       return;
     951                 :             :     }
     952                 :             :   else
     953                 :             :     {
     954                 :           0 :       stream << "\n";
     955                 :             :     }
     956                 :             : 
     957                 :           0 :   for (const auto &kv : rib.get_values ())
     958                 :           0 :     stream << next_next << kv.first << ": " << kv.second.to_string () << "\n";
     959                 :             : 
     960                 :           0 :   stream << next << "},\n";
     961                 :           0 : }
     962                 :             : 
     963                 :             : template <Namespace N>
     964                 :             : void
     965                 :           0 : ForeverStack<N>::stream_node (std::stringstream &stream, unsigned indentation,
     966                 :             :                               const ForeverStack<N>::Node &node) const
     967                 :             : {
     968                 :           0 :   auto indent = std::string (indentation, ' ');
     969                 :           0 :   auto next = std::string (indentation + 4, ' ');
     970                 :           0 :   auto next_next = std::string (indentation + 8, ' ');
     971                 :             : 
     972                 :             :   stream << indent << "Node {\n"
     973                 :           0 :          << next << "is_root: " << (node.is_root () ? "true" : "false") << ",\n"
     974                 :           0 :          << next << "is_leaf: " << (node.is_leaf () ? "true" : "false")
     975                 :           0 :          << ",\n";
     976                 :             : 
     977                 :           0 :   stream_rib (stream, node.rib, next, next_next);
     978                 :             : 
     979                 :           0 :   stream << indent << "}\n";
     980                 :             : 
     981                 :           0 :   for (auto &kv : node.children)
     982                 :             :     {
     983                 :           0 :       auto link = kv.first;
     984                 :           0 :       auto child = kv.second;
     985                 :           0 :       stream << indent << "Link (" << link.id << ", "
     986                 :           0 :              << (link.path.has_value () ? link.path.value ().as_string ()
     987                 :           0 :                                         : "<anon>")
     988                 :           0 :              << "):\n";
     989                 :             : 
     990                 :           0 :       stream_node (stream, indentation + 4, child);
     991                 :             : 
     992                 :           0 :       stream << '\n';
     993                 :             :     }
     994                 :           0 : }
     995                 :             : 
     996                 :             : template <Namespace N>
     997                 :             : std::string
     998                 :           0 : ForeverStack<N>::as_debug_string () const
     999                 :             : {
    1000                 :           0 :   std::stringstream stream;
    1001                 :             : 
    1002                 :           0 :   stream_node (stream, 0, root);
    1003                 :             : 
    1004                 :           0 :   return stream.str ();
    1005                 :           0 : }
    1006                 :             : 
    1007                 :             : template <Namespace N>
    1008                 :             : bool
    1009                 :          14 : ForeverStack<N>::is_module_descendant (NodeId parent, NodeId child) const
    1010                 :             : {
    1011                 :          14 :   return dfs_node (dfs_node (root, parent).value (), child).has_value ();
    1012                 :             : }
    1013                 :             : 
    1014                 :             : // FIXME: Can we add selftests?
    1015                 :             : 
    1016                 :             : } // namespace Resolver2_0
    1017                 :             : } // namespace Rust
        

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