LCOV - code coverage report
Current view: top level - gcc/rust/hir/tree - rust-hir-pattern-abstract.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 88.4 % 155 137
Test Date: 2026-08-22 16:33:35 Functions: 100.0 % 8 8
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 "rust-hir-pattern-abstract.h"
      20              : #include "rust-hir-pattern.h"
      21              : #include "rust-hir-item.h"
      22              : #include "optional.h"
      23              : #include "rust-tyty.h"
      24              : #include "rust-hir-type-check.h"
      25              : namespace Rust {
      26              : namespace HIR {
      27              : 
      28              : static bool
      29           43 : is_refutable_with_lookup (Pattern &pattern)
      30              : {
      31           43 :   auto context = Resolver::TypeCheckContext::get ();
      32           43 :   HirId hir_id = pattern.get_mappings ().get_hirid ();
      33           43 :   if (hir_id)
      34              :     {
      35           43 :       TyTy::BaseType *ty = nullptr;
      36           43 :       if (context->lookup_type (hir_id, &ty))
      37              :         {
      38           43 :           if (pattern.is_refutable (*ty))
      39            4 :             return true;
      40              :         }
      41              :       else
      42              :         {
      43            0 :           rust_internal_error_at (
      44            0 :             pattern.get_locus (),
      45              :             "failed to lookup hir item during refutability checks");
      46              :           return true;
      47              :         }
      48              :     }
      49              :   return false;
      50              : }
      51              : 
      52              : bool
      53            2 : PathPattern::is_refutable (const TyTy::BaseType &scrutinee) const
      54              : {
      55            2 :   rust_assert (kind != Kind::LangItem);
      56              : 
      57            2 :   auto &mappings = Analysis::Mappings::get ();
      58            2 :   HirId hir_id = get_final_segment ().get_mappings ().get_hirid ();
      59            2 :   if (hir_id)
      60              :     {
      61            2 :       auto item = mappings.lookup_hir_item (hir_id);
      62            2 :       if (item && item.value ()->get_item_kind () == Item::ItemKind::Constant)
      63              :         {
      64            0 :           return true;
      65              :         }
      66              :       else
      67              :         {
      68            2 :           rust_internal_error_at (
      69            2 :             get_locus (),
      70              :             "failed to lookup hir item during refutability checks");
      71              :           return true;
      72              :         }
      73              :     }
      74              : 
      75              :   // A path pattern is irrefutable if it corresponds to an enum with one variant
      76            0 :   if (scrutinee.get_kind () == TyTy::TypeKind::ADT)
      77              :     {
      78            0 :       const auto &adt = static_cast<const TyTy::ADTType &> (scrutinee);
      79            0 :       if (adt.is_enum ())
      80              :         {
      81            0 :           return adt.number_of_variants () > 1;
      82              :         }
      83              :     }
      84              :   // cannot have a Path that is neither a constant or an enum-like ADT
      85            0 :   rust_unreachable ();
      86              : }
      87              : 
      88              : bool
      89            7 : SlicePattern::is_refutable (const TyTy::BaseType &scrutinee) const
      90              : {
      91              :   // A slice pattern is refutable if the scrutinee is a dynamic slice,
      92              :   // and the pattern contains anything other than just a rest pattern
      93            7 :   if (scrutinee.get_kind () == TyTy::TypeKind::SLICE)
      94            1 :     if (items->get_item_type () == SlicePatternItems::ItemType::HAS_REST)
      95              :       {
      96            1 :         const auto &items_has_rest
      97            1 :           = static_cast<const SlicePatternItemsHasRest &> (*items);
      98            1 :         if (items_has_rest.get_lower_patterns ().empty ()
      99            1 :             && items_has_rest.get_upper_patterns ().empty ())
     100              :           return false;
     101              :       }
     102              : 
     103            6 :   rust_assert (scrutinee.get_kind () == TyTy::TypeKind::ARRAY);
     104            6 :   const auto &arr = static_cast<const TyTy::ArrayType &> (scrutinee);
     105            6 :   switch (items->get_item_type ())
     106              :     {
     107            2 :     case SlicePatternItems::ItemType::NO_REST:
     108            2 :       {
     109            2 :         const auto &items_no_rest
     110            2 :           = static_cast<const SlicePatternItemsNoRest &> (*items);
     111            2 :         const auto *capacity_ty = arr.get_capacity ();
     112            2 :         rust_assert (capacity_ty->get_kind () == TyTy::TypeKind::CONST);
     113            2 :         auto *capacity_const = capacity_ty->as_const_type ();
     114            2 :         rust_assert (capacity_const->const_kind ()
     115              :                      == TyTy::BaseConstType::ConstKind::Value);
     116            2 :         auto &capacity_value
     117              :           = *static_cast<const TyTy::ConstValueType *> (capacity_const);
     118            2 :         auto cap_tree = capacity_value.get_value ();
     119            2 :         rust_assert (!error_operand_p (cap_tree));
     120            2 :         size_t cap = (size_t) wi::to_wide (cap_tree).to_uhwi ();
     121              : 
     122            2 :         if (items_no_rest.get_patterns ().size () != cap)
     123              :           return true;
     124            8 :         for (const auto &pattern : items_no_rest.get_patterns ())
     125            6 :           if (is_refutable_with_lookup (*pattern))
     126              :             {
     127            7 :               return true;
     128              :             }
     129              :         break;
     130              :       }
     131            4 :     case SlicePatternItems::ItemType::HAS_REST:
     132            4 :       {
     133            4 :         const auto &items_has_rest
     134            4 :           = static_cast<const SlicePatternItemsHasRest &> (*items);
     135            4 :         size_t bound_patterns_count
     136            4 :           = items_has_rest.get_lower_patterns ().size ()
     137            4 :             + items_has_rest.get_upper_patterns ().size ();
     138            4 :         auto *capacity_ty = arr.get_capacity ();
     139            4 :         rust_assert (capacity_ty->get_kind () == TyTy::TypeKind::CONST);
     140            4 :         auto *capacity_const = capacity_ty->as_const_type ();
     141            4 :         rust_assert (capacity_const->const_kind ()
     142              :                      == TyTy::BaseConstType::ConstKind::Value);
     143            4 :         auto &capacity_value
     144              :           = *static_cast<const TyTy::ConstValueType *> (capacity_const);
     145            4 :         auto cap_tree = capacity_value.get_value ();
     146            4 :         rust_assert (!error_operand_p (cap_tree));
     147            4 :         size_t cap = (size_t) wi::to_wide (cap_tree).to_uhwi ();
     148              : 
     149            4 :         if (bound_patterns_count > cap)
     150              :           return true;
     151            8 :         for (const auto &pattern : items_has_rest.get_lower_patterns ())
     152            4 :           if (is_refutable_with_lookup (*pattern))
     153              :             {
     154            7 :               return true;
     155              :             }
     156            8 :         for (const auto &pattern : items_has_rest.get_upper_patterns ())
     157            4 :           if (is_refutable_with_lookup (*pattern))
     158              :             {
     159            7 :               return true;
     160              :             }
     161              :         break;
     162              :       }
     163              :     }
     164              :   return false;
     165              : }
     166              : 
     167              : bool
     168           23 : TupleStructPattern::is_refutable (const TyTy::BaseType &scrutinee) const
     169              : {
     170              :   // A tuple struct pattern corresponding to an enum with multiple variants is
     171              :   // always refutable
     172           23 :   if (scrutinee.get_kind () == TyTy::TypeKind::ADT)
     173              :     {
     174           23 :       const auto &adt = static_cast<const TyTy::ADTType &> (scrutinee);
     175           31 :       if (adt.is_enum () && adt.number_of_variants () > 1)
     176              :         {
     177              :           return true;
     178              :         }
     179              :     }
     180              :   // We need to also check the refutability of each item's pattern in the tuple
     181              :   // struct
     182           21 :   switch (items->get_item_type ())
     183              :     {
     184           15 :     case TupleStructItems::ItemType::NO_REST:
     185           17 :       for (const auto &pattern :
     186           32 :            static_cast<TupleStructItemsNoRest &> (*items).get_patterns ())
     187           19 :         if (is_refutable_with_lookup (*pattern))
     188              :           {
     189           23 :             return true;
     190              :           }
     191              :       break;
     192            6 :     case TupleStructItems::ItemType::HAS_REST:
     193            6 :       auto &items_has_rest = static_cast<TupleStructItemsHasRest &> (*items);
     194           10 :       for (const auto &pattern : items_has_rest.get_lower_patterns ())
     195            6 :         if (is_refutable_with_lookup (*pattern))
     196              :           {
     197           23 :             return true;
     198              :           }
     199            8 :       for (const auto &pattern : items_has_rest.get_upper_patterns ())
     200            4 :         if (is_refutable_with_lookup (*pattern))
     201              :           {
     202           23 :             return true;
     203              :           }
     204              :       break;
     205              :     }
     206              :   return false;
     207              : }
     208              : 
     209              : bool
     210          319 : TuplePattern::is_refutable (const TyTy::BaseType &scrutinee) const
     211              : {
     212          319 :   const auto *destructured = scrutinee.destructure ();
     213          319 :   rust_assert (destructured->get_kind () == TyTy::TypeKind::TUPLE);
     214          319 :   const auto &tup = static_cast<const TyTy::TupleType &> (*destructured);
     215              : 
     216          319 :   switch (items->get_item_type ())
     217              :     {
     218          309 :     case TuplePatternItems::ItemType::NO_REST:
     219          309 :       {
     220          309 :         auto &no_rest = static_cast<TuplePatternItemsNoRest &> (*items);
     221          309 :         const auto &patterns = no_rest.get_patterns ();
     222          933 :         for (size_t i = 0; i < patterns.size (); i++)
     223          628 :           if (patterns[i]->is_refutable (*tup.get_field (i)))
     224              :             return true;
     225              :         break;
     226              :       }
     227           10 :     case TuplePatternItems::ItemType::HAS_REST:
     228           10 :       {
     229           10 :         auto &has_rest = static_cast<TuplePatternItemsHasRest &> (*items);
     230           10 :         const auto &lower = has_rest.get_lower_patterns ();
     231           10 :         const auto &upper = has_rest.get_upper_patterns ();
     232           16 :         for (size_t i = 0; i < lower.size (); i++)
     233            6 :           if (lower[i]->is_refutable (*tup.get_field (i)))
     234              :             return true;
     235           10 :         size_t base = tup.get_fields ().size () - upper.size ();
     236           14 :         for (size_t i = 0; i < upper.size (); i++)
     237            6 :           if (upper[i]->is_refutable (*tup.get_field (base + i)))
     238              :             return true;
     239              :         break;
     240              :       }
     241              :     }
     242              :   return false;
     243              : }
     244              : bool
     245        19117 : IdentifierPattern::is_refutable (const TyTy::BaseType &scrutinee) const
     246              : {
     247        19117 :   if (has_subpattern ())
     248              :     {
     249           13 :       auto context = Resolver::TypeCheckContext::get ();
     250           13 :       HirId hir_id = subpattern->get_mappings ().get_hirid ();
     251           13 :       if (hir_id)
     252              :         {
     253           13 :           TyTy::BaseType *ty = nullptr;
     254           13 :           if (context->lookup_type (hir_id, &ty))
     255              :             {
     256           13 :               return subpattern->is_refutable (*ty);
     257              :             }
     258              :           else
     259              :             {
     260            0 :               rust_internal_error_at (
     261            0 :                 get_locus (),
     262              :                 "failed to lookup hir item during refutability checks");
     263              :               return true;
     264              :             }
     265              :         }
     266              :     }
     267              : 
     268              :   return false;
     269              : }
     270              : 
     271              : bool
     272           19 : ReferencePattern::is_refutable (const TyTy::BaseType &scrutinee) const
     273              : {
     274           19 :   const auto *inner = scrutinee.destructure ();
     275              : 
     276           19 :   rust_assert (inner->get_kind () == TyTy::TypeKind::REF);
     277           19 :   const auto &ref = static_cast<const TyTy::ReferenceType &> (*inner);
     278           19 :   return pattern->is_refutable (*ref.get_base ());
     279              : }
     280              : 
     281              : bool
     282           11 : StructPattern::is_refutable (const TyTy::BaseType &scrutinee) const
     283              : {
     284           11 :   const auto *inner = scrutinee.destructure ();
     285           11 :   rust_assert (inner->get_kind () == TyTy::TypeKind::ADT);
     286           11 :   const auto &adt = static_cast<const TyTy::ADTType &> (*inner);
     287           11 :   rust_assert (!adt.is_enum ());
     288           11 :   TyTy::VariantDef *variant = adt.get_variants ().at (0);
     289              : 
     290           26 :   for (const auto &field : elems.get_struct_pattern_fields ())
     291              :     {
     292           19 :       switch (field->get_item_type ())
     293              :         {
     294            0 :         case StructPatternField::ItemType::TUPLE_PAT:
     295            0 :           {
     296            0 :             const auto &tuple_field
     297            0 :               = static_cast<const StructPatternFieldTuplePat &> (*field);
     298            0 :             TyTy::StructFieldType *field_ty
     299            0 :               = variant->get_field_at_index (tuple_field.get_index ());
     300            0 :             if (tuple_field.get_tuple_pattern ().is_refutable (
     301            0 :                   *field_ty->get_field_type ()))
     302              :               return true;
     303              :             break;
     304              :           }
     305           13 :         case StructPatternField::ItemType::IDENT_PAT:
     306           13 :           {
     307           13 :             const auto &ident_field
     308           13 :               = static_cast<const StructPatternFieldIdentPat &> (*field);
     309           13 :             TyTy::StructFieldType *field_ty = nullptr;
     310           13 :             bool found = variant->lookup_field (
     311           13 :               ident_field.get_identifier ().as_string (), &field_ty, nullptr);
     312           13 :             rust_assert (found);
     313           13 :             if (ident_field.get_pattern ().is_refutable (
     314           13 :                   *field_ty->get_field_type ()))
     315            4 :               return true;
     316            9 :             break;
     317              :           }
     318              :         case StructPatternField::ItemType::IDENT:
     319              :           break;
     320              :         }
     321              :     }
     322              :   return false;
     323              : }
     324              : } // namespace HIR
     325              : 
     326              : } // 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.