LCOV - code coverage report
Current view: top level - gcc/rust/resolve - rust-ast-resolve-pattern.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 90.3 % 175 158
Test Date: 2024-12-28 13:16:48 Functions: 93.3 % 15 14
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : // Copyright (C) 2020-2024 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 "rust-ast-resolve-pattern.h"
      20                 :             : #include "rust-ast-resolve-path.h"
      21                 :             : 
      22                 :             : namespace Rust {
      23                 :             : namespace Resolver {
      24                 :             : 
      25                 :             : void
      26                 :       13431 : PatternDeclaration::go (AST::Pattern &pattern, Rib::ItemType type)
      27                 :             : {
      28                 :       13431 :   std::vector<PatternBinding> bindings
      29                 :       26862 :     = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())};
      30                 :       13431 :   PatternDeclaration::go (pattern, type, bindings);
      31                 :       13431 : }
      32                 :             : 
      33                 :             : void
      34                 :       17512 : PatternDeclaration::go (AST::Pattern &pattern, Rib::ItemType type,
      35                 :             :                         std::vector<PatternBinding> &bindings)
      36                 :             : {
      37                 :       17512 :   PatternDeclaration resolver (bindings, type);
      38                 :       17512 :   pattern.accept_vis (resolver);
      39                 :             : 
      40                 :       17526 :   for (auto &map_entry : resolver.missing_bindings)
      41                 :             :     {
      42                 :          14 :       auto ident = map_entry.first; // key
      43                 :          14 :       auto info = map_entry.second; // value
      44                 :             : 
      45                 :          14 :       rust_error_at (info.get_locus (), ErrorCode::E0408,
      46                 :             :                      "variable '%s' is not bound in all patterns",
      47                 :          14 :                      ident.as_string ().c_str ());
      48                 :          14 :     }
      49                 :             : 
      50                 :       17519 :   for (auto &map_entry : resolver.inconsistent_bindings)
      51                 :             :     {
      52                 :           7 :       auto ident = map_entry.first; // key
      53                 :           7 :       auto info = map_entry.second; // value
      54                 :             : 
      55                 :           7 :       rust_error_at (
      56                 :             :         info.get_locus (), ErrorCode::E0409,
      57                 :             :         "variable '%s' is bound inconsistently across pattern alternatives",
      58                 :           7 :         ident.as_string ().c_str ());
      59                 :           7 :     }
      60                 :       17512 : }
      61                 :             : 
      62                 :             : void
      63                 :       17232 : PatternDeclaration::visit (AST::IdentifierPattern &pattern)
      64                 :             : {
      65                 :       17232 :   Mutability mut = pattern.get_is_mut () ? Mutability::Mut : Mutability::Imm;
      66                 :       17232 :   add_new_binding (pattern.get_ident (), pattern.get_node_id (),
      67                 :       17232 :                    BindingTypeInfo (mut, pattern.get_is_ref (),
      68                 :       17232 :                                     pattern.get_locus ()));
      69                 :       17232 : }
      70                 :             : 
      71                 :             : void
      72                 :          43 : PatternDeclaration::visit (AST::GroupedPattern &pattern)
      73                 :             : {
      74                 :          43 :   pattern.get_pattern_in_parens ().accept_vis (*this);
      75                 :          43 : }
      76                 :             : 
      77                 :             : void
      78                 :          28 : PatternDeclaration::visit (AST::ReferencePattern &pattern)
      79                 :             : {
      80                 :          28 :   pattern.get_referenced_pattern ().accept_vis (*this);
      81                 :          28 : }
      82                 :             : 
      83                 :             : void
      84                 :         128 : PatternDeclaration::visit (AST::PathInExpression &pattern)
      85                 :             : {
      86                 :         128 :   ResolvePath::go (pattern);
      87                 :         128 : }
      88                 :             : 
      89                 :             : void
      90                 :         191 : PatternDeclaration::visit (AST::TupleStructPattern &pattern)
      91                 :             : {
      92                 :         191 :   ResolvePath::go (pattern.get_path ());
      93                 :             : 
      94                 :         191 :   AST::TupleStructItems &items = pattern.get_items ();
      95                 :         191 :   switch (items.get_item_type ())
      96                 :             :     {
      97                 :           0 :       case AST::TupleStructItems::RANGE: {
      98                 :             :         // TODO
      99                 :           0 :         rust_unreachable ();
     100                 :             :       }
     101                 :         191 :       break;
     102                 :             : 
     103                 :         191 :       case AST::TupleStructItems::NO_RANGE: {
     104                 :         191 :         auto &items_no_range
     105                 :             :           = static_cast<AST::TupleStructItemsNoRange &> (items);
     106                 :             : 
     107                 :         432 :         for (auto &inner_pattern : items_no_range.get_patterns ())
     108                 :             :           {
     109                 :         241 :             inner_pattern->accept_vis (*this);
     110                 :             :           }
     111                 :             :       }
     112                 :             :       break;
     113                 :             :     }
     114                 :         191 : }
     115                 :             : 
     116                 :             : void
     117                 :          35 : PatternDeclaration::visit (AST::StructPattern &pattern)
     118                 :             : {
     119                 :          35 :   ResolvePath::go (pattern.get_path ());
     120                 :             : 
     121                 :          35 :   auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
     122                 :         100 :   for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
     123                 :             :     {
     124                 :          65 :       switch (field->get_item_type ())
     125                 :             :         {
     126                 :           1 :           case AST::StructPatternField::ItemType::TUPLE_PAT: {
     127                 :           1 :             AST::StructPatternFieldTuplePat &tuple
     128                 :           1 :               = static_cast<AST::StructPatternFieldTuplePat &> (*field);
     129                 :             : 
     130                 :           1 :             tuple.get_index_pattern ().accept_vis (*this);
     131                 :             :           }
     132                 :           1 :           break;
     133                 :             : 
     134                 :           1 :           case AST::StructPatternField::ItemType::IDENT_PAT: {
     135                 :           1 :             AST::StructPatternFieldIdentPat &ident
     136                 :           1 :               = static_cast<AST::StructPatternFieldIdentPat &> (*field);
     137                 :             : 
     138                 :           1 :             ident.get_ident_pattern ().accept_vis (*this);
     139                 :             :           }
     140                 :           1 :           break;
     141                 :             : 
     142                 :          63 :           case AST::StructPatternField::ItemType::IDENT: {
     143                 :          63 :             auto &ident = static_cast<AST::StructPatternFieldIdent &> (*field);
     144                 :             : 
     145                 :          63 :             Mutability mut
     146                 :          63 :               = ident.is_mut () ? Mutability::Mut : Mutability::Imm;
     147                 :             : 
     148                 :          63 :             add_new_binding (ident.get_identifier (), ident.get_node_id (),
     149                 :          63 :                              BindingTypeInfo (mut, ident.is_ref (),
     150                 :          63 :                                               ident.get_locus ()));
     151                 :             :           }
     152                 :          63 :           break;
     153                 :             :         }
     154                 :             :     }
     155                 :          35 : }
     156                 :             : 
     157                 :             : void
     158                 :         164 : PatternDeclaration::visit (AST::TuplePattern &pattern)
     159                 :             : {
     160                 :         164 :   auto &items = pattern.get_items ();
     161                 :         164 :   switch (items.get_pattern_type ())
     162                 :             :     {
     163                 :         164 :       case AST::TuplePatternItems::TuplePatternItemType::MULTIPLE: {
     164                 :         164 :         auto &ref = static_cast<AST::TuplePatternItemsMultiple &> (
     165                 :         164 :           pattern.get_items ());
     166                 :             : 
     167                 :         509 :         for (auto &p : ref.get_patterns ())
     168                 :         345 :           p->accept_vis (*this);
     169                 :             :       }
     170                 :             :       break;
     171                 :             : 
     172                 :           0 :       case AST::TuplePatternItems::TuplePatternItemType::RANGED: {
     173                 :           0 :         auto &ref
     174                 :           0 :           = static_cast<AST::TuplePatternItemsRanged &> (pattern.get_items ());
     175                 :             : 
     176                 :           0 :         for (auto &p : ref.get_lower_patterns ())
     177                 :           0 :           p->accept_vis (*this);
     178                 :           0 :         for (auto &p : ref.get_upper_patterns ())
     179                 :           0 :           p->accept_vis (*this);
     180                 :             :       }
     181                 :             :       break;
     182                 :             :     }
     183                 :         164 : }
     184                 :             : 
     185                 :             : void
     186                 :          45 : PatternDeclaration::visit (AST::AltPattern &pattern)
     187                 :             : {
     188                 :             :   // push a new set of 'Or' bindings to the stack. Accounts for the
     189                 :             :   // alternatives. e.g. in `p_0 | p_1`, bindings to the same identifier between
     190                 :             :   // p_0 and p_1 shouldn't cause an error.
     191                 :          45 :   bindings_with_ctx.push_back (
     192                 :          90 :     PatternBinding (PatternBoundCtx::Or, std::set<Identifier> ()));
     193                 :             : 
     194                 :             :   // This is a hack to avoid creating a separate visitor class for the
     195                 :             :   // consistency checks. We empty out the binding_info_map before each iteration
     196                 :             :   // to separate between the alts' binding_maps. And right after the alt
     197                 :             :   // visit...
     198                 :          45 :   auto tmp_binding_map = binding_info_map;
     199                 :          45 :   binding_info_map.clear ();
     200                 :             : 
     201                 :          45 :   std::vector<BindingMap> alts_binding_maps;
     202                 :             : 
     203                 :         150 :   for (auto &alt : pattern.get_alts ())
     204                 :             :     {
     205                 :             :       // before this visit, the binding_info_map is guaranteed to be empty
     206                 :         105 :       rust_assert (binding_info_map.empty ());
     207                 :             : 
     208                 :             :       // push a new `Product` context to correctly reject multiple bindings
     209                 :             :       // within this single alt.
     210                 :         105 :       bindings_with_ctx.push_back (
     211                 :         210 :         PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ()));
     212                 :             : 
     213                 :         105 :       alt->accept_vis (*this);
     214                 :             : 
     215                 :             :       // ...the binding_info_map is (potentially) populated. We copy it to the
     216                 :             :       // vector, and empty it out to be ready for the next iteration. And after
     217                 :             :       // all the iterations are finished...
     218                 :         105 :       alts_binding_maps.push_back (binding_info_map);
     219                 :         105 :       binding_info_map.clear ();
     220                 :             : 
     221                 :             :       // Remove the last (i.e. `Product`) context and add the bindings from the
     222                 :             :       // visited alt to the one before last (i.e. `Or`). Now (after checking
     223                 :             :       // with the alt internally), the bindings from this alt will reside in the
     224                 :             :       // `Or` context.
     225                 :         105 :       auto last_bound_idents = bindings_with_ctx.back ().idents;
     226                 :         105 :       bindings_with_ctx.pop_back ();
     227                 :             : 
     228                 :         149 :       for (auto &ident : last_bound_idents)
     229                 :             :         {
     230                 :          44 :           bindings_with_ctx.back ().idents.insert (ident);
     231                 :             :         }
     232                 :         105 :     }
     233                 :             : 
     234                 :             :   // Now we can finally check for consistency.
     235                 :          45 :   check_bindings_consistency (alts_binding_maps);
     236                 :             : 
     237                 :             :   // Now we remove the `Or` context we pushed earlier.
     238                 :             :   // e.g. in `(a, (p_0 | p_1), c)`: after finishing up inside the alt pattern,
     239                 :             :   // we return to the tuple (`Product`) context and push the new bindings.
     240                 :          45 :   auto idents = bindings_with_ctx.back ().idents;
     241                 :          45 :   bindings_with_ctx.pop_back ();
     242                 :          89 :   for (auto &ident : idents)
     243                 :          44 :     bindings_with_ctx.back ().idents.insert (ident.as_string ());
     244                 :             : 
     245                 :             :   // ...we repopulate the binding_info_map correctly (the initial bindings
     246                 :             :   // stored in the tmp_binding_map + all the bindings from all the alts)
     247                 :          45 :   binding_info_map = tmp_binding_map;
     248                 :         150 :   for (auto &alt_map : alts_binding_maps)
     249                 :         228 :     for (auto &map_entry : alt_map)
     250                 :         123 :       binding_info_map.insert (map_entry);
     251                 :          45 : }
     252                 :             : 
     253                 :             : void
     254                 :       17295 : PatternDeclaration::add_new_binding (Identifier ident, NodeId node_id,
     255                 :             :                                      BindingTypeInfo info)
     256                 :             : {
     257                 :       17295 :   bool has_binding_ctx = bindings_with_ctx.size () > 0;
     258                 :       17295 :   rust_assert (has_binding_ctx);
     259                 :             : 
     260                 :             :   bool identifier_or_bound = false, identifier_product_bound = false;
     261                 :             : 
     262                 :       34850 :   for (auto binding : bindings_with_ctx)
     263                 :             :     {
     264                 :       17555 :       bool identifier_bound_here
     265                 :       17555 :         = (binding.idents.find (ident) != binding.idents.end ());
     266                 :       17555 :       if (identifier_bound_here)
     267                 :             :         {
     268                 :          66 :           identifier_product_bound |= binding.ctx == PatternBoundCtx::Product;
     269                 :          66 :           identifier_or_bound |= binding.ctx == PatternBoundCtx::Or;
     270                 :             :         }
     271                 :       17555 :     }
     272                 :             : 
     273                 :       17295 :   if (identifier_product_bound)
     274                 :             :     {
     275                 :           8 :       if (type == Rib::ItemType::Param)
     276                 :             :         {
     277                 :           5 :           rust_error_at (info.get_locus (), ErrorCode::E0415,
     278                 :             :                          "identifier '%s' is bound more than once in the "
     279                 :             :                          "same parameter list",
     280                 :           5 :                          ident.as_string ().c_str ());
     281                 :             :         }
     282                 :             :       else
     283                 :             :         {
     284                 :           3 :           rust_error_at (
     285                 :             :             info.get_locus (), ErrorCode::E0416,
     286                 :             :             "identifier '%s' is bound more than once in the same pattern",
     287                 :           3 :             ident.as_string ().c_str ());
     288                 :             :         }
     289                 :             : 
     290                 :           8 :       return;
     291                 :             :     }
     292                 :             : 
     293                 :       17287 :   if (!identifier_or_bound)
     294                 :             :     {
     295                 :       17229 :       bindings_with_ctx.back ().idents.insert (ident);
     296                 :       17229 :       resolver->get_name_scope ().insert (
     297                 :       34458 :         CanonicalPath::new_seg (node_id, ident.as_string ()), node_id,
     298                 :             :         info.get_locus (), type);
     299                 :             :     }
     300                 :             : 
     301                 :       17287 :   binding_info_map.insert ({ident, info});
     302                 :             : }
     303                 :             : 
     304                 :             : // Verifies that all the alts in an AltPattern have the same set of bindings
     305                 :             : // with the same mutability and reference states.
     306                 :             : void
     307                 :          45 : PatternDeclaration::check_bindings_consistency (
     308                 :             :   std::vector<BindingMap> &binding_maps)
     309                 :             : {
     310                 :         150 :   for (size_t i = 0; i < binding_maps.size (); i++)
     311                 :             :     {
     312                 :         105 :       auto &outer_bindings_map = binding_maps[i];
     313                 :             : 
     314                 :         360 :       for (size_t j = 0; j < binding_maps.size (); j++)
     315                 :             :         {
     316                 :             :           // skip comparing the current outer map with itself.
     317                 :         255 :           if (j == i)
     318                 :         105 :             continue;
     319                 :             : 
     320                 :         150 :           auto &inner_bindings_map = binding_maps[j];
     321                 :             : 
     322                 :             :           // iterate over the inner map entries and check if they exist in outer
     323                 :             :           // map
     324                 :         322 :           for (auto map_entry : inner_bindings_map)
     325                 :             :             {
     326                 :         172 :               auto ident = map_entry.first;       // key
     327                 :         172 :               auto inner_info = map_entry.second; // value
     328                 :         172 :               bool ident_is_outer_bound = outer_bindings_map.count (ident);
     329                 :             : 
     330                 :         172 :               if (!ident_is_outer_bound && !missing_bindings.count (ident))
     331                 :          14 :                 missing_bindings.insert ({ident, inner_info});
     332                 :             : 
     333                 :         158 :               else if (outer_bindings_map[ident] != inner_info
     334                 :         158 :                        && !inconsistent_bindings.count (ident))
     335                 :           7 :                 inconsistent_bindings.insert ({ident, inner_info});
     336                 :         172 :             }
     337                 :             :         }
     338                 :             :     }
     339                 :          45 : }
     340                 :             : 
     341                 :             : static void
     342                 :          42 : resolve_range_pattern_bound (AST::RangePatternBound &bound)
     343                 :             : {
     344                 :          42 :   switch (bound.get_bound_type ())
     345                 :             :     {
     346                 :             :     case AST::RangePatternBound::RangePatternBoundType::LITERAL:
     347                 :             :       // Nothing to resolve for a literal.
     348                 :             :       break;
     349                 :             : 
     350                 :          21 :       case AST::RangePatternBound::RangePatternBoundType::PATH: {
     351                 :          21 :         auto &ref = static_cast<AST::RangePatternBoundPath &> (bound);
     352                 :             : 
     353                 :          21 :         ResolvePath::go (ref.get_path ());
     354                 :             :       }
     355                 :          21 :       break;
     356                 :             : 
     357                 :           0 :       case AST::RangePatternBound::RangePatternBoundType::QUALPATH: {
     358                 :           0 :         auto &ref = static_cast<AST::RangePatternBoundQualPath &> (bound);
     359                 :             : 
     360                 :           0 :         ResolvePath::go (ref.get_qualified_path ());
     361                 :             :       }
     362                 :           0 :       break;
     363                 :             :     }
     364                 :          42 : }
     365                 :             : 
     366                 :             : void
     367                 :          21 : PatternDeclaration::visit (AST::RangePattern &pattern)
     368                 :             : {
     369                 :          21 :   resolve_range_pattern_bound (pattern.get_upper_bound ());
     370                 :          21 :   resolve_range_pattern_bound (pattern.get_lower_bound ());
     371                 :          21 : }
     372                 :             : 
     373                 :             : void
     374                 :           0 : PatternDeclaration::visit (AST::SlicePattern &pattern)
     375                 :             : {
     376                 :           0 :   for (auto &p : pattern.get_items ())
     377                 :             :     {
     378                 :           0 :       p->accept_vis (*this);
     379                 :             :     }
     380                 :           0 : }
     381                 :             : 
     382                 :             : } // namespace Resolver
     383                 :             : } // 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.