LCOV - code coverage report
Current view: top level - gcc/rust/resolve - rust-forever-stack.hxx (source / functions) Coverage Total Hit
Test: gcc.info Lines: 85.9 % 355 305
Test Date: 2025-04-19 15:48:17 Functions: 61.4 % 145 89
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                 :      194311 : ForeverStack<N>::Node::is_root () const
      34                 :             : {
      35                 :       44713 :   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                 :       21536 : ForeverStack<N>::Node::is_leaf () const
      48                 :             : {
      49                 :       21536 :   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                 :      139503 : ForeverStack<N>::push (Rib::Kind rib_kind, NodeId id,
      65                 :             :                        tl::optional<Identifier> path)
      66                 :             : {
      67                 :      301794 :   push_inner (rib_kind, Link (id, path));
      68                 :      139503 : }
      69                 :             : 
      70                 :             : template <Namespace N>
      71                 :             : void
      72                 :      139503 : ForeverStack<N>::push_inner (Rib rib, Link link)
      73                 :             : {
      74                 :      139503 :   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                 :        2736 :       rust_assert (&cursor_reference.get () == &root);
      79                 :             :       // Prelude doesn't have an access path
      80                 :        2736 :       rust_assert (!link.path);
      81                 :        2736 :       update_cursor (this->lang_prelude);
      82                 :        2736 :       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                 :      273534 :   auto emplace = cursor ().children.emplace (
      90                 :      136767 :     std::make_pair (link, Node (rib, link.id, cursor ())));
      91                 :             : 
      92                 :      136767 :   auto it = emplace.first;
      93                 :      136767 :   auto existed = !emplace.second;
      94                 :             : 
      95                 :      159597 :   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                 :      136767 :   update_cursor (it->second);
     102                 :             : }
     103                 :             : 
     104                 :             : template <Namespace N>
     105                 :             : void
     106                 :      139482 : ForeverStack<N>::pop ()
     107                 :             : {
     108                 :      139482 :   rust_assert (!cursor ().is_root ());
     109                 :             : 
     110                 :      139482 :   rust_debug ("popping link");
     111                 :             : 
     112                 :      182004 :   for (const auto &kv : cursor ().rib.get_values ())
     113                 :       42522 :     rust_debug ("current_rib: k: %s, v: %s", kv.first.c_str (),
     114                 :             :                 kv.second.to_string ().c_str ());
     115                 :             : 
     116                 :      139482 :   if (cursor ().parent.has_value ())
     117                 :      285155 :     for (const auto &kv : cursor ().parent.value ().rib.get_values ())
     118                 :      145673 :       rust_debug ("new cursor: k: %s, v: %s", kv.first.c_str (),
     119                 :             :                   kv.second.to_string ().c_str ());
     120                 :             : 
     121                 :      139482 :   update_cursor (cursor ().parent.value ());
     122                 :      139482 : }
     123                 :             : 
     124                 :             : static tl::expected<NodeId, DuplicateNameError>
     125                 :       35859 : insert_inner (Rib &rib, std::string name, Rib::Definition definition)
     126                 :             : {
     127                 :       35859 :   return rib.insert (name, definition);
     128                 :             : }
     129                 :             : 
     130                 :             : template <Namespace N>
     131                 :             : tl::expected<NodeId, DuplicateNameError>
     132                 :       32841 : ForeverStack<N>::insert (Identifier name, NodeId node)
     133                 :             : {
     134                 :       32841 :   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                 :       32841 :   return insert_inner (innermost_rib, name.as_string (),
     141                 :       32841 :                        Rib::Definition::NonShadowable (node));
     142                 :             : }
     143                 :             : 
     144                 :             : template <Namespace N>
     145                 :             : tl::expected<NodeId, DuplicateNameError>
     146                 :        2497 : ForeverStack<N>::insert_shadowable (Identifier name, NodeId node)
     147                 :             : {
     148                 :        2497 :   auto &innermost_rib = peek ();
     149                 :             : 
     150                 :        2497 :   return insert_inner (innermost_rib, name.as_string (),
     151                 :        2497 :                        Rib::Definition::Shadowable (node));
     152                 :             : }
     153                 :             : 
     154                 :             : template <Namespace N>
     155                 :             : tl::expected<NodeId, DuplicateNameError>
     156                 :          12 : ForeverStack<N>::insert_globbed (Identifier name, NodeId node)
     157                 :             : {
     158                 :          12 :   auto &innermost_rib = peek ();
     159                 :             : 
     160                 :          12 :   return insert_inner (innermost_rib, name.as_string (),
     161                 :          12 :                        Rib::Definition::Globbed (node));
     162                 :             : }
     163                 :             : 
     164                 :             : template <Namespace N>
     165                 :             : tl::expected<NodeId, DuplicateNameError>
     166                 :           8 : ForeverStack<N>::insert_at_root (Identifier name, NodeId node)
     167                 :             : {
     168                 :           8 :   auto &root_rib = root.rib;
     169                 :             : 
     170                 :             :   // inserting in the root of the crate is never a shadowing operation, even for
     171                 :             :   // macros
     172                 :           8 :   return insert_inner (root_rib, name.as_string (),
     173                 :           8 :                        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                 :          59 : ForeverStack<Namespace::Macros>::insert (Identifier name, NodeId node)
     181                 :             : {
     182                 :          59 :   return insert_inner (peek (), name.as_string (),
     183                 :         118 :                        Rib::Definition::Shadowable (node));
     184                 :             : }
     185                 :             : 
     186                 :             : template <>
     187                 :             : inline tl::expected<NodeId, DuplicateNameError>
     188                 :          27 : ForeverStack<Namespace::Labels>::insert (Identifier name, NodeId node)
     189                 :             : {
     190                 :          27 :   return insert_inner (peek (), name.as_string (),
     191                 :          54 :                        Rib::Definition::Shadowable (node));
     192                 :             : }
     193                 :             : 
     194                 :             : template <>
     195                 :             : inline tl::expected<NodeId, DuplicateNameError>
     196                 :         415 : ForeverStack<Namespace::Types>::insert_variant (Identifier name, NodeId node)
     197                 :             : {
     198                 :         415 :   return insert_inner (peek (), name.as_string (),
     199                 :         830 :                        Rib::Definition::NonShadowable (node, true));
     200                 :             : }
     201                 :             : 
     202                 :             : template <Namespace N>
     203                 :             : Rib &
     204                 :       36018 : ForeverStack<N>::peek ()
     205                 :             : {
     206                 :       36018 :   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                 :       10500 : ForeverStack<N>::reverse_iter (std::function<KeepGoing (Node &)> lambda)
     219                 :             : {
     220                 :       21000 :   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                 :       10875 : ForeverStack<N>::reverse_iter (Node &start,
     234                 :             :                                std::function<KeepGoing (Node &)> lambda)
     235                 :             : {
     236                 :       10875 :   auto *tmp = &start;
     237                 :             : 
     238                 :       13886 :   while (true)
     239                 :             :     {
     240                 :       24761 :       auto keep_going = lambda (*tmp);
     241                 :       24761 :       if (keep_going == KeepGoing::No)
     242                 :             :         return;
     243                 :             : 
     244                 :       17755 :       if (tmp->is_root ())
     245                 :             :         return;
     246                 :             : 
     247                 :       13886 :       tmp = &tmp->parent.value ();
     248                 :             :     }
     249                 :             : }
     250                 :             : 
     251                 :             : template <Namespace N>
     252                 :             : void
     253                 :        5214 : ForeverStack<N>::reverse_iter (
     254                 :             :   const Node &start, std::function<KeepGoing (const Node &)> lambda) const
     255                 :             : {
     256                 :        5214 :   auto *tmp = &start;
     257                 :             : 
     258                 :        3593 :   while (true)
     259                 :             :     {
     260                 :        8807 :       auto keep_going = lambda (*tmp);
     261                 :        8807 :       if (keep_going == KeepGoing::No)
     262                 :             :         return;
     263                 :             : 
     264                 :        3593 :       if (tmp->is_root ())
     265                 :             :         return;
     266                 :             : 
     267                 :        3593 :       tmp = &tmp->parent.value ();
     268                 :             :     }
     269                 :             : }
     270                 :             : 
     271                 :             : template <Namespace N>
     272                 :             : typename ForeverStack<N>::Node &
     273                 :      743271 : ForeverStack<N>::cursor ()
     274                 :             : {
     275                 :      743271 :   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                 :      139503 : ForeverStack<N>::update_cursor (Node &new_cursor)
     288                 :             : {
     289                 :      139503 :   cursor_reference = new_cursor;
     290                 :             : }
     291                 :             : 
     292                 :             : template <Namespace N>
     293                 :             : tl::optional<Rib::Definition>
     294                 :       10486 : ForeverStack<N>::get (const Identifier &name)
     295                 :             : {
     296                 :       10486 :   tl::optional<Rib::Definition> resolved_definition = tl::nullopt;
     297                 :             : 
     298                 :             :   // TODO: Can we improve the API? have `reverse_iter` return an optional?
     299                 :       34833 :   reverse_iter ([&resolved_definition, &name] (Node &current) {
     300                 :       24347 :     auto candidate = current.rib.get (name.as_string ());
     301                 :             : 
     302                 :       24347 :     return candidate.map_or (
     303                 :       55322 :       [&resolved_definition] (Rib::Definition found) {
     304                 :        6628 :         if (found.is_variant ())
     305                 :             :           return KeepGoing::Yes;
     306                 :             :         // for most namespaces, we do not need to care about various ribs -
     307                 :             :         // they are available from all contexts if defined in the current
     308                 :             :         // scope, or an outermore one. so if we do have a candidate, we can
     309                 :             :         // return it directly and stop iterating
     310                 :        6625 :         resolved_definition = found;
     311                 :             : 
     312                 :        6625 :         return KeepGoing::No;
     313                 :             :       },
     314                 :             :       // if there was no candidate, we keep iterating
     315                 :       24347 :       KeepGoing::Yes);
     316                 :       24347 :   });
     317                 :             : 
     318                 :       10486 :   return resolved_definition;
     319                 :             : }
     320                 :             : 
     321                 :             : template <Namespace N>
     322                 :             : tl::optional<Rib::Definition>
     323                 :          10 : ForeverStack<N>::get_lang_prelude (const Identifier &name)
     324                 :             : {
     325                 :          10 :   return lang_prelude.rib.get (name.as_string ());
     326                 :             : }
     327                 :             : 
     328                 :             : template <Namespace N>
     329                 :             : tl::optional<Rib::Definition>
     330                 :        3891 : ForeverStack<N>::get_lang_prelude (const std::string &name)
     331                 :             : {
     332                 :        3891 :   return lang_prelude.rib.get (name);
     333                 :             : }
     334                 :             : 
     335                 :             : template <>
     336                 :          14 : tl::optional<Rib::Definition> inline ForeverStack<Namespace::Labels>::get (
     337                 :             :   const Identifier &name)
     338                 :             : {
     339                 :          14 :   tl::optional<Rib::Definition> resolved_definition = tl::nullopt;
     340                 :             : 
     341                 :          14 :   reverse_iter ([&resolved_definition, &name] (Node &current) {
     342                 :             :     // looking up for labels cannot go through function ribs
     343                 :             :     // TODO: What other ribs?
     344                 :          14 :     if (current.rib.kind == Rib::Kind::Function)
     345                 :             :       return KeepGoing::No;
     346                 :             : 
     347                 :          14 :     auto candidate = current.rib.get (name.as_string ());
     348                 :             : 
     349                 :             :     // FIXME: Factor this in a function with the generic `get`
     350                 :          14 :     return candidate.map_or (
     351                 :          34 :       [&resolved_definition] (Rib::Definition found) {
     352                 :           6 :         resolved_definition = found;
     353                 :             : 
     354                 :           6 :         return KeepGoing::No;
     355                 :             :       },
     356                 :          14 :       KeepGoing::Yes);
     357                 :          14 :   });
     358                 :             : 
     359                 :          14 :   return resolved_definition;
     360                 :             : }
     361                 :             : 
     362                 :             : /* Check if an iterator points to the last element */
     363                 :             : template <typename I, typename C>
     364                 :             : static bool
     365                 :        6207 : is_last (const I &iterator, const C &collection)
     366                 :             : {
     367                 :        6207 :   return iterator + 1 == collection.end ();
     368                 :             : }
     369                 :             : 
     370                 :             : /* Check if an iterator points to the start of the collection */
     371                 :             : template <typename I, typename C>
     372                 :             : static bool
     373                 :        2596 : is_start (const I &iterator, const C &collection)
     374                 :             : {
     375                 :        4666 :   return iterator == collection.begin ();
     376                 :             : }
     377                 :             : 
     378                 :             : template <Namespace N>
     379                 :             : typename ForeverStack<N>::Node &
     380                 :         375 : ForeverStack<N>::find_closest_module (Node &starting_point)
     381                 :             : {
     382                 :         375 :   auto *closest_module = &starting_point;
     383                 :             : 
     384                 :         775 :   reverse_iter (starting_point, [&closest_module] (Node &current) {
     385                 :         400 :     if (current.rib.kind == Rib::Kind::Module || current.is_root ())
     386                 :             :       {
     387                 :         375 :         closest_module = &current;
     388                 :         375 :         return KeepGoing::No;
     389                 :             :       }
     390                 :             : 
     391                 :             :     return KeepGoing::Yes;
     392                 :             :   });
     393                 :             : 
     394                 :         375 :   return *closest_module;
     395                 :             : }
     396                 :             : 
     397                 :             : /* If a the given condition is met, emit an error about misused leading path
     398                 :             :  * segments */
     399                 :             : template <typename S>
     400                 :             : static inline bool
     401                 :        4398 : check_leading_kw_at_start (const S &segment, bool condition)
     402                 :             : {
     403                 :        4398 :   if (condition)
     404                 :          10 :     rust_error_at (
     405                 :             :       segment.get_locus (), ErrorCode::E0433,
     406                 :             :       "leading path segment %qs can only be used at the beginning of a path",
     407                 :          20 :       segment.as_string ().c_str ());
     408                 :             : 
     409                 :        4398 :   return condition;
     410                 :             : }
     411                 :             : 
     412                 :             : // we first need to handle the "starting" segments - `super`, `self` or
     413                 :             : // `crate`. we don't need to do anything for `self` and can just skip it. for
     414                 :             : // `crate`, we need to go back to the root of the current stack. for each
     415                 :             : // `super` segment, we go back to the cursor's parent until we reach the
     416                 :             : // correct one or the root.
     417                 :             : template <Namespace N>
     418                 :             : template <typename S>
     419                 :             : tl::optional<typename std::vector<S>::const_iterator>
     420                 :        2058 : ForeverStack<N>::find_starting_point (
     421                 :             :   const std::vector<S> &segments, std::reference_wrapper<Node> &starting_point,
     422                 :             :   std::function<void (const S &, NodeId)> insert_segment_resolution)
     423                 :             : {
     424                 :        2058 :   auto iterator = segments.begin ();
     425                 :             : 
     426                 :        2235 :   for (; !is_last (iterator, segments); iterator++)
     427                 :             :     {
     428                 :        2070 :       auto &outer_seg = *iterator;
     429                 :             : 
     430                 :        2070 :       if (unwrap_segment_get_lang_item (outer_seg).has_value ())
     431                 :             :         break;
     432                 :             : 
     433                 :        2070 :       auto &seg = unwrap_type_segment (outer_seg);
     434                 :        2070 :       bool is_self_or_crate
     435                 :        2070 :         = seg.is_crate_path_seg () || seg.is_lower_self_seg ();
     436                 :             : 
     437                 :             :       // if we're after the first path segment and meet `self` or `crate`, it's
     438                 :             :       // an error - we should only be seeing `super` keywords at this point
     439                 :        2070 :       if (check_leading_kw_at_start (seg, !is_start (iterator, segments)
     440                 :        2070 :                                             && is_self_or_crate))
     441                 :           2 :         return tl::nullopt;
     442                 :             : 
     443                 :        2068 :       if (seg.is_crate_path_seg ())
     444                 :             :         {
     445                 :         277 :           starting_point = root;
     446                 :         277 :           insert_segment_resolution (outer_seg, starting_point.get ().id);
     447                 :         277 :           iterator++;
     448                 :             :           break;
     449                 :             :         }
     450                 :        1791 :       if (seg.is_lower_self_seg ())
     451                 :             :         {
     452                 :             :           // insert segment resolution and exit
     453                 :          19 :           starting_point = find_closest_module (starting_point);
     454                 :          19 :           insert_segment_resolution (outer_seg, starting_point.get ().id);
     455                 :          19 :           iterator++;
     456                 :             :           break;
     457                 :             :         }
     458                 :        1949 :       if (seg.is_super_path_seg ())
     459                 :             :         {
     460                 :         179 :           starting_point = find_closest_module (starting_point);
     461                 :         179 :           if (starting_point.get ().is_root ())
     462                 :             :             {
     463                 :           2 :               rust_error_at (seg.get_locus (), ErrorCode::E0433,
     464                 :             :                              "too many leading %<super%> keywords");
     465                 :           2 :               return tl::nullopt;
     466                 :             :             }
     467                 :             : 
     468                 :         177 :           starting_point
     469                 :         177 :             = find_closest_module (starting_point.get ().parent.value ());
     470                 :             : 
     471                 :         177 :           insert_segment_resolution (outer_seg, starting_point.get ().id);
     472                 :             :           continue;
     473                 :             :         }
     474                 :             : 
     475                 :             :       // now we've gone through the allowed `crate`, `self` or leading `super`
     476                 :             :       // segments. we can start resolving each segment itself.
     477                 :             :       // if we do see another leading segment, then we can error out.
     478                 :             :       break;
     479                 :             :     }
     480                 :             : 
     481                 :        2054 :   return iterator;
     482                 :             : }
     483                 :             : 
     484                 :             : template <Namespace N>
     485                 :             : template <typename S>
     486                 :             : tl::optional<typename ForeverStack<N>::Node &>
     487                 :        2054 : ForeverStack<N>::resolve_segments (
     488                 :             :   Node &starting_point, const std::vector<S> &segments,
     489                 :             :   typename std::vector<S>::const_iterator iterator,
     490                 :             :   std::function<void (const S &, NodeId)> insert_segment_resolution)
     491                 :             : {
     492                 :        2054 :   Node *current_node = &starting_point;
     493                 :        4382 :   for (; !is_last (iterator, segments); iterator++)
     494                 :             :     {
     495                 :        2328 :       auto &outer_seg = *iterator;
     496                 :             : 
     497                 :        2328 :       if (auto lang_item = unwrap_segment_get_lang_item (outer_seg))
     498                 :             :         {
     499                 :           0 :           NodeId seg_id = Analysis::Mappings::get ().get_lang_item_node (
     500                 :           0 :             lang_item.value ());
     501                 :           0 :           current_node = &dfs_node (root, seg_id).value ();
     502                 :             : 
     503                 :           0 :           insert_segment_resolution (outer_seg, seg_id);
     504                 :           0 :           continue;
     505                 :           0 :         }
     506                 :             : 
     507                 :        2328 :       auto &seg = unwrap_type_segment (outer_seg);
     508                 :        2328 :       std::string str = seg.as_string ();
     509                 :        2328 :       rust_debug ("[ARTHUR]: resolving segment part: %s", str.c_str ());
     510                 :             : 
     511                 :             :       // check that we don't encounter *any* leading keywords afterwards
     512                 :        4656 :       if (check_leading_kw_at_start (seg, seg.is_crate_path_seg ()
     513                 :        2328 :                                             || seg.is_super_path_seg ()
     514                 :        4651 :                                             || seg.is_lower_self_seg ()))
     515                 :           8 :         return tl::nullopt;
     516                 :             : 
     517                 :        2320 :       tl::optional<typename ForeverStack<N>::Node &> child = tl::nullopt;
     518                 :             : 
     519                 :             :       /*
     520                 :             :        * On every iteration this loop either
     521                 :             :        *
     522                 :             :        * 1. terminates
     523                 :             :        *
     524                 :             :        * 2. decreases the depth of the node pointed to by current_node until
     525                 :             :        *    current_node reaches the root
     526                 :             :        *
     527                 :             :        * 3. If the root node is reached, and we were not able to resolve the
     528                 :             :        *    segment, we search the prelude rib for the segment, by setting
     529                 :             :        *    current_node to point to the prelude, and toggling the
     530                 :             :        *    searched_prelude boolean to true. If current_node is the prelude
     531                 :             :        *    rib, and searched_prelude is true, we will exit.
     532                 :             :        *
     533                 :             :        * This ensures termination.
     534                 :             :        *
     535                 :             :        */
     536                 :        2320 :       bool searched_prelude = false;
     537                 :             :       while (true)
     538                 :             :         {
     539                 :             :           // may set the value of child
     540                 :       19830 :           for (auto &kv : current_node->children)
     541                 :             :             {
     542                 :       16838 :               auto &link = kv.first;
     543                 :             : 
     544                 :       33676 :               if (link.path.map_or (
     545                 :       41028 :                     [&str] (Identifier path) {
     546                 :        7352 :                       auto &path_str = path.as_string ();
     547                 :        7352 :                       return str == path_str;
     548                 :             :                     },
     549                 :       16838 :                     false))
     550                 :             :                 {
     551                 :        1918 :                   child = kv.second;
     552                 :             :                   break;
     553                 :             :                 }
     554                 :             :             }
     555                 :             : 
     556                 :        4910 :           if (child.has_value ())
     557                 :             :             {
     558                 :             :               break;
     559                 :             :             }
     560                 :             : 
     561                 :             :           if (N == Namespace::Types)
     562                 :             :             {
     563                 :        1377 :               auto rib_lookup = current_node->rib.get (seg.as_string ());
     564                 :        1377 :               if (rib_lookup && !rib_lookup->is_ambiguous ())
     565                 :             :                 {
     566                 :         247 :                   insert_segment_resolution (outer_seg,
     567                 :             :                                              rib_lookup->get_node_id ());
     568                 :         247 :                   return tl::nullopt;
     569                 :             :                 }
     570                 :        1377 :             }
     571                 :             : 
     572                 :        2745 :           if (current_node->is_root () && !searched_prelude)
     573                 :             :             {
     574                 :         149 :               searched_prelude = true;
     575                 :         149 :               current_node = &lang_prelude;
     576                 :         149 :               continue;
     577                 :             :             }
     578                 :             : 
     579                 :        2596 :           if (!is_start (iterator, segments)
     580                 :        2590 :               || current_node->rib.kind == Rib::Kind::Module
     581                 :        5184 :               || current_node->is_prelude ())
     582                 :             :             {
     583                 :         155 :               return tl::nullopt;
     584                 :             :             }
     585                 :             : 
     586                 :        2441 :           current_node = &current_node->parent.value ();
     587                 :             :         }
     588                 :             : 
     589                 :             :       // if child didn't contain a value
     590                 :             :       // the while loop above should have return'd or kept looping
     591                 :        1918 :       current_node = &child.value ();
     592                 :        1918 :       insert_segment_resolution (outer_seg, current_node->id);
     593                 :             :     }
     594                 :             : 
     595                 :        1644 :   return *current_node;
     596                 :             : }
     597                 :             : 
     598                 :             : template <>
     599                 :             : inline tl::optional<Rib::Definition>
     600                 :         485 : ForeverStack<Namespace::Types>::resolve_final_segment (Node &final_node,
     601                 :             :                                                        std::string &seg_name,
     602                 :             :                                                        bool is_lower_self)
     603                 :             : {
     604                 :         485 :   if (is_lower_self)
     605                 :          38 :     return Rib::Definition::NonShadowable (final_node.id);
     606                 :             :   else
     607                 :         447 :     return final_node.rib.get (seg_name);
     608                 :             : }
     609                 :             : 
     610                 :             : template <Namespace N>
     611                 :             : tl::optional<Rib::Definition>
     612                 :        1017 : ForeverStack<N>::resolve_final_segment (Node &final_node, std::string &seg_name,
     613                 :             :                                         bool is_lower_self)
     614                 :             : {
     615                 :        1017 :   return final_node.rib.get (seg_name);
     616                 :             : }
     617                 :             : 
     618                 :             : template <Namespace N>
     619                 :             : template <typename S>
     620                 :             : tl::optional<Rib::Definition>
     621                 :        9678 : ForeverStack<N>::resolve_path (
     622                 :             :   const std::vector<S> &segments, bool has_opening_scope_resolution,
     623                 :             :   std::function<void (const S &, NodeId)> insert_segment_resolution)
     624                 :             : {
     625                 :             :   // TODO: What to do if segments.empty() ?
     626                 :             : 
     627                 :             :   // handle paths with opening scopes
     628                 :        9678 :   std::function<void (void)> cleanup_current = [] () {};
     629                 :        9678 :   if (has_opening_scope_resolution)
     630                 :             :     {
     631                 :          40 :       Node *last_current = &cursor_reference.get ();
     632                 :          40 :       if (get_rust_edition () == Edition::E2015)
     633                 :          40 :         cursor_reference = root;
     634                 :             :       else
     635                 :           0 :         cursor_reference = extern_prelude;
     636                 :             :       cleanup_current
     637                 :          80 :         = [this, last_current] () { cursor_reference = *last_current; };
     638                 :             :     }
     639                 :             : 
     640                 :             :   // if there's only one segment, we just use `get`
     641                 :        9678 :   if (segments.size () == 1)
     642                 :             :     {
     643                 :        7620 :       auto &seg = segments.front ();
     644                 :        7620 :       if (auto lang_item = unwrap_segment_get_lang_item (seg))
     645                 :             :         {
     646                 :          78 :           NodeId seg_id = Analysis::Mappings::get ().get_lang_item_node (
     647                 :          39 :             lang_item.value ());
     648                 :             : 
     649                 :          39 :           insert_segment_resolution (seg, seg_id);
     650                 :          39 :           cleanup_current ();
     651                 :             :           // TODO: does NonShadowable matter?
     652                 :          39 :           return Rib::Definition::NonShadowable (seg_id);
     653                 :             :         }
     654                 :             : 
     655                 :        7581 :       tl::optional<Rib::Definition> res
     656                 :       15162 :         = get (unwrap_type_segment (segments.back ()).as_string ());
     657                 :             : 
     658                 :        7581 :       if (!res)
     659                 :        6275 :         res = get_lang_prelude (
     660                 :        6366 :           unwrap_type_segment (segments.back ()).as_string ());
     661                 :             : 
     662                 :        7581 :       if (res && !res->is_ambiguous ())
     663                 :        7489 :         insert_segment_resolution (segments.back (), res->get_node_id ());
     664                 :        7581 :       cleanup_current ();
     665                 :        7581 :       return res;
     666                 :        7581 :     }
     667                 :             : 
     668                 :        2058 :   std::reference_wrapper<Node> starting_point = cursor ();
     669                 :             : 
     670                 :        2058 :   auto res
     671                 :        2058 :     = find_starting_point (segments, starting_point, insert_segment_resolution)
     672                 :        4116 :         .and_then (
     673                 :        4112 :           [this, &segments, &starting_point, &insert_segment_resolution] (
     674                 :             :             typename std::vector<S>::const_iterator iterator) {
     675                 :        2054 :             return resolve_segments (starting_point.get (), segments, iterator,
     676                 :        2054 :                                      insert_segment_resolution);
     677                 :             :           })
     678                 :        3702 :         .and_then ([this, &segments, &insert_segment_resolution] (
     679                 :             :                      Node final_node) -> tl::optional<Rib::Definition> {
     680                 :             :           // leave resolution within impl blocks to type checker
     681                 :        1644 :           if (final_node.rib.kind == Rib::Kind::TraitOrImpl)
     682                 :         142 :             return tl::nullopt;
     683                 :             : 
     684                 :        1502 :           auto &seg = unwrap_type_segment (segments.back ());
     685                 :        1502 :           std::string seg_name = seg.as_string ();
     686                 :             : 
     687                 :             :           // assuming this can't be a lang item segment
     688                 :        1502 :           tl::optional<Rib::Definition> res
     689                 :             :             = resolve_final_segment (final_node, seg_name,
     690                 :        1502 :                                      seg.is_lower_self_seg ());
     691                 :             :           // Ok we didn't find it in the rib, Lets try the prelude...
     692                 :        1502 :           if (!res)
     693                 :         708 :             res = get_lang_prelude (seg_name);
     694                 :             : 
     695                 :        1502 :           if (res && !res->is_ambiguous ())
     696                 :         794 :             insert_segment_resolution (segments.back (), res->get_node_id ());
     697                 :             : 
     698                 :        1502 :           return res;
     699                 :        1502 :         });
     700                 :        2058 :   cleanup_current ();
     701                 :        2058 :   return res;
     702                 :        2058 : }
     703                 :             : 
     704                 :             : template <Namespace N>
     705                 :             : tl::optional<typename ForeverStack<N>::DfsResult>
     706                 :             : ForeverStack<N>::dfs (ForeverStack<N>::Node &starting_point, NodeId to_find)
     707                 :             : {
     708                 :             :   auto values = starting_point.rib.get_values ();
     709                 :             : 
     710                 :             :   for (auto &kv : values)
     711                 :             :     {
     712                 :             :       for (auto id : kv.second.ids_shadowable)
     713                 :             :         if (id == to_find)
     714                 :             :           return {{starting_point, kv.first}};
     715                 :             :       for (auto id : kv.second.ids_non_shadowable)
     716                 :             :         if (id == to_find)
     717                 :             :           return {{starting_point, kv.first}};
     718                 :             :       for (auto id : kv.second.ids_globbed)
     719                 :             :         if (id == to_find)
     720                 :             :           return {{starting_point, kv.first}};
     721                 :             :     }
     722                 :             : 
     723                 :             :   for (auto &child : starting_point.children)
     724                 :             :     {
     725                 :             :       auto candidate = dfs (child.second, to_find);
     726                 :             : 
     727                 :             :       if (candidate.has_value ())
     728                 :             :         return candidate;
     729                 :             :     }
     730                 :             : 
     731                 :             :   return tl::nullopt;
     732                 :             : }
     733                 :             : 
     734                 :             : template <Namespace N>
     735                 :             : tl::optional<typename ForeverStack<N>::ConstDfsResult>
     736                 :      199914 : ForeverStack<N>::dfs (const ForeverStack<N>::Node &starting_point,
     737                 :             :                       NodeId to_find) const
     738                 :             : {
     739                 :      199914 :   auto values = starting_point.rib.get_values ();
     740                 :             : 
     741                 :      384166 :   for (auto &kv : values)
     742                 :             :     {
     743                 :      264788 :       for (auto id : kv.second.ids_shadowable)
     744                 :       75322 :         if (id == to_find)
     745                 :           0 :           return {{starting_point, kv.first}};
     746                 :      300037 :       for (auto id : kv.second.ids_non_shadowable)
     747                 :      115779 :         if (id == to_find)
     748                 :        5208 :           return {{starting_point, kv.first}};
     749                 :      184270 :       for (auto id : kv.second.ids_globbed)
     750                 :          18 :         if (id == to_find)
     751                 :           6 :           return {{starting_point, kv.first}};
     752                 :             :     }
     753                 :             : 
     754                 :      389400 :   for (auto &child : starting_point.children)
     755                 :             :     {
     756                 :      194700 :       auto candidate = dfs (child.second, to_find);
     757                 :             : 
     758                 :      194700 :       if (candidate.has_value ())
     759                 :        3593 :         return candidate;
     760                 :             :     }
     761                 :             : 
     762                 :      191107 :   return tl::nullopt;
     763                 :      199914 : }
     764                 :             : 
     765                 :             : template <Namespace N>
     766                 :             : tl::optional<Resolver::CanonicalPath>
     767                 :        5214 : ForeverStack<N>::to_canonical_path (NodeId id) const
     768                 :             : {
     769                 :             :   // find the id in the current forever stack, starting from the root,
     770                 :             :   // performing either a BFS or DFS once the Node containing the ID is found, go
     771                 :             :   // back up to the root (parent().parent().parent()...) accumulate link
     772                 :             :   // segments reverse them that's your canonical path
     773                 :             : 
     774                 :        5674 :   return dfs (root, id).map ([this, id] (ConstDfsResult tuple) {
     775                 :        5214 :     auto containing_node = tuple.first;
     776                 :        5214 :     auto name = tuple.second;
     777                 :             : 
     778                 :        5214 :     auto segments = std::vector<Resolver::CanonicalPath> ();
     779                 :             : 
     780                 :       14021 :     reverse_iter (containing_node, [&segments] (const Node &current) {
     781                 :        8807 :       if (current.is_root ())
     782                 :             :         return KeepGoing::No;
     783                 :             : 
     784                 :        3593 :       auto children = current.parent.value ().children;
     785                 :        3593 :       const Link *outer_link = nullptr;
     786                 :             : 
     787                 :       32287 :       for (auto &kv : children)
     788                 :             :         {
     789                 :       32287 :           auto &link = kv.first;
     790                 :       32287 :           auto &child = kv.second;
     791                 :             : 
     792                 :       32287 :           if (current.id == child.id)
     793                 :             :             {
     794                 :             :               outer_link = &link;
     795                 :             :               break;
     796                 :             :             }
     797                 :             :         }
     798                 :             : 
     799                 :        3593 :       rust_assert (outer_link);
     800                 :             : 
     801                 :        3967 :       outer_link->path.map ([&segments, outer_link] (Identifier path) {
     802                 :        1873 :         segments.emplace (segments.begin (),
     803                 :        1873 :                           Resolver::CanonicalPath::new_seg (outer_link->id,
     804                 :             :                                                             path.as_string ()));
     805                 :             :       });
     806                 :             : 
     807                 :        3593 :       return KeepGoing::Yes;
     808                 :        3593 :     });
     809                 :             : 
     810                 :        5214 :     auto &mappings = Analysis::Mappings::get ();
     811                 :        5214 :     CrateNum crate_num = mappings.lookup_crate_num (root.id).value ();
     812                 :        5214 :     auto path = Resolver::CanonicalPath::new_seg (
     813                 :        5214 :       root.id, mappings.get_crate_name (crate_num).value ());
     814                 :        5214 :     path.set_crate_num (crate_num);
     815                 :             : 
     816                 :        7087 :     for (const auto &segment : segments)
     817                 :        1873 :       path = path.append (segment);
     818                 :             : 
     819                 :             :     // Finally, append the name
     820                 :        5214 :     path = path.append (Resolver::CanonicalPath::new_seg (id, name));
     821                 :             : 
     822                 :        5214 :     return path;
     823                 :       10428 :   });
     824                 :             : }
     825                 :             : 
     826                 :             : template <Namespace N>
     827                 :             : tl::optional<Rib &>
     828                 :             : ForeverStack<N>::dfs_rib (ForeverStack<N>::Node &starting_point, NodeId to_find)
     829                 :             : {
     830                 :             :   return dfs_node (starting_point, to_find).map ([] (Node &x) -> Rib & {
     831                 :             :     return x.rib;
     832                 :             :   });
     833                 :             : }
     834                 :             : 
     835                 :             : template <Namespace N>
     836                 :             : tl::optional<const Rib &>
     837                 :           1 : ForeverStack<N>::dfs_rib (const ForeverStack<N>::Node &starting_point,
     838                 :             :                           NodeId to_find) const
     839                 :             : {
     840                 :           1 :   return dfs_node (starting_point, to_find)
     841                 :           1 :     .map ([] (const Node &x) -> const Rib & { return x.rib; });
     842                 :             : }
     843                 :             : 
     844                 :             : template <Namespace N>
     845                 :             : tl::optional<typename ForeverStack<N>::Node &>
     846                 :           0 : ForeverStack<N>::dfs_node (ForeverStack<N>::Node &starting_point,
     847                 :             :                            NodeId to_find)
     848                 :             : {
     849                 :           0 :   if (starting_point.id == to_find)
     850                 :           0 :     return starting_point;
     851                 :             : 
     852                 :           0 :   for (auto &child : starting_point.children)
     853                 :             :     {
     854                 :           0 :       auto candidate = dfs_node (child.second, to_find);
     855                 :             : 
     856                 :           0 :       if (candidate.has_value ())
     857                 :           0 :         return candidate;
     858                 :             :     }
     859                 :             : 
     860                 :           0 :   return tl::nullopt;
     861                 :             : }
     862                 :             : 
     863                 :             : template <Namespace N>
     864                 :             : tl::optional<const typename ForeverStack<N>::Node &>
     865                 :         114 : ForeverStack<N>::dfs_node (const ForeverStack<N>::Node &starting_point,
     866                 :             :                            NodeId to_find) const
     867                 :             : {
     868                 :         114 :   if (starting_point.id == to_find)
     869                 :          15 :     return starting_point;
     870                 :             : 
     871                 :         156 :   for (auto &child : starting_point.children)
     872                 :             :     {
     873                 :          87 :       auto candidate = dfs_node (child.second, to_find);
     874                 :             : 
     875                 :          87 :       if (candidate.has_value ())
     876                 :          30 :         return candidate;
     877                 :             :     }
     878                 :             : 
     879                 :          69 :   return tl::nullopt;
     880                 :             : }
     881                 :             : 
     882                 :             : template <Namespace N>
     883                 :             : tl::optional<Rib &>
     884                 :             : ForeverStack<N>::to_rib (NodeId rib_id)
     885                 :             : {
     886                 :             :   return dfs_rib (root, rib_id);
     887                 :             : }
     888                 :             : 
     889                 :             : template <Namespace N>
     890                 :             : tl::optional<const Rib &>
     891                 :           1 : ForeverStack<N>::to_rib (NodeId rib_id) const
     892                 :             : {
     893                 :           1 :   return dfs_rib (root, rib_id);
     894                 :             : }
     895                 :             : 
     896                 :             : template <Namespace N>
     897                 :             : void
     898                 :           0 : ForeverStack<N>::stream_rib (std::stringstream &stream, const Rib &rib,
     899                 :             :                              const std::string &next,
     900                 :             :                              const std::string &next_next) const
     901                 :             : {
     902                 :           0 :   std::string rib_kind = Rib::kind_to_string (rib.kind);
     903                 :           0 :   stream << next << "rib [" << rib_kind << "]: {";
     904                 :           0 :   if (rib.get_values ().empty ())
     905                 :             :     {
     906                 :           0 :       stream << "}\n";
     907                 :           0 :       return;
     908                 :             :     }
     909                 :             :   else
     910                 :             :     {
     911                 :           0 :       stream << "\n";
     912                 :             :     }
     913                 :             : 
     914                 :           0 :   for (const auto &kv : rib.get_values ())
     915                 :           0 :     stream << next_next << kv.first << ": " << kv.second.to_string () << "\n";
     916                 :             : 
     917                 :           0 :   stream << next << "},\n";
     918                 :           0 : }
     919                 :             : 
     920                 :             : template <Namespace N>
     921                 :             : void
     922                 :           0 : ForeverStack<N>::stream_node (std::stringstream &stream, unsigned indentation,
     923                 :             :                               const ForeverStack<N>::Node &node) const
     924                 :             : {
     925                 :           0 :   auto indent = std::string (indentation, ' ');
     926                 :           0 :   auto next = std::string (indentation + 4, ' ');
     927                 :           0 :   auto next_next = std::string (indentation + 8, ' ');
     928                 :             : 
     929                 :             :   stream << indent << "Node {\n"
     930                 :           0 :          << next << "is_root: " << (node.is_root () ? "true" : "false") << ",\n"
     931                 :           0 :          << next << "is_leaf: " << (node.is_leaf () ? "true" : "false")
     932                 :           0 :          << ",\n";
     933                 :             : 
     934                 :           0 :   stream_rib (stream, node.rib, next, next_next);
     935                 :             : 
     936                 :           0 :   stream << indent << "}\n";
     937                 :             : 
     938                 :           0 :   for (auto &kv : node.children)
     939                 :             :     {
     940                 :           0 :       auto link = kv.first;
     941                 :           0 :       auto child = kv.second;
     942                 :           0 :       stream << indent << "Link (" << link.id << ", "
     943                 :           0 :              << (link.path.has_value () ? link.path.value ().as_string ()
     944                 :             :                                         : "<anon>")
     945                 :           0 :              << "):\n";
     946                 :             : 
     947                 :           0 :       stream_node (stream, indentation + 4, child);
     948                 :             : 
     949                 :           0 :       stream << '\n';
     950                 :             :     }
     951                 :           0 : }
     952                 :             : 
     953                 :             : template <Namespace N>
     954                 :             : std::string
     955                 :           0 : ForeverStack<N>::as_debug_string () const
     956                 :             : {
     957                 :           0 :   std::stringstream stream;
     958                 :             : 
     959                 :           0 :   stream_node (stream, 0, root);
     960                 :             : 
     961                 :           0 :   return stream.str ();
     962                 :           0 : }
     963                 :             : 
     964                 :             : template <Namespace N>
     965                 :             : bool
     966                 :          13 : ForeverStack<N>::is_module_descendant (NodeId parent, NodeId child) const
     967                 :             : {
     968                 :          13 :   return dfs_node (dfs_node (root, parent).value (), child).has_value ();
     969                 :             : }
     970                 :             : 
     971                 :             : // FIXME: Can we add selftests?
     972                 :             : 
     973                 :             : } // namespace Resolver2_0
     974                 :             : } // 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.