LCOV - code coverage report
Current view: top level - gcc/rust/resolve - rust-name-resolution-context.hxx (source / functions) Coverage Total Hit
Test: gcc.info Lines: 92.1 % 152 140
Test Date: 2026-08-22 16:33:35 Functions: 78.6 % 14 11
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2026 Free Software Foundation, Inc.
       2              : 
       3              : // This file is part of GCC.
       4              : 
       5              : // GCC is free software; you can redistribute it and/or modify it under
       6              : // the terms of the GNU General Public License as published by the Free
       7              : // Software Foundation; either version 3, or (at your option) any later
       8              : // version.
       9              : 
      10              : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11              : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12              : // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13              : // for more details.
      14              : 
      15              : // You should have received a copy of the GNU General Public License
      16              : // along with GCC; see the file COPYING3.  If not see
      17              : // <http://www.gnu.org/licenses/>.
      18              : 
      19              : #include "optional.h"
      20              : #include "rust-forever-stack.h"
      21              : #include "rust-name-resolution-context.h"
      22              : 
      23              : /**
      24              :  * Split the actual path resolution logic in its own file because it's a lot,
      25              :  * and it could get even worse for certain edge cases.
      26              :  */
      27              : 
      28              : namespace Rust {
      29              : namespace Resolver2_0 {
      30              : 
      31              : template <Namespace N>
      32              : bool
      33        78402 : NameResolutionContext::should_search_prelude (
      34              :   const typename ForeverStack<N>::Node *current_node,
      35              :   const typename ForeverStack<N>::SegIterator &iterator,
      36              :   const std::vector<ResolutionPath::Segment> &segments)
      37              : {
      38              :   // Check whether the current_node is a root node
      39        78402 :   if (current_node->is_root ())
      40              :     return true;
      41              : 
      42              :   // Check whether we're at the start of a module (we can't travel elsewhere
      43              :   // from the start of a module)
      44        78383 :   if (is_start (iterator, segments)
      45        78383 :       && current_node->rib (N).kind == Rib::Kind::Module)
      46              :     return true;
      47              : 
      48              :   return false;
      49              : }
      50              : 
      51              : template <Namespace N>
      52              : tl::optional<Rib::Definition>
      53       303209 : NameResolutionContext::resolve_path (
      54              :   ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode,
      55              :   std::function<void (Usage, Definition, Namespace)> insert_segment_resolution,
      56              :   std::vector<Error> &collect_errors)
      57              : {
      58       303209 :   std::reference_wrapper<typename ForeverStack<N>::Node> starting_point
      59              :     = stack.cursor ();
      60              : 
      61       303209 :   return NameResolutionContext::resolve_path (stack, path, mode,
      62              :                                               insert_segment_resolution,
      63       303209 :                                               collect_errors, starting_point);
      64              : }
      65              : 
      66              : template <Namespace N>
      67              : tl::optional<Rib::Definition>
      68        25957 : NameResolutionContext::resolve_path (
      69              :   ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode,
      70              :   std::function<void (Usage, Definition, Namespace)> insert_segment_resolution,
      71              :   std::vector<Error> &collect_errors, NodeId starting_point_id)
      72              : 
      73              : {
      74        25957 :   auto starting_point = stack.dfs_node (stack.root, starting_point_id);
      75              : 
      76              :   // We may have a prelude, but haven't visited it yet and thus it's not in
      77              :   // our nodes
      78        25957 :   if (!starting_point)
      79            0 :     return tl::nullopt;
      80              : 
      81        25957 :   return NameResolutionContext::resolve_path (stack, path, mode,
      82              :                                               insert_segment_resolution,
      83        25957 :                                               collect_errors, *starting_point);
      84              : }
      85              : 
      86              : template <Namespace N>
      87              : tl::optional<Rib::Definition>
      88       329166 : NameResolutionContext::resolve_path (
      89              :   ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode,
      90              :   std::function<void (Usage, Definition, Namespace)> insert_segment_resolution,
      91              :   std::vector<Error> &collect_errors,
      92              :   std::reference_wrapper<typename ForeverStack<N>::Node> starting_point)
      93              : {
      94       329166 :   bool can_descend = true;
      95              : 
      96       329166 :   rust_debug ("resolving %s", path.as_string ().c_str ());
      97              : 
      98       329166 :   if (auto lang_item = path.get_lang_prefix ())
      99              :     {
     100              :       NodeId seg_id
     101         1208 :         = Analysis::Mappings::get ().get_lang_item_node (lang_item->first);
     102              : 
     103         1208 :       insert_segment_resolution (Usage (lang_item->second), Definition (seg_id),
     104              :                                  N);
     105              : 
     106         1208 :       if (path.get_segments ().empty ())
     107         1208 :         return Rib::Definition::NonShadowable (seg_id);
     108              : 
     109            0 :       auto new_start = stack.dfs_node (stack.root, seg_id);
     110            0 :       rust_assert (new_start.has_value ());
     111            0 :       starting_point = new_start.value ();
     112              : 
     113            0 :       can_descend = false;
     114              :     }
     115              :   else
     116              :     {
     117       327958 :       switch (mode)
     118              :         {
     119              :         case ResolutionMode::Normal:
     120              :           break; // default
     121          952 :         case ResolutionMode::FromRoot:
     122          952 :           starting_point = stack.root;
     123          952 :           break;
     124         1475 :         case ResolutionMode::FromExtern:
     125         1475 :           starting_point = stack.extern_prelude;
     126         1475 :           break;
     127            0 :         default:
     128            0 :           rust_unreachable ();
     129              :         }
     130              :     }
     131              : 
     132       327958 :   if (path.get_segments ().empty ())
     133            2 :     return Rib::Definition::NonShadowable (starting_point.get ().id);
     134              : 
     135       327956 :   auto &segments = path.get_segments ();
     136              : 
     137              :   // if there's only one segment, we just use `get`
     138       655912 :   if (can_descend && segments.size () == 1)
     139              :     {
     140       247161 :       auto &seg = segments.front ();
     141              : 
     142       247161 :       tl::optional<Rib::Definition> res
     143       988644 :         = stack.get (starting_point.get (), seg.name);
     144              : 
     145       247161 :       if (!res)
     146       109358 :         res = stack.get_lang_prelude (seg.name);
     147              : 
     148       127600 :       if (N == Namespace::Types && !res)
     149              :         {
     150          708 :           if (seg.is_crate_path_seg ())
     151              :             {
     152          266 :               insert_segment_resolution (Usage (seg.node_id),
     153          266 :                                          Definition (stack.root.id), N);
     154              :               // TODO: does NonShadowable matter?
     155          266 :               return Rib::Definition::NonShadowable (stack.root.id);
     156              :             }
     157          442 :           else if (seg.is_lower_self_seg ())
     158              :             {
     159            5 :               NodeId id = stack.find_closest_module (starting_point.get ()).id;
     160            5 :               insert_segment_resolution (Usage (seg.node_id), Definition (id),
     161              :                                          N);
     162              :               // TODO: does NonShadowable matter?
     163            5 :               return Rib::Definition::NonShadowable (id);
     164              :             }
     165          437 :           else if (seg.is_super_path_seg ())
     166              :             {
     167              :               auto &closest_module
     168          273 :                 = stack.find_closest_module (starting_point.get ());
     169          273 :               if (closest_module.is_root ())
     170              :                 {
     171            0 :                   rust_error_at (seg.locus, ErrorCode::E0433,
     172              :                                  "too many leading %<super%> keywords");
     173            0 :                   return tl::nullopt;
     174              :                 }
     175              : 
     176          273 :               NodeId id
     177          273 :                 = stack.find_closest_module (closest_module.parent.value ()).id;
     178          273 :               insert_segment_resolution (Usage (seg.node_id), Definition (id),
     179              :                                          N);
     180              :               // TODO: does NonShadowable matter?
     181          273 :               return Rib::Definition::NonShadowable (id);
     182              :             }
     183              :         }
     184              : 
     185              :       // FIXME: Is the NS to insert_segment_resolution valid?
     186       246617 :       if (res && !res->is_ambiguous ())
     187       245472 :         insert_segment_resolution (Usage (seg.node_id),
     188       245472 :                                    Definition (res->get_node_id ()), N);
     189       246617 :       return res;
     190       247161 :     }
     191              : 
     192        80795 :   auto iterator = segments.begin ();
     193        80795 :   if (can_descend)
     194              :     {
     195        80795 :       if (auto res = stack.find_starting_point (segments, starting_point,
     196              :                                                 insert_segment_resolution,
     197              :                                                 collect_errors))
     198        80793 :         iterator = *res;
     199              :       else
     200            2 :         return tl::nullopt;
     201              : 
     202              :       // if find_starting_point used all segments, return early
     203        80793 :       if (iterator == segments.end ())
     204              :         {
     205              :           if (N == Namespace::Types)
     206            6 :             return Rib::Definition::NonShadowable (starting_point.get ().id);
     207              :           else
     208            0 :             return tl::nullopt;
     209              :         }
     210              :     }
     211              : 
     212              :   // We do the first part of path resolution exclusively in the types NS - this
     213              :   // gives us a node in which to resolve the last segment of the path.
     214              : 
     215              :   // nodes are shared between stacks
     216        80787 :   auto node
     217        80787 :     = resolve_segments (types, starting_point.get (), segments, iterator,
     218              :                         insert_segment_resolution, collect_errors);
     219              : 
     220        80787 :   if (!node)
     221        22564 :     return tl::nullopt;
     222              : 
     223              :   // This node now represents the Node which *should* contain the definition
     224              :   // used by the last segment.
     225        58223 :   auto &final_node = node.value ();
     226              : 
     227              :   // leave resolution within impl blocks to type checker
     228        58223 :   if (final_node.rib (N).kind == Rib::Kind::TraitOrImpl)
     229            0 :     return tl::nullopt;
     230              : 
     231        58223 :   auto &seg = segments.back ();
     232        58223 :   std::string seg_name = seg.name;
     233              : 
     234        58223 :   tl::optional<Rib::Definition> res
     235              :     = resolve_final_segment (stack, final_node, seg_name,
     236              :                              seg.is_lower_self_seg ());
     237              :   // Ok we didn't find it in the rib, Lets try the prelude...
     238        58223 :   if (!res)
     239        35045 :     res = stack.get_lang_prelude (seg_name);
     240              : 
     241        58223 :   if (res && !res->is_ambiguous ())
     242        23180 :     insert_segment_resolution (Usage (seg.node_id),
     243        23180 :                                Definition (res->get_node_id ()), N);
     244              : 
     245        58223 :   return res;
     246        58223 : }
     247              : 
     248              : template <Namespace N>
     249              : tl::optional<typename ForeverStack<N>::Node &>
     250        80787 : NameResolutionContext::resolve_segments (
     251              :   ForeverStack<N> &stack, typename ForeverStack<N>::Node &starting_point,
     252              :   const std::vector<ResolutionPath::Segment> &segments,
     253              :   typename ForeverStack<N>::SegIterator iterator,
     254              :   std::function<void (Usage, Definition, Namespace)> insert_segment_resolution,
     255              :   std::vector<Error> &collect_errors)
     256              : {
     257        80787 :   auto *current_node = &starting_point;
     258       167195 :   for (; !is_last (iterator, segments); iterator++)
     259              :     {
     260        86408 :       auto &seg = *iterator;
     261              : 
     262       172816 :       std::string str = seg.name;
     263              : 
     264              :       // check that we don't encounter *any* leading keywords afterwards
     265        86408 :       if (check_leading_kw_at_start (collect_errors, seg,
     266        86408 :                                      seg.is_crate_path_seg ()
     267        86408 :                                        || seg.is_super_path_seg ()
     268        86401 :                                        || seg.is_lower_self_seg ()))
     269           10 :         return tl::nullopt;
     270              : 
     271        86398 :       tl::optional<std::reference_wrapper<typename ForeverStack<N>::Node>> child
     272              :         = tl::nullopt;
     273              : 
     274              :       /*
     275              :        * On every iteration this loop either
     276              :        *
     277              :        * 1. terminates
     278              :        *
     279              :        * 2. decreases the depth of the node pointed to by current_node until
     280              :        *    current_node reaches the root
     281              :        *
     282              :        * 3. If the root node is reached, and we were not able to resolve the
     283              :        *    segment, we search the prelude rib for the segment, by setting
     284              :        *    current_node to point to the prelude, and toggling the
     285              :        *    searched_prelude boolean to true. If current_node is the prelude
     286              :        *    rib, and searched_prelude is true, we will exit.
     287              :        *
     288              :        * This ensures termination.
     289              :        *
     290              :        */
     291        86398 :       bool searched_prelude = false;
     292        86270 :       while (true)
     293              :         {
     294       198306 :           if (is_start (iterator, segments)
     295       315588 :               && current_node->rib (N).kind == Rib::Kind::TraitOrImpl)
     296              :             {
     297              :               // we can't reference associated types/functions like this
     298        17728 :               current_node = &current_node->parent.value ();
     299        30464 :               continue;
     300              :             }
     301              : 
     302              :           // may set the value of child
     303      3134703 :           for (auto &kv : current_node->children)
     304              :             {
     305      3029620 :               auto &link = kv.first;
     306              : 
     307      6059240 :               if (link.path.map_or (
     308      1004144 :                     [&str] (Identifier path) {
     309      1004144 :                       auto &path_str = path.as_string ();
     310      1004144 :                       return str == path_str;
     311              :                     },
     312      3029620 :                     false))
     313              :                 {
     314       220617 :                   child = kv.second;
     315              :                   break;
     316              :                 }
     317              :             }
     318              : 
     319       162850 :           if (child.has_value ())
     320              :             {
     321              :               break;
     322              :             }
     323              : 
     324       105083 :           auto rib_lookup = current_node->rib (N).get (seg.name);
     325       105083 :           if (rib_lookup && !rib_lookup->is_ambiguous ())
     326              :             {
     327        14461 :               if (Analysis::Mappings::get ()
     328        14461 :                     .lookup_glob_container (rib_lookup->get_node_id ())
     329        14461 :                     .has_value ())
     330              :                 {
     331         6077 :                   NodeId leaf_module
     332         6077 :                     = stack.find_leaf_definition (rib_lookup->get_node_id ())
     333         6077 :                         .value_or (Definition (rib_lookup->get_node_id ()))
     334              :                         .id;
     335              : 
     336         6077 :                   if (auto new_child = stack.dfs_node (stack.root, leaf_module))
     337              :                     {
     338         6077 :                       child = new_child.value ();
     339         6077 :                       break;
     340              :                     }
     341              :                   else
     342              :                     {
     343            0 :                       return tl::nullopt;
     344              :                     }
     345              :                 }
     346              :               else
     347              :                 {
     348              :                   // FIXME: Resolve segments always resolves in the Types NS
     349              :                   // correct? If so, we should remove the template parameter for
     350              :                   // this function - and use NS::Types directly here instead of
     351              :                   // N
     352         8384 :                   insert_segment_resolution (Usage (seg.node_id),
     353         8384 :                                              Definition (
     354              :                                                rib_lookup->get_node_id ()),
     355              :                                              N);
     356              : 
     357         8384 :                   return tl::nullopt;
     358              :                 }
     359              :             }
     360              : 
     361        12736 :           if (!searched_prelude
     362       156288 :               && should_search_prelude<N> (current_node, iterator, segments))
     363              :             {
     364        12736 :               searched_prelude = true;
     365        12736 :               current_node = &stack.lang_prelude;
     366              :               continue;
     367              :             }
     368              : 
     369        77886 :           if (!is_start (iterator, segments)
     370        75934 :               || current_node->rib (N).kind == Rib::Kind::Module
     371       153820 :               || current_node->is_prelude ())
     372              :             {
     373        14170 :               return tl::nullopt;
     374              :             }
     375              : 
     376        63716 :           current_node = &current_node->parent.value ();
     377              :         }
     378              : 
     379              :       // if child didn't point to a value
     380              :       // the while loop above would have returned or kept looping
     381        63844 :       current_node = &child->get ();
     382        63844 :       insert_segment_resolution (Usage (seg.node_id),
     383        63844 :                                  Definition (current_node->id), N);
     384              :     }
     385              : 
     386        58223 :   return *current_node;
     387              : }
     388              : 
     389              : template <>
     390              : inline tl::optional<Rib::Definition>
     391        23691 : NameResolutionContext::resolve_final_segment (
     392              :   ForeverStack<Namespace::Types> &stack,
     393              :   typename ForeverStack<Namespace::Types>::Node &final_node,
     394              :   std::string &seg_name, bool is_lower_self)
     395              : {
     396        23691 :   if (is_lower_self)
     397           95 :     return Rib::Definition::NonShadowable (final_node.id);
     398              :   else
     399        23596 :     return final_node.rib_types.get (seg_name);
     400              : }
     401              : 
     402              : template <Namespace N>
     403              : tl::optional<Rib::Definition>
     404        34532 : NameResolutionContext::resolve_final_segment (
     405              :   ForeverStack<N> &stack, typename ForeverStack<N>::Node &final_node,
     406              :   std::string &seg_name, bool is_lower_self)
     407              : {
     408        34532 :   return final_node.rib (N).get (seg_name);
     409              : }
     410              : 
     411              : } // namespace Resolver2_0
     412              : } // namespace Rust
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.