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