LCOV - code coverage report
Current view: top level - gcc/rust/backend - rust-compile-pattern.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 95.5 % 819 782
Test Date: 2026-07-11 15:47:05 Functions: 100.0 % 25 25
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2020-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-compile-pattern.h"
      20              : #include "rust-compile-drop-builder.h"
      21              : #include "print-tree.h"
      22              : #include "rust-compile-drop.h"
      23              : #include "rust-compile-expr.h"
      24              : #include "rust-compile-resolve-path.h"
      25              : #include "rust-compile-type.h"
      26              : #include "rust-constexpr.h"
      27              : #include "rust-diagnostics.h"
      28              : #include "rust-hir-pattern-abstract.h"
      29              : #include "rust-hir-pattern.h"
      30              : #include "rust-hir-trait-reference.h"
      31              : #include "rust-hir-type-bounds.h"
      32              : #include "rust-lang-item.h"
      33              : #include "rust-system.h"
      34              : #include "rust-tyty.h"
      35              : #include "tree.h"
      36              : 
      37              : namespace Rust {
      38              : namespace Compile {
      39              : 
      40              : void
      41          786 : CompilePatternCheckExpr::visit (HIR::PathInExpression &pattern)
      42              : {
      43              :   // lookup the type
      44          786 :   TyTy::BaseType *lookup = nullptr;
      45          786 :   bool ok
      46          786 :     = ctx->get_tyctx ()->lookup_type (pattern.get_mappings ().get_hirid (),
      47              :                                       &lookup);
      48          786 :   rust_assert (ok);
      49              : 
      50              :   // must be an ADT (?)
      51          786 :   rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
      52          786 :   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
      53              : 
      54              :   // if this isn't an enum, always succeed
      55          786 :   if (!adt->is_enum ())
      56              :     {
      57            2 :       check_expr = boolean_true_node;
      58            2 :       return;
      59              :     }
      60              : 
      61              :   // lookup the variant
      62          784 :   HirId variant_id;
      63          784 :   ok = ctx->get_tyctx ()->lookup_variant_definition (
      64          784 :     pattern.get_mappings ().get_hirid (), &variant_id);
      65          784 :   rust_assert (ok);
      66              : 
      67          784 :   TyTy::VariantDef *variant = nullptr;
      68          784 :   ok = adt->lookup_variant_by_id (variant_id, &variant);
      69          784 :   rust_assert (ok);
      70              : 
      71              :   // find discriminant field of scrutinee
      72          784 :   tree scrutinee_expr_qualifier_expr
      73          784 :     = Backend::struct_field_expression (match_scrutinee_expr, 0,
      74              :                                         pattern.get_locus ());
      75              : 
      76              :   // must be enum
      77          784 :   match_scrutinee_expr = scrutinee_expr_qualifier_expr;
      78              : 
      79          784 :   HIR::Expr &discrim_expr = variant->get_discriminant ();
      80          784 :   tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
      81              : 
      82          784 :   check_expr
      83          784 :     = Backend::comparison_expression (ComparisonOperator::EQUAL,
      84              :                                       match_scrutinee_expr, discrim_expr_node,
      85              :                                       pattern.get_locus ());
      86              : }
      87              : 
      88              : void
      89          406 : CompilePatternCheckExpr::visit (HIR::LiteralPattern &pattern)
      90              : {
      91              :   // Compile the literal
      92          406 :   auto litexpr = std::make_unique<HIR::LiteralExpr> (
      93          812 :     HIR::LiteralExpr (pattern.get_mappings (), pattern.get_literal (),
      94          812 :                       pattern.get_locus (), std::vector<AST::Attribute> ()));
      95          406 :   if (pattern.get_has_minus ())
      96            8 :     litexpr->set_negative ();
      97              : 
      98              :   // Note: Floating point literals are currently accepted but will likely be
      99              :   // forbidden in LiteralPatterns in a future version of Rust.
     100              :   // See: https://github.com/rust-lang/rust/issues/41620
     101              :   // For now, we cannot compile them anyway as CASE_LABEL_EXPR does not support
     102              :   // floating point types.
     103          406 :   if (pattern.get_literal ().get_lit_type () == HIR::Literal::LitType::FLOAT)
     104              :     {
     105            0 :       rust_sorry_at (pattern.get_locus (), "floating-point literal in pattern");
     106              :     }
     107              : 
     108          406 :   tree lit = CompileExpr::Compile (*litexpr, ctx);
     109              : 
     110          406 :   check_expr = Backend::comparison_expression (ComparisonOperator::EQUAL,
     111              :                                                match_scrutinee_expr, lit,
     112          406 :                                                pattern.get_locus ());
     113          406 : }
     114              : 
     115              : static tree
     116           88 : compile_range_pattern_bound (HIR::RangePatternBound &bound,
     117              :                              Analysis::NodeMapping mappings, location_t locus,
     118              :                              Context *ctx)
     119              : {
     120           88 :   tree result = NULL_TREE;
     121           88 :   switch (bound.get_bound_type ())
     122              :     {
     123           67 :     case HIR::RangePatternBound::RangePatternBoundType::LITERAL:
     124           67 :       {
     125           67 :         auto &ref = static_cast<HIR::RangePatternBoundLiteral &> (bound);
     126              : 
     127          201 :         HIR::LiteralExpr litexpr (mappings, ref.get_literal (), locus,
     128           67 :                                   std::vector<AST::Attribute> ());
     129           67 :         if (ref.get_has_minus ())
     130           29 :           litexpr.set_negative ();
     131              : 
     132           67 :         result = CompileExpr::Compile (litexpr, ctx);
     133           67 :       }
     134           67 :       break;
     135              : 
     136           21 :     case HIR::RangePatternBound::RangePatternBoundType::PATH:
     137           21 :       {
     138           21 :         auto &ref = static_cast<HIR::RangePatternBoundPath &> (bound);
     139              : 
     140           21 :         result = ResolvePathRef::Compile (ref.get_path (), ctx);
     141              : 
     142              :         // If the path resolves to a const expression, fold it.
     143           21 :         result = fold_expr (result);
     144              :       }
     145           21 :       break;
     146              : 
     147            0 :     case HIR::RangePatternBound::RangePatternBoundType::QUALPATH:
     148            0 :       {
     149            0 :         auto &ref = static_cast<HIR::RangePatternBoundQualPath &> (bound);
     150              : 
     151            0 :         result = ResolvePathRef::Compile (ref.get_qualified_path (), ctx);
     152              : 
     153              :         // If the path resolves to a const expression, fold it.
     154            0 :         result = fold_expr (result);
     155              :       }
     156              :     }
     157              : 
     158           88 :   return result;
     159              : }
     160              : 
     161              : void
     162           44 : CompilePatternCheckExpr::visit (HIR::RangePattern &pattern)
     163              : {
     164           44 :   tree upper = compile_range_pattern_bound (pattern.get_upper_bound (),
     165           44 :                                             pattern.get_mappings (),
     166           44 :                                             pattern.get_locus (), ctx);
     167          132 :   tree lower = compile_range_pattern_bound (pattern.get_lower_bound (),
     168           44 :                                             pattern.get_mappings (),
     169           44 :                                             pattern.get_locus (), ctx);
     170              : 
     171           44 :   rust_assert (
     172              :     (TREE_CODE (upper) == REAL_CST && TREE_CODE (lower) == REAL_CST)
     173              :     || (TREE_CODE (upper) == INTEGER_CST && TREE_CODE (lower) == INTEGER_CST));
     174              : 
     175           44 :   bool error_E0579 = false;
     176           44 :   if (TREE_CODE (upper) == REAL_CST)
     177              :     {
     178            2 :       const REAL_VALUE_TYPE *upper_r = TREE_REAL_CST_PTR (upper);
     179            2 :       const REAL_VALUE_TYPE *lower_r = TREE_REAL_CST_PTR (lower);
     180            2 :       if (real_compare (GE_EXPR, lower_r, upper_r))
     181              :         error_E0579 = true;
     182              :     }
     183           42 :   else if (TREE_CODE (upper) == INTEGER_CST)
     184              :     {
     185           42 :       auto upper_wi = wi::to_wide (upper).to_shwi ();
     186           42 :       auto lower_wi = wi::to_wide (lower).to_shwi ();
     187           42 :       if (lower_wi >= upper_wi)
     188              :         error_E0579 = true;
     189              :     }
     190              : 
     191              :   if (error_E0579)
     192            2 :     rust_error_at (pattern.get_locus (), ErrorCode::E0579,
     193              :                    "lower range bound must be less than upper");
     194              : 
     195           44 :   ComparisonOperator upper_cmp = pattern.is_inclusive_range ()
     196           44 :                                    ? ComparisonOperator::LESS_OR_EQUAL
     197           21 :                                    : ComparisonOperator::LESS_THAN;
     198           44 :   tree check_lower
     199           44 :     = Backend::comparison_expression (ComparisonOperator::GREATER_OR_EQUAL,
     200              :                                       match_scrutinee_expr, lower,
     201           44 :                                       pattern.get_locus ());
     202           44 :   tree check_upper
     203           44 :     = Backend::comparison_expression (upper_cmp, match_scrutinee_expr, upper,
     204           44 :                                       pattern.get_locus ());
     205           44 :   check_expr = Backend::arithmetic_or_logical_expression (
     206              :     ArithmeticOrLogicalOperator::BITWISE_AND, check_lower, check_upper,
     207           44 :     pattern.get_locus ());
     208           44 : }
     209              : 
     210              : void
     211          163 : CompilePatternCheckExpr::visit (HIR::ReferencePattern &pattern)
     212              : {
     213          163 :   match_scrutinee_expr
     214          163 :     = indirect_expression (match_scrutinee_expr, pattern.get_locus ());
     215          163 :   pattern.get_referenced_pattern ().accept_vis (*this);
     216          163 : }
     217              : 
     218              : void
     219           43 : CompilePatternCheckExpr::visit (HIR::AltPattern &pattern)
     220              : {
     221           43 :   auto &alts = pattern.get_alts ();
     222              : 
     223           43 :   check_expr = CompilePatternCheckExpr::Compile (*alts.at (0),
     224              :                                                  match_scrutinee_expr, ctx);
     225           43 :   auto end = alts.end ();
     226           87 :   for (auto i = alts.begin () + 1; i != end; i++)
     227              :     {
     228           44 :       tree next_expr
     229           44 :         = CompilePatternCheckExpr::Compile (**i, match_scrutinee_expr, ctx);
     230           44 :       check_expr = Backend::arithmetic_or_logical_expression (
     231              :         ArithmeticOrLogicalOperator::BITWISE_OR, check_expr, next_expr,
     232           44 :         (*i)->get_locus ());
     233              :     }
     234           43 : }
     235              : 
     236              : void
     237          139 : CompilePatternCheckExpr::visit (HIR::StructPattern &pattern)
     238              : {
     239              :   // lookup the type
     240          139 :   TyTy::BaseType *lookup = nullptr;
     241          139 :   bool ok = ctx->get_tyctx ()->lookup_type (
     242          139 :     pattern.get_path ().get_mappings ().get_hirid (), &lookup);
     243          139 :   rust_assert (ok);
     244              : 
     245              :   // this might be an enum
     246          139 :   rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
     247          139 :   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
     248              : 
     249          139 :   rust_assert (adt->number_of_variants () > 0);
     250          139 :   TyTy::VariantDef *variant = nullptr;
     251          139 :   tree variant_accesser_expr = nullptr;
     252          139 :   if (adt->is_enum ())
     253              :     {
     254              :       // lookup the variant
     255          111 :       HirId variant_id;
     256          111 :       ok = ctx->get_tyctx ()->lookup_variant_definition (
     257          111 :         pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
     258          111 :       rust_assert (ok);
     259              : 
     260          111 :       int variant_index = 0;
     261          111 :       ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
     262          111 :       rust_assert (ok);
     263              : 
     264              :       // find expected discriminant
     265              :       // // need to access qualifier the field, if we use QUAL_UNION_TYPE this
     266              :       // // would be DECL_QUALIFIER i think.
     267          111 :       HIR::Expr &discrim_expr = variant->get_discriminant ();
     268          111 :       tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
     269              : 
     270              :       // find discriminant field of scrutinee
     271          111 :       tree scrutinee_expr_qualifier_expr
     272          111 :         = Backend::struct_field_expression (match_scrutinee_expr, 0,
     273          111 :                                             pattern.get_path ().get_locus ());
     274              : 
     275              :       // access variant data
     276          111 :       tree scrutinee_union_expr
     277          111 :         = Backend::struct_field_expression (match_scrutinee_expr, 1,
     278          111 :                                             pattern.get_path ().get_locus ());
     279          111 :       variant_accesser_expr
     280          111 :         = Backend::struct_field_expression (scrutinee_union_expr, variant_index,
     281          111 :                                             pattern.get_path ().get_locus ());
     282              : 
     283          111 :       check_expr
     284          111 :         = Backend::comparison_expression (ComparisonOperator::EQUAL,
     285              :                                           scrutinee_expr_qualifier_expr,
     286              :                                           discrim_expr_node,
     287          111 :                                           pattern.get_path ().get_locus ());
     288              : 
     289          111 :       match_scrutinee_expr = scrutinee_expr_qualifier_expr;
     290              :     }
     291              :   else
     292              :     {
     293           28 :       variant = adt->get_variants ().at (0);
     294           28 :       variant_accesser_expr = match_scrutinee_expr;
     295           28 :       check_expr = boolean_true_node;
     296              :     }
     297              : 
     298          139 :   auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
     299          377 :   for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
     300              :     {
     301          238 :       switch (field->get_item_type ())
     302              :         {
     303           18 :         case HIR::StructPatternField::ItemType::TUPLE_PAT:
     304           18 :           {
     305           18 :             HIR::StructPatternFieldTuplePat &tuple_pat
     306           18 :               = static_cast<HIR::StructPatternFieldTuplePat &> (*field.get ());
     307           18 :             size_t tuple_pat_index = tuple_pat.get_index ();
     308           18 :             tree field_expr
     309           18 :               = Backend::struct_field_expression (variant_accesser_expr,
     310              :                                                   tuple_pat_index,
     311              :                                                   tuple_pat.get_locus ());
     312           18 :             tree check_expr_sub = CompilePatternCheckExpr::Compile (
     313              :               tuple_pat.get_tuple_pattern (), field_expr, ctx);
     314           18 :             check_expr = Backend::arithmetic_or_logical_expression (
     315              :               ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
     316              :               check_expr_sub, tuple_pat.get_locus ());
     317              :           }
     318           18 :           break;
     319              : 
     320          130 :         case HIR::StructPatternField::ItemType::IDENT_PAT:
     321          130 :           {
     322          130 :             HIR::StructPatternFieldIdentPat &ident
     323          130 :               = static_cast<HIR::StructPatternFieldIdentPat &> (*field.get ());
     324              : 
     325          130 :             size_t offs = 0;
     326          130 :             ok = variant->lookup_field (ident.get_identifier ().as_string (),
     327              :                                         nullptr, &offs);
     328          130 :             rust_assert (ok);
     329              : 
     330          130 :             tree field_expr
     331          130 :               = Backend::struct_field_expression (variant_accesser_expr, offs,
     332              :                                                   ident.get_locus ());
     333              : 
     334          130 :             tree check_expr_sub
     335          130 :               = CompilePatternCheckExpr::Compile (ident.get_pattern (),
     336              :                                                   field_expr, ctx);
     337          130 :             check_expr = Backend::arithmetic_or_logical_expression (
     338              :               ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
     339          130 :               check_expr_sub, ident.get_pattern ().get_locus ());
     340              :           }
     341          130 :           break;
     342              : 
     343              :         case HIR::StructPatternField::ItemType::IDENT:
     344              :           {
     345              :             // ident pattern always matches - do nothing
     346              :           }
     347              :           break;
     348              :         }
     349              :     }
     350          139 : }
     351              : 
     352              : void
     353          744 : CompilePatternCheckExpr::visit (HIR::TupleStructPattern &pattern)
     354              : {
     355              :   // lookup the type
     356          744 :   TyTy::BaseType *lookup = nullptr;
     357          744 :   bool ok = ctx->get_tyctx ()->lookup_type (
     358          744 :     pattern.get_path ().get_mappings ().get_hirid (), &lookup);
     359          744 :   rust_assert (ok);
     360              : 
     361              :   // this might be an enum
     362          744 :   rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
     363          744 :   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
     364              : 
     365          744 :   int variant_index = 0;
     366          744 :   rust_assert (adt->number_of_variants () > 0);
     367          744 :   TyTy::VariantDef *variant = nullptr;
     368          744 :   if (adt->is_enum ())
     369              :     {
     370              :       // lookup the variant
     371          697 :       HirId variant_id;
     372          697 :       ok = ctx->get_tyctx ()->lookup_variant_definition (
     373          697 :         pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
     374          697 :       rust_assert (ok);
     375              : 
     376          697 :       ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
     377          697 :       rust_assert (ok);
     378              : 
     379              :       // find expected discriminant
     380          697 :       HIR::Expr &discrim_expr = variant->get_discriminant ();
     381          697 :       tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
     382              : 
     383              :       // find discriminant field of scrutinee
     384          697 :       tree scrutinee_expr_qualifier_expr
     385          697 :         = Backend::struct_field_expression (match_scrutinee_expr, 0,
     386          697 :                                             pattern.get_path ().get_locus ());
     387              : 
     388          697 :       check_expr
     389          697 :         = Backend::comparison_expression (ComparisonOperator::EQUAL,
     390              :                                           scrutinee_expr_qualifier_expr,
     391              :                                           discrim_expr_node,
     392          697 :                                           pattern.get_path ().get_locus ());
     393              :     }
     394              :   else
     395              :     {
     396           47 :       variant = adt->get_variants ().at (0);
     397           47 :       check_expr = boolean_true_node;
     398              :     }
     399              : 
     400          744 :   HIR::TupleStructItems &items = pattern.get_items ();
     401          744 :   switch (items.get_item_type ())
     402              :     {
     403           36 :     case HIR::TupleStructItems::HAS_REST:
     404           36 :       {
     405           36 :         HIR::TupleStructItemsHasRest &items_has_rest
     406              :           = static_cast<HIR::TupleStructItemsHasRest &> (items);
     407           36 :         size_t num_patterns = items_has_rest.get_lower_patterns ().size ()
     408           36 :                               + items_has_rest.get_upper_patterns ().size ();
     409              : 
     410              :         // enums cases shouldn't reach here
     411           36 :         rust_assert (num_patterns <= variant->num_fields ()
     412              :                      && (!adt->is_enum ()));
     413              : 
     414           36 :         size_t tuple_field_index = 0;
     415           65 :         for (auto &pattern : items_has_rest.get_lower_patterns ())
     416              :           {
     417           29 :             tree field_expr
     418           29 :               = Backend::struct_field_expression (match_scrutinee_expr,
     419              :                                                   tuple_field_index++,
     420           29 :                                                   pattern->get_locus ());
     421           29 :             tree check_expr_sub
     422           29 :               = CompilePatternCheckExpr::Compile (*pattern, field_expr, ctx);
     423           29 :             check_expr = Backend::arithmetic_or_logical_expression (
     424              :               ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
     425           29 :               check_expr_sub, pattern->get_locus ());
     426              :           }
     427           36 :         tuple_field_index = variant->num_fields ()
     428           36 :                             - items_has_rest.get_upper_patterns ().size ();
     429           50 :         for (auto &pattern : items_has_rest.get_upper_patterns ())
     430              :           {
     431           14 :             tree field_expr
     432           14 :               = Backend::struct_field_expression (match_scrutinee_expr,
     433              :                                                   tuple_field_index++,
     434           14 :                                                   pattern->get_locus ());
     435           14 :             tree check_expr_sub
     436           14 :               = CompilePatternCheckExpr::Compile (*pattern, field_expr, ctx);
     437           14 :             check_expr = Backend::arithmetic_or_logical_expression (
     438              :               ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
     439           14 :               check_expr_sub, pattern->get_locus ());
     440              :           }
     441              :       }
     442              :       break;
     443              : 
     444          708 :     case HIR::TupleStructItems::NO_REST:
     445          708 :       {
     446          708 :         HIR::TupleStructItemsNoRest &items_no_range
     447              :           = static_cast<HIR::TupleStructItemsNoRest &> (items);
     448              : 
     449          708 :         rust_assert (items_no_range.get_patterns ().size ()
     450              :                      == variant->num_fields ());
     451              : 
     452          708 :         if (adt->is_enum ())
     453              :           {
     454          697 :             size_t tuple_field_index = 0;
     455         1474 :             for (auto &pattern : items_no_range.get_patterns ())
     456              :               {
     457              :                 // find payload union field of scrutinee
     458          777 :                 tree payload_ref
     459          777 :                   = Backend::struct_field_expression (match_scrutinee_expr, 1,
     460          777 :                                                       pattern->get_locus ());
     461              : 
     462          777 :                 tree variant_ref
     463          777 :                   = Backend::struct_field_expression (payload_ref,
     464              :                                                       variant_index,
     465          777 :                                                       pattern->get_locus ());
     466              : 
     467          777 :                 tree field_expr
     468          777 :                   = Backend::struct_field_expression (variant_ref,
     469              :                                                       tuple_field_index++,
     470          777 :                                                       pattern->get_locus ());
     471              : 
     472          777 :                 tree check_expr_sub
     473          777 :                   = CompilePatternCheckExpr::Compile (*pattern, field_expr,
     474              :                                                       ctx);
     475          777 :                 check_expr = Backend::arithmetic_or_logical_expression (
     476              :                   ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
     477          777 :                   check_expr_sub, pattern->get_locus ());
     478              :               }
     479              :           }
     480              :         else
     481              :           {
     482              :             // For non-enum TupleStructPatterns
     483           11 :             size_t tuple_field_index = 0;
     484           31 :             for (auto &pattern : items_no_range.get_patterns ())
     485              :               {
     486           20 :                 tree field_expr
     487           20 :                   = Backend::struct_field_expression (match_scrutinee_expr,
     488              :                                                       tuple_field_index++,
     489           20 :                                                       pattern->get_locus ());
     490              : 
     491           20 :                 tree check_expr_sub
     492           20 :                   = CompilePatternCheckExpr::Compile (*pattern, field_expr,
     493              :                                                       ctx);
     494           20 :                 check_expr = Backend::arithmetic_or_logical_expression (
     495              :                   ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
     496           20 :                   check_expr_sub, pattern->get_locus ());
     497              :               }
     498              :           }
     499              :         break;
     500              :       }
     501              :     }
     502          744 : }
     503              : 
     504              : void
     505          122 : CompilePatternCheckExpr::visit (HIR::TuplePattern &pattern)
     506              : {
     507          122 :   check_expr = boolean_true_node;
     508              : 
     509          122 :   switch (pattern.get_items ().get_item_type ())
     510              :     {
     511           23 :     case HIR::TuplePatternItems::HAS_REST:
     512           23 :       {
     513           23 :         auto &items
     514           23 :           = static_cast<HIR::TuplePatternItemsHasRest &> (pattern.get_items ());
     515           23 :         size_t tuple_field_index = 0;
     516              : 
     517              :         // lookup the type to find out number of fields
     518           23 :         TyTy::BaseType *ty = nullptr;
     519           23 :         bool ok = ctx->get_tyctx ()->lookup_type (
     520           23 :           pattern.get_mappings ().get_hirid (), &ty);
     521           23 :         rust_assert (ok);
     522           23 :         rust_assert (ty->get_kind () == TyTy::TypeKind::TUPLE);
     523              : 
     524              :         // compile check expr for lower patterns
     525           46 :         for (auto &pat : items.get_lower_patterns ())
     526              :           {
     527           23 :             tree field_expr
     528           23 :               = Backend::struct_field_expression (match_scrutinee_expr,
     529              :                                                   tuple_field_index++,
     530           23 :                                                   pat->get_locus ());
     531              : 
     532           23 :             tree check_expr_sub
     533           23 :               = CompilePatternCheckExpr::Compile (*pat, field_expr, ctx);
     534           23 :             check_expr = Backend::arithmetic_or_logical_expression (
     535              :               ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
     536           23 :               check_expr_sub, pat->get_locus ());
     537              :           }
     538              : 
     539              :         // skip the fields that are not checked
     540           23 :         tuple_field_index = static_cast<TyTy::TupleType &> (*ty).num_fields ()
     541           23 :                             - items.get_upper_patterns ().size ();
     542              : 
     543              :         // compile check expr for upper patterns
     544           45 :         for (auto &pat : items.get_upper_patterns ())
     545              :           {
     546           22 :             tree field_expr
     547           22 :               = Backend::struct_field_expression (match_scrutinee_expr,
     548              :                                                   tuple_field_index++,
     549           22 :                                                   pat->get_locus ());
     550              : 
     551           22 :             tree check_expr_sub
     552           22 :               = CompilePatternCheckExpr::Compile (*pat, field_expr, ctx);
     553           22 :             check_expr = Backend::arithmetic_or_logical_expression (
     554              :               ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
     555           22 :               check_expr_sub, pat->get_locus ());
     556              :           }
     557              :       }
     558           23 :       break;
     559              : 
     560           99 :     case HIR::TuplePatternItems::NO_REST:
     561           99 :       {
     562           99 :         auto &items
     563           99 :           = static_cast<HIR::TuplePatternItemsNoRest &> (pattern.get_items ());
     564           99 :         size_t tuple_field_index = 0;
     565              : 
     566          304 :         for (auto &pat : items.get_patterns ())
     567              :           {
     568          205 :             tree field_expr
     569          205 :               = Backend::struct_field_expression (match_scrutinee_expr,
     570              :                                                   tuple_field_index++,
     571          205 :                                                   pat->get_locus ());
     572              : 
     573          205 :             tree check_expr_sub
     574          205 :               = CompilePatternCheckExpr::Compile (*pat, field_expr, ctx);
     575          205 :             check_expr = Backend::arithmetic_or_logical_expression (
     576              :               ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
     577          205 :               check_expr_sub, pat->get_locus ());
     578              :           }
     579              :       }
     580              :     }
     581          122 : }
     582              : 
     583              : void
     584          709 : CompilePatternCheckExpr::visit (HIR::IdentifierPattern &pattern)
     585              : {
     586          709 :   if (pattern.has_subpattern ())
     587              :     {
     588            9 :       check_expr = CompilePatternCheckExpr::Compile (pattern.get_subpattern (),
     589              :                                                      match_scrutinee_expr, ctx);
     590              :     }
     591              :   else
     592              :     {
     593          700 :       check_expr = boolean_true_node;
     594              :     }
     595          709 : }
     596              : 
     597              : void
     598           75 : CompilePatternCheckExpr::visit (HIR::SlicePattern &pattern)
     599              : {
     600           75 :   check_expr = boolean_true_node;
     601              : 
     602              :   // lookup the type
     603           75 :   TyTy::BaseType *lookup = nullptr;
     604           75 :   bool ok
     605           75 :     = ctx->get_tyctx ()->lookup_type (pattern.get_mappings ().get_hirid (),
     606              :                                       &lookup);
     607           75 :   rust_assert (ok);
     608              : 
     609              :   // pattern must either be ArrayType or SliceType, should be already confirmed
     610              :   // by type checking
     611           75 :   rust_assert (lookup->get_kind () == TyTy::TypeKind::ARRAY
     612              :                || lookup->get_kind () == TyTy::TypeKind::SLICE
     613              :                || lookup->get_kind () == TyTy::REF);
     614              : 
     615              :   // function ptr that points to either array_index_expression or
     616              :   // slice_index_expression depending on the scrutinee's type
     617           75 :   tree (*scrutinee_index_expr_func) (tree, tree, location_t) = nullptr;
     618              : 
     619           75 :   switch (lookup->get_kind ())
     620              :     {
     621              :     case TyTy::TypeKind::ARRAY:
     622              :       scrutinee_index_expr_func = Backend::array_index_expression;
     623              :       break;
     624            0 :     case TyTy::TypeKind::SLICE:
     625            0 :       rust_sorry_at (
     626              :         pattern.get_locus (),
     627              :         "SlicePattern matching against non-ref slices are not yet supported");
     628            0 :       break;
     629           39 :     case TyTy::TypeKind::REF:
     630           39 :       {
     631           39 :         rust_assert (RS_DST_FLAG_P (TREE_TYPE (match_scrutinee_expr)));
     632           39 :         scrutinee_index_expr_func = Backend::slice_index_expression;
     633           39 :         tree size_field
     634           39 :           = Backend::struct_field_expression (match_scrutinee_expr, 1,
     635           39 :                                               pattern.get_locus ());
     636              : 
     637              :         // for slices, generate a dynamic size comparison expression tree
     638              :         // because size checking is done at runtime.
     639           39 :         switch (pattern.get_items ().get_item_type ())
     640              :           {
     641           16 :           case HIR::SlicePatternItems::ItemType::NO_REST:
     642           16 :             {
     643           16 :               auto &items = static_cast<HIR::SlicePatternItemsNoRest &> (
     644           16 :                 pattern.get_items ());
     645           16 :               check_expr = Backend::comparison_expression (
     646              :                 ComparisonOperator::EQUAL, size_field,
     647           16 :                 build_int_cst (size_type_node, items.get_patterns ().size ()),
     648           16 :                 pattern.get_locus ());
     649              :             }
     650           16 :             break;
     651           23 :           case HIR::SlicePatternItems::ItemType::HAS_REST:
     652           23 :             {
     653           23 :               auto &items = static_cast<HIR::SlicePatternItemsHasRest &> (
     654           23 :                 pattern.get_items ());
     655           23 :               auto pattern_min_cap = items.get_lower_patterns ().size ()
     656           23 :                                      + items.get_upper_patterns ().size ();
     657           23 :               check_expr = Backend::comparison_expression (
     658              :                 ComparisonOperator::GREATER_OR_EQUAL, size_field,
     659           23 :                 build_int_cst (size_type_node, pattern_min_cap),
     660           23 :                 pattern.get_locus ());
     661              :             }
     662           23 :             break;
     663              :           }
     664              :       }
     665              :       break;
     666            0 :     default:
     667            0 :       rust_unreachable ();
     668              :     }
     669              : 
     670           39 :   rust_assert (scrutinee_index_expr_func != nullptr);
     671              : 
     672              :   // Generate tree to compare every element within array/slice
     673           75 :   size_t element_index = 0;
     674           75 :   switch (pattern.get_items ().get_item_type ())
     675              :     {
     676           31 :     case HIR::SlicePatternItems::ItemType::NO_REST:
     677           31 :       {
     678           31 :         auto &items
     679           31 :           = static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ());
     680           92 :         for (auto &pattern_member : items.get_patterns ())
     681              :           {
     682           61 :             tree index_tree
     683           61 :               = Backend::size_constant_expression (element_index++);
     684           61 :             tree element_expr
     685           61 :               = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
     686           61 :                                            pattern.get_locus ());
     687           61 :             tree check_expr_sub
     688           61 :               = CompilePatternCheckExpr::Compile (*pattern_member, element_expr,
     689              :                                                   ctx);
     690           61 :             check_expr = Backend::arithmetic_or_logical_expression (
     691              :               ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
     692           61 :               check_expr_sub, pattern.get_locus ());
     693              :           }
     694              :         break;
     695              :       }
     696           44 :     case HIR::SlicePatternItems::ItemType::HAS_REST:
     697           44 :       {
     698           44 :         auto &items
     699           44 :           = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
     700           87 :         for (auto &pattern_member : items.get_lower_patterns ())
     701              :           {
     702           43 :             tree index_tree
     703           43 :               = Backend::size_constant_expression (element_index++);
     704           43 :             tree element_expr
     705           43 :               = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
     706           43 :                                            pattern.get_locus ());
     707           43 :             tree check_expr_sub
     708           43 :               = CompilePatternCheckExpr::Compile (*pattern_member, element_expr,
     709              :                                                   ctx);
     710           43 :             check_expr = Backend::arithmetic_or_logical_expression (
     711              :               ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
     712           43 :               check_expr_sub, pattern.get_locus ());
     713              :           }
     714              : 
     715              :         // handle codegen for upper patterns differently for both types
     716           44 :         switch (lookup->get_kind ())
     717              :           {
     718           21 :           case TyTy::TypeKind::ARRAY:
     719           21 :             {
     720              :               // for array type scrutinee, we can simply get the capacity as a
     721              :               // const and calculate how many elements to skip
     722           21 :               auto array_ty = static_cast<TyTy::ArrayType *> (lookup);
     723           21 :               auto capacity_ty = array_ty->get_capacity ();
     724              : 
     725           21 :               rust_assert (capacity_ty->get_kind () == TyTy::TypeKind::CONST);
     726           21 :               auto *capacity_const = capacity_ty->as_const_type ();
     727           21 :               rust_assert (capacity_const->const_kind ()
     728              :                            == TyTy::BaseConstType::ConstKind::Value);
     729           21 :               auto &capacity_value
     730              :                 = *static_cast<TyTy::ConstValueType *> (capacity_const);
     731           21 :               auto cap_tree = capacity_value.get_value ();
     732              : 
     733           21 :               rust_assert (!error_operand_p (cap_tree));
     734              : 
     735           21 :               size_t cap_wi = (size_t) wi::to_wide (cap_tree).to_uhwi ();
     736           21 :               element_index = cap_wi - items.get_upper_patterns ().size ();
     737           42 :               for (auto &pattern_member : items.get_upper_patterns ())
     738              :                 {
     739           21 :                   tree index_tree
     740           21 :                     = Backend::size_constant_expression (element_index++);
     741           21 :                   tree element_expr
     742           21 :                     = scrutinee_index_expr_func (match_scrutinee_expr,
     743              :                                                  index_tree,
     744           21 :                                                  pattern.get_locus ());
     745           21 :                   tree check_expr_sub
     746           21 :                     = CompilePatternCheckExpr::Compile (*pattern_member,
     747              :                                                         element_expr, ctx);
     748           21 :                   check_expr = Backend::arithmetic_or_logical_expression (
     749              :                     ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
     750           21 :                     check_expr_sub, pattern.get_locus ());
     751              :                 }
     752              :             }
     753              :             break;
     754           23 :           case TyTy::TypeKind::REF:
     755           23 :             {
     756              :               // for slice type scrutinee, size is dyanamic, so number of
     757              :               // elements to skip is calculated during runtime
     758           23 :               tree slice_size
     759           23 :                 = Backend::struct_field_expression (match_scrutinee_expr, 1,
     760           23 :                                                     pattern.get_locus ());
     761           23 :               tree upper_patterns_size = Backend::size_constant_expression (
     762           23 :                 items.get_upper_patterns ().size ());
     763           23 :               tree index_tree = Backend::arithmetic_or_logical_expression (
     764              :                 ArithmeticOrLogicalOperator::SUBTRACT, slice_size,
     765           23 :                 upper_patterns_size, pattern.get_locus ());
     766           45 :               for (auto &pattern_member : items.get_upper_patterns ())
     767              :                 {
     768           22 :                   tree element_expr
     769           22 :                     = scrutinee_index_expr_func (match_scrutinee_expr,
     770              :                                                  index_tree,
     771           22 :                                                  pattern.get_locus ());
     772           22 :                   tree check_expr_sub
     773           22 :                     = CompilePatternCheckExpr::Compile (*pattern_member,
     774              :                                                         element_expr, ctx);
     775           22 :                   check_expr = Backend::arithmetic_or_logical_expression (
     776              :                     ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
     777           22 :                     check_expr_sub, pattern.get_locus ());
     778           22 :                   index_tree = Backend::arithmetic_or_logical_expression (
     779              :                     ArithmeticOrLogicalOperator::ADD, index_tree,
     780              :                     Backend::size_constant_expression (1),
     781           22 :                     pattern.get_locus ());
     782              :                 }
     783              :             }
     784              :             break;
     785            0 :           default:
     786            0 :             rust_unreachable ();
     787              :           }
     788              :       }
     789              :       break;
     790              :     }
     791           75 : }
     792              : 
     793              : // setup the bindings
     794              : 
     795              : void
     796          730 : CompilePatternBindings::visit (HIR::TupleStructPattern &pattern)
     797              : {
     798              :   // lookup the type
     799          730 :   TyTy::BaseType *lookup = nullptr;
     800          730 :   bool ok = ctx->get_tyctx ()->lookup_type (
     801          730 :     pattern.get_path ().get_mappings ().get_hirid (), &lookup);
     802          730 :   rust_assert (ok);
     803              : 
     804              :   // this must be an enum
     805          730 :   rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
     806          730 :   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
     807          730 :   rust_assert (adt->number_of_variants () > 0);
     808              : 
     809          730 :   int variant_index = 0;
     810          730 :   TyTy::VariantDef *variant = adt->get_variants ().at (0);
     811          730 :   if (adt->is_enum ())
     812              :     {
     813          669 :       HirId variant_id = UNKNOWN_HIRID;
     814          669 :       bool ok = ctx->get_tyctx ()->lookup_variant_definition (
     815          669 :         pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
     816          669 :       rust_assert (ok);
     817              : 
     818          669 :       ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
     819          669 :       rust_assert (ok);
     820              :     }
     821              : 
     822          730 :   rust_assert (variant->get_variant_type ()
     823              :                == TyTy::VariantDef::VariantType::TUPLE);
     824              : 
     825          730 :   HIR::TupleStructItems &items = pattern.get_items ();
     826          730 :   switch (items.get_item_type ())
     827              :     {
     828           36 :     case HIR::TupleStructItems::HAS_REST:
     829           36 :       {
     830           36 :         HIR::TupleStructItemsHasRest &items_has_rest
     831              :           = static_cast<HIR::TupleStructItemsHasRest &> (items);
     832           36 :         size_t num_patterns = items_has_rest.get_lower_patterns ().size ()
     833           36 :                               + items_has_rest.get_upper_patterns ().size ();
     834              : 
     835              :         // enums cases shouldn't reach here
     836           36 :         rust_assert (num_patterns <= variant->num_fields ()
     837              :                      && (!adt->is_enum ()));
     838              : 
     839           36 :         size_t tuple_field_index = 0;
     840           65 :         for (auto &pattern : items_has_rest.get_lower_patterns ())
     841              :           {
     842           29 :             tree binding
     843           29 :               = Backend::struct_field_expression (match_scrutinee_expr,
     844              :                                                   tuple_field_index++,
     845           29 :                                                   pattern->get_locus ());
     846              : 
     847           29 :             CompilePatternBindings::Compile (*pattern, binding, ctx);
     848              :           }
     849              : 
     850           36 :         tuple_field_index = variant->num_fields ()
     851           36 :                             - items_has_rest.get_upper_patterns ().size ();
     852              : 
     853           50 :         for (auto &pattern : items_has_rest.get_upper_patterns ())
     854              :           {
     855           14 :             tree binding
     856           14 :               = Backend::struct_field_expression (match_scrutinee_expr,
     857              :                                                   tuple_field_index++,
     858           14 :                                                   pattern->get_locus ());
     859              : 
     860           14 :             CompilePatternBindings::Compile (*pattern, binding, ctx);
     861              :           }
     862              :       }
     863              :       break;
     864              : 
     865          694 :     case HIR::TupleStructItems::NO_REST:
     866          694 :       {
     867          694 :         HIR::TupleStructItemsNoRest &items_no_rest
     868              :           = static_cast<HIR::TupleStructItemsNoRest &> (items);
     869          694 :         rust_assert (items_no_rest.get_patterns ().size ()
     870              :                      == variant->num_fields ());
     871              : 
     872          694 :         if (adt->is_enum ())
     873              :           {
     874          669 :             size_t tuple_field_index = 0;
     875         1418 :             for (auto &pattern : items_no_rest.get_patterns ())
     876              :               {
     877          749 :                 tree payload_accessor_union
     878          749 :                   = Backend::struct_field_expression (match_scrutinee_expr, 1,
     879          749 :                                                       pattern->get_locus ());
     880              : 
     881          749 :                 tree variant_accessor
     882          749 :                   = Backend::struct_field_expression (payload_accessor_union,
     883              :                                                       variant_index,
     884          749 :                                                       pattern->get_locus ());
     885              : 
     886          749 :                 tree binding
     887          749 :                   = Backend::struct_field_expression (variant_accessor,
     888              :                                                       tuple_field_index++,
     889          749 :                                                       pattern->get_locus ());
     890              : 
     891          749 :                 CompilePatternBindings::Compile (*pattern, binding, ctx);
     892              :               }
     893              :           }
     894              :         else
     895              :           {
     896           25 :             size_t tuple_field_index = 0;
     897           66 :             for (auto &pattern : items_no_rest.get_patterns ())
     898              :               {
     899           41 :                 tree binding
     900           41 :                   = Backend::struct_field_expression (match_scrutinee_expr,
     901              :                                                       tuple_field_index++,
     902           41 :                                                       pattern->get_locus ());
     903              : 
     904           41 :                 CompilePatternBindings::Compile (*pattern, binding, ctx);
     905              :               }
     906              :           }
     907              :       }
     908              :       break;
     909              :     }
     910          730 : }
     911              : 
     912              : tree
     913          220 : CompilePatternBindings::make_struct_access (TyTy::ADTType *adt,
     914              :                                             TyTy::VariantDef *variant,
     915              :                                             const Identifier &ident,
     916              :                                             int variant_index)
     917              : {
     918          220 :   size_t offs = 0;
     919          220 :   auto ok = variant->lookup_field (ident.as_string (), nullptr, &offs);
     920          220 :   rust_assert (ok);
     921              : 
     922          220 :   if (adt->is_enum ())
     923              :     {
     924          187 :       tree payload_accessor_union
     925          187 :         = Backend::struct_field_expression (match_scrutinee_expr, 1,
     926              :                                             ident.get_locus ());
     927              : 
     928          187 :       tree variant_accessor
     929          187 :         = Backend::struct_field_expression (payload_accessor_union,
     930              :                                             variant_index, ident.get_locus ());
     931              : 
     932          187 :       return Backend::struct_field_expression (variant_accessor, offs,
     933          187 :                                                ident.get_locus ());
     934              :     }
     935              :   else
     936              :     {
     937           33 :       tree variant_accessor = match_scrutinee_expr;
     938              : 
     939           33 :       return Backend::struct_field_expression (variant_accessor, offs,
     940           33 :                                                ident.get_locus ());
     941              :     }
     942              : }
     943              : 
     944              : void
     945           90 : CompilePatternBindings::handle_struct_pattern_ident (
     946              :   HIR::StructPatternField &pat, TyTy::ADTType *adt, TyTy::VariantDef *variant,
     947              :   int variant_index)
     948              : {
     949           90 :   HIR::StructPatternFieldIdent &ident
     950              :     = static_cast<HIR::StructPatternFieldIdent &> (pat);
     951              : 
     952           90 :   auto identifier = ident.get_identifier ();
     953           90 :   tree binding = make_struct_access (adt, variant, identifier, variant_index);
     954              : 
     955           90 :   ctx->insert_pattern_binding (ident.get_mappings ().get_hirid (), binding);
     956           90 : }
     957              : 
     958              : void
     959          130 : CompilePatternBindings::handle_struct_pattern_ident_pat (
     960              :   HIR::StructPatternField &pat, TyTy::ADTType *adt, TyTy::VariantDef *variant,
     961              :   int variant_index)
     962              : {
     963          130 :   auto &pattern = static_cast<HIR::StructPatternFieldIdentPat &> (pat);
     964              : 
     965          130 :   tree binding = make_struct_access (adt, variant, pattern.get_identifier (),
     966              :                                      variant_index);
     967          130 :   CompilePatternBindings::Compile (pattern.get_pattern (), binding, ctx);
     968          130 : }
     969              : 
     970              : void
     971           18 : CompilePatternBindings::handle_struct_pattern_tuple_pat (
     972              :   HIR::StructPatternField &pat, TyTy::ADTType *adt, TyTy::VariantDef *variant,
     973              :   int variant_index)
     974              : {
     975           18 :   HIR::StructPatternFieldTuplePat &tuple_pat
     976              :     = static_cast<HIR::StructPatternFieldTuplePat &> (pat);
     977              : 
     978           18 :   size_t tuple_pat_index = tuple_pat.get_index ();
     979           18 :   tree binding;
     980              : 
     981           18 :   if (adt->is_enum ())
     982              :     {
     983            0 :       tree payload_accessor_union
     984            0 :         = Backend::struct_field_expression (match_scrutinee_expr, 1,
     985              :                                             pat.get_locus ());
     986              : 
     987            0 :       tree variant_accessor
     988            0 :         = Backend::struct_field_expression (payload_accessor_union,
     989              :                                             variant_index, pat.get_locus ());
     990              : 
     991            0 :       binding
     992            0 :         = Backend::struct_field_expression (variant_accessor, tuple_pat_index,
     993              :                                             pat.get_locus ());
     994              :     }
     995              :   else
     996              :     {
     997           18 :       tree variant_accessor = match_scrutinee_expr;
     998              : 
     999           18 :       binding
    1000           18 :         = Backend::struct_field_expression (variant_accessor, tuple_pat_index,
    1001              :                                             pat.get_locus ());
    1002              :     }
    1003              : 
    1004           18 :   CompilePatternBindings::Compile (tuple_pat.get_tuple_pattern (), binding,
    1005              :                                    ctx);
    1006           18 : }
    1007              : 
    1008              : void
    1009          139 : CompilePatternBindings::visit (HIR::StructPattern &pattern)
    1010              : {
    1011              :   // lookup the type
    1012          139 :   TyTy::BaseType *lookup = nullptr;
    1013          139 :   bool ok = ctx->get_tyctx ()->lookup_type (
    1014          139 :     pattern.get_path ().get_mappings ().get_hirid (), &lookup);
    1015          139 :   rust_assert (ok);
    1016              : 
    1017              :   // this must be an enum
    1018          139 :   rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
    1019          139 :   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
    1020          139 :   rust_assert (adt->number_of_variants () > 0);
    1021              : 
    1022          139 :   int variant_index = 0;
    1023          139 :   TyTy::VariantDef *variant = adt->get_variants ().at (0);
    1024          139 :   if (adt->is_enum ())
    1025              :     {
    1026          111 :       HirId variant_id = UNKNOWN_HIRID;
    1027          111 :       bool ok = ctx->get_tyctx ()->lookup_variant_definition (
    1028          111 :         pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
    1029          111 :       rust_assert (ok);
    1030              : 
    1031          111 :       ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
    1032          111 :       rust_assert (ok);
    1033              :     }
    1034              : 
    1035          139 :   rust_assert (
    1036              :     variant->get_variant_type () == TyTy::VariantDef::VariantType::STRUCT
    1037              :     || variant->get_variant_type () == TyTy::VariantDef::VariantType::TUPLE);
    1038              : 
    1039          139 :   auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
    1040          377 :   for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
    1041              :     {
    1042          238 :       switch (field->get_item_type ())
    1043              :         {
    1044           18 :         case HIR::StructPatternField::ItemType::TUPLE_PAT:
    1045           18 :           handle_struct_pattern_tuple_pat (*field, adt, variant, variant_index);
    1046           18 :           break;
    1047          130 :         case HIR::StructPatternField::ItemType::IDENT_PAT:
    1048          130 :           handle_struct_pattern_ident_pat (*field, adt, variant, variant_index);
    1049          130 :           break;
    1050           90 :         case HIR::StructPatternField::ItemType::IDENT:
    1051           90 :           handle_struct_pattern_ident (*field, adt, variant, variant_index);
    1052           90 :           break;
    1053              :         }
    1054              :     }
    1055          139 : }
    1056              : 
    1057              : void
    1058          193 : CompilePatternBindings::visit (HIR::ReferencePattern &pattern)
    1059              : {
    1060          193 :   tree derefed
    1061          193 :     = indirect_expression (match_scrutinee_expr, pattern.get_locus ());
    1062              : 
    1063          193 :   CompilePatternBindings::Compile (pattern.get_referenced_pattern (), derefed,
    1064              :                                    ctx);
    1065          193 : }
    1066              : 
    1067              : void
    1068          791 : CompilePatternBindings::visit (HIR::IdentifierPattern &pattern)
    1069              : {
    1070          791 :   if (pattern.has_subpattern ())
    1071              :     {
    1072            9 :       CompilePatternBindings::Compile (pattern.get_subpattern (),
    1073              :                                        match_scrutinee_expr, ctx);
    1074              :     }
    1075              : 
    1076          791 :   if (!pattern.get_is_ref ())
    1077              :     {
    1078          790 :       ctx->insert_pattern_binding (pattern.get_mappings ().get_hirid (),
    1079              :                                    match_scrutinee_expr);
    1080          790 :       return;
    1081              :     }
    1082              : 
    1083            1 :   tree ref = address_expression (match_scrutinee_expr,
    1084            1 :                                  EXPR_LOCATION (match_scrutinee_expr));
    1085            1 :   ctx->insert_pattern_binding (pattern.get_mappings ().get_hirid (), ref);
    1086              : }
    1087              : 
    1088              : void
    1089          123 : CompilePatternBindings::visit (HIR::TuplePattern &pattern)
    1090              : {
    1091          123 :   rust_assert (pattern.has_tuple_pattern_items ());
    1092              : 
    1093              :   // lookup the type
    1094          123 :   TyTy::BaseType *ty = nullptr;
    1095          123 :   bool ok
    1096          123 :     = ctx->get_tyctx ()->lookup_type (pattern.get_mappings ().get_hirid (),
    1097              :                                       &ty);
    1098          123 :   rust_assert (ok);
    1099              : 
    1100          123 :   switch (pattern.get_items ().get_item_type ())
    1101              :     {
    1102           23 :     case HIR::TuplePatternItems::ItemType::HAS_REST:
    1103           23 :       {
    1104           23 :         size_t tuple_idx = 0;
    1105           23 :         auto &items
    1106           23 :           = static_cast<HIR::TuplePatternItemsHasRest &> (pattern.get_items ());
    1107              : 
    1108           23 :         auto &items_lower = items.get_lower_patterns ();
    1109           23 :         auto &items_upper = items.get_upper_patterns ();
    1110              : 
    1111           46 :         for (auto &sub : items_lower)
    1112              :           {
    1113           23 :             TyTy::BaseType *ty_sub = nullptr;
    1114           23 :             HirId sub_id = sub->get_mappings ().get_hirid ();
    1115           23 :             bool ok = ctx->get_tyctx ()->lookup_type (sub_id, &ty_sub);
    1116           23 :             rust_assert (ok);
    1117              : 
    1118           23 :             tree sub_init
    1119           23 :               = Backend::struct_field_expression (match_scrutinee_expr,
    1120           23 :                                                   tuple_idx, sub->get_locus ());
    1121              : 
    1122           23 :             CompilePatternBindings::Compile (*sub.get (), sub_init, ctx);
    1123           23 :             tuple_idx++;
    1124              :           }
    1125              : 
    1126           23 :         rust_assert (ty->get_kind () == TyTy::TypeKind::TUPLE);
    1127           23 :         tuple_idx = static_cast<TyTy::TupleType &> (*ty).num_fields ()
    1128           23 :                     - items_upper.size ();
    1129              : 
    1130           45 :         for (auto &sub : items_upper)
    1131              :           {
    1132           22 :             TyTy::BaseType *ty_sub = nullptr;
    1133           22 :             HirId sub_id = sub->get_mappings ().get_hirid ();
    1134           22 :             bool ok = ctx->get_tyctx ()->lookup_type (sub_id, &ty_sub);
    1135           22 :             rust_assert (ok);
    1136              : 
    1137           22 :             tree sub_init
    1138           22 :               = Backend::struct_field_expression (match_scrutinee_expr,
    1139           22 :                                                   tuple_idx, sub->get_locus ());
    1140           22 :             CompilePatternBindings::Compile (*sub.get (), sub_init, ctx);
    1141           22 :             tuple_idx++;
    1142              :           }
    1143              : 
    1144              :         return;
    1145              :       }
    1146          100 :     case HIR::TuplePatternItems::ItemType::NO_REST:
    1147          100 :       {
    1148          100 :         size_t tuple_idx = 0;
    1149          100 :         auto &items
    1150          100 :           = static_cast<HIR::TuplePatternItemsNoRest &> (pattern.get_items ());
    1151              : 
    1152          307 :         for (auto &sub : items.get_patterns ())
    1153              :           {
    1154          207 :             TyTy::BaseType *ty_sub = nullptr;
    1155          207 :             HirId sub_id = sub->get_mappings ().get_hirid ();
    1156          207 :             bool ok = ctx->get_tyctx ()->lookup_type (sub_id, &ty_sub);
    1157          207 :             rust_assert (ok);
    1158              : 
    1159          207 :             tree sub_init
    1160          207 :               = Backend::struct_field_expression (match_scrutinee_expr,
    1161          207 :                                                   tuple_idx, sub->get_locus ());
    1162          207 :             CompilePatternBindings::Compile (*sub.get (), sub_init, ctx);
    1163          207 :             tuple_idx++;
    1164              :           }
    1165              : 
    1166              :         return;
    1167              :       }
    1168            0 :     default:
    1169            0 :       {
    1170            0 :         rust_unreachable ();
    1171              :       }
    1172              :     }
    1173              : }
    1174              : 
    1175              : void
    1176           75 : CompilePatternBindings::visit (HIR::SlicePattern &pattern)
    1177              : {
    1178              :   // lookup the type
    1179           75 :   TyTy::BaseType *lookup = nullptr;
    1180           75 :   bool ok
    1181           75 :     = ctx->get_tyctx ()->lookup_type (pattern.get_mappings ().get_hirid (),
    1182              :                                       &lookup);
    1183           75 :   rust_assert (ok);
    1184              : 
    1185           75 :   rust_assert (lookup->get_kind () == TyTy::TypeKind::ARRAY
    1186              :                || lookup->get_kind () == TyTy::TypeKind::SLICE
    1187              :                || lookup->get_kind () == TyTy::REF);
    1188              : 
    1189              :   // function ptr that points to either array_index_expression or
    1190              :   // slice_index_expression depending on the scrutinee's type
    1191           75 :   tree (*scrutinee_index_expr_func) (tree, tree, location_t) = nullptr;
    1192              : 
    1193           75 :   switch (lookup->get_kind ())
    1194              :     {
    1195              :     case TyTy::TypeKind::ARRAY:
    1196              :       scrutinee_index_expr_func = Backend::array_index_expression;
    1197              :       break;
    1198            0 :     case TyTy::TypeKind::SLICE:
    1199            0 :       rust_sorry_at (pattern.get_locus (),
    1200              :                      "SlicePattern matching against non-ref slices are "
    1201              :                      "not yet supported");
    1202            0 :       break;
    1203              :     case TyTy::TypeKind::REF:
    1204              :       scrutinee_index_expr_func = Backend::slice_index_expression;
    1205              :       break;
    1206            0 :     default:
    1207            0 :       rust_unreachable ();
    1208              :     }
    1209              : 
    1210            0 :   rust_assert (scrutinee_index_expr_func != nullptr);
    1211              : 
    1212           75 :   size_t element_index = 0;
    1213              : 
    1214           75 :   switch (pattern.get_items ().get_item_type ())
    1215              :     {
    1216           31 :     case HIR::SlicePatternItems::ItemType::NO_REST:
    1217           31 :       {
    1218           31 :         auto &items
    1219           31 :           = static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ());
    1220           92 :         for (auto &pattern_member : items.get_patterns ())
    1221              :           {
    1222           61 :             tree index_tree
    1223           61 :               = Backend::size_constant_expression (element_index++);
    1224           61 :             tree element_expr
    1225           61 :               = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
    1226           61 :                                            pattern.get_locus ());
    1227           61 :             CompilePatternBindings::Compile (*pattern_member, element_expr,
    1228              :                                              ctx);
    1229              :           }
    1230              :       }
    1231              :       break;
    1232           44 :     case HIR::SlicePatternItems::ItemType::HAS_REST:
    1233           44 :       {
    1234           44 :         auto &items
    1235           44 :           = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
    1236           87 :         for (auto &pattern_member : items.get_lower_patterns ())
    1237              :           {
    1238           43 :             tree index_tree
    1239           43 :               = Backend::size_constant_expression (element_index++);
    1240           43 :             tree element_expr
    1241           43 :               = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
    1242           43 :                                            pattern.get_locus ());
    1243           43 :             CompilePatternBindings::Compile (*pattern_member, element_expr,
    1244              :                                              ctx);
    1245              :           }
    1246              : 
    1247              :         // handle codegen for upper patterns differently for both types
    1248           44 :         switch (lookup->get_kind ())
    1249              :           {
    1250           21 :           case TyTy::TypeKind::ARRAY:
    1251           21 :             {
    1252           21 :               auto array_ty = static_cast<TyTy::ArrayType *> (lookup);
    1253           21 :               auto capacity_ty = array_ty->get_capacity ();
    1254              : 
    1255           21 :               rust_assert (capacity_ty->get_kind () == TyTy::TypeKind::CONST);
    1256           21 :               auto *capacity_const = capacity_ty->as_const_type ();
    1257           21 :               rust_assert (capacity_const->const_kind ()
    1258              :                            == TyTy::BaseConstType::ConstKind::Value);
    1259           21 :               auto &capacity_value
    1260              :                 = *static_cast<TyTy::ConstValueType *> (capacity_const);
    1261           21 :               auto cap_tree = capacity_value.get_value ();
    1262              : 
    1263           21 :               rust_assert (!error_operand_p (cap_tree));
    1264              : 
    1265           21 :               size_t cap_wi = (size_t) wi::to_wide (cap_tree).to_uhwi ();
    1266           21 :               element_index = cap_wi - items.get_upper_patterns ().size ();
    1267           42 :               for (auto &pattern_member : items.get_upper_patterns ())
    1268              :                 {
    1269           21 :                   tree index_tree
    1270           21 :                     = Backend::size_constant_expression (element_index++);
    1271           21 :                   tree element_expr
    1272           21 :                     = scrutinee_index_expr_func (match_scrutinee_expr,
    1273              :                                                  index_tree,
    1274           21 :                                                  pattern.get_locus ());
    1275           21 :                   CompilePatternBindings::Compile (*pattern_member,
    1276              :                                                    element_expr, ctx);
    1277              :                 }
    1278              :             }
    1279              :             break;
    1280            0 :           case TyTy::TypeKind::SLICE:
    1281            0 :             rust_sorry_at (pattern.get_locus (),
    1282              :                            "SlicePattern matching against non-ref slices are "
    1283              :                            "not yet supported");
    1284            0 :             break;
    1285           23 :           case TyTy::TypeKind::REF:
    1286           23 :             {
    1287           23 :               tree slice_size
    1288           23 :                 = Backend::struct_field_expression (match_scrutinee_expr, 1,
    1289           23 :                                                     pattern.get_locus ());
    1290           23 :               tree upper_patterns_size = Backend::size_constant_expression (
    1291           23 :                 items.get_upper_patterns ().size ());
    1292           23 :               tree index_tree = Backend::arithmetic_or_logical_expression (
    1293              :                 ArithmeticOrLogicalOperator::SUBTRACT, slice_size,
    1294           23 :                 upper_patterns_size, pattern.get_locus ());
    1295           45 :               for (auto &pattern_member : items.get_upper_patterns ())
    1296              :                 {
    1297           22 :                   tree element_expr
    1298           22 :                     = scrutinee_index_expr_func (match_scrutinee_expr,
    1299              :                                                  index_tree,
    1300           22 :                                                  pattern.get_locus ());
    1301           22 :                   CompilePatternBindings::Compile (*pattern_member,
    1302              :                                                    element_expr, ctx);
    1303           22 :                   index_tree = Backend::arithmetic_or_logical_expression (
    1304              :                     ArithmeticOrLogicalOperator::ADD, index_tree,
    1305              :                     Backend::size_constant_expression (1),
    1306           22 :                     pattern.get_locus ());
    1307              :                 }
    1308              :             }
    1309              :             break;
    1310            0 :           default:
    1311            0 :             rust_unreachable ();
    1312              :           }
    1313              :       }
    1314              :       break;
    1315              :     }
    1316           75 : }
    1317              : 
    1318              : //
    1319              : 
    1320              : void
    1321        11346 : CompilePatternLet::visit (HIR::IdentifierPattern &pattern)
    1322              : {
    1323        11346 :   Bvariable *var = nullptr;
    1324        11346 :   rust_assert (
    1325              :     ctx->lookup_var_decl (pattern.get_mappings ().get_hirid (), &var));
    1326              : 
    1327        11346 :   if (pattern.get_is_ref ())
    1328              :     {
    1329            2 :       init_expr = address_expression (init_expr, EXPR_LOCATION (init_expr));
    1330              :     }
    1331              : 
    1332        11346 :   auto fnctx = ctx->peek_fn ();
    1333        11346 :   if (ty->is_unit ())
    1334              :     {
    1335          251 :       ctx->add_statement (init_expr);
    1336              : 
    1337          251 :       auto unit_type_init_expr = unit_expression (rval_locus);
    1338          251 :       auto s = Backend::init_statement (fnctx.fndecl, var, unit_type_init_expr);
    1339          251 :       ctx->add_statement (s);
    1340              :     }
    1341              :   else
    1342              :     {
    1343        11095 :       if (pattern.has_subpattern ())
    1344              :         {
    1345            7 :           CompilePatternLet::Compile (&pattern.get_subpattern (), init_expr, ty,
    1346              :                                       rval_locus, ctx);
    1347              :         }
    1348        11095 :       auto s = Backend::init_statement (fnctx.fndecl, var, init_expr);
    1349        11095 :       ctx->add_statement (s);
    1350              :     }
    1351              : 
    1352        11346 :   TyTy::BaseType *drop_ty = ty;
    1353        11346 :   if (pattern.get_is_ref ())
    1354              :     {
    1355            2 :       auto ref_ty = ty->try_as<TyTy::ReferenceType> ();
    1356            0 :       rust_assert (ref_ty != nullptr);
    1357            2 :       drop_ty = ref_ty->get_base ();
    1358              :     }
    1359              : 
    1360        11346 :   if (!CompileDrop (ctx).type_has_drop_impl (drop_ty))
    1361        11332 :     return;
    1362              : 
    1363           14 :   if (!pattern.has_subpattern () && !pattern.get_is_ref ())
    1364              :     {
    1365           13 :       DropBuilder drop_builder (*ctx);
    1366           13 :       drop_builder.note_simple_drop_candidate (
    1367           13 :         pattern.get_mappings ().get_hirid (), pattern.get_locus ());
    1368              :     }
    1369              :   else
    1370            1 :     rust_sorry_at (pattern.get_locus (),
    1371              :                    "drop trait not supported for subpatterns and ref patterns");
    1372              : }
    1373              : 
    1374              : void
    1375          222 : CompilePatternLet::visit (HIR::WildcardPattern &pattern)
    1376              : {
    1377          222 :   tree init_stmt = NULL;
    1378          222 :   tree stmt_type = TyTyResolveCompile::compile (ctx, ty);
    1379              : 
    1380          222 :   Backend::temporary_variable (ctx->peek_fn ().fndecl, NULL_TREE, stmt_type,
    1381          222 :                                init_expr, false, pattern.get_locus (),
    1382              :                                &init_stmt);
    1383              : 
    1384          222 :   ctx->add_statement (init_stmt);
    1385          222 : }
    1386              : 
    1387              : void
    1388          289 : CompilePatternLet::visit (HIR::TuplePattern &pattern)
    1389              : {
    1390          289 :   rust_assert (pattern.has_tuple_pattern_items ());
    1391              : 
    1392          289 :   bool has_by_ref = false;
    1393          289 :   auto check_refs
    1394          291 :     = [] (const std::vector<std::unique_ptr<HIR::Pattern>> &patterns) {
    1395          879 :         for (const auto &sub : patterns)
    1396              :           {
    1397          589 :             switch (sub->get_pattern_type ())
    1398              :               {
    1399          573 :               case HIR::Pattern::PatternType::IDENTIFIER:
    1400          573 :                 {
    1401          573 :                   auto id = static_cast<HIR::IdentifierPattern *> (sub.get ());
    1402          573 :                   if (id->get_is_ref ())
    1403              :                     return true;
    1404              :                   break;
    1405              :                 }
    1406              :               case HIR::Pattern::PatternType::REFERENCE:
    1407              :                 return true;
    1408              :               default:
    1409              :                 break;
    1410              :               }
    1411              :           }
    1412              :         return false;
    1413              :       };
    1414          289 :   switch (pattern.get_items ().get_item_type ())
    1415              :     {
    1416          287 :     case HIR::TuplePatternItems::ItemType::NO_REST:
    1417          287 :       {
    1418          287 :         auto &items
    1419          287 :           = static_cast<HIR::TuplePatternItemsNoRest &> (pattern.get_items ());
    1420          287 :         has_by_ref = check_refs (items.get_patterns ());
    1421          287 :         break;
    1422              :       }
    1423            2 :     case HIR::TuplePatternItems::ItemType::HAS_REST:
    1424            2 :       {
    1425            2 :         auto &items
    1426            2 :           = static_cast<HIR::TuplePatternItemsHasRest &> (pattern.get_items ());
    1427            2 :         has_by_ref = check_refs (items.get_lower_patterns ())
    1428            2 :                      || check_refs (items.get_upper_patterns ());
    1429              :         break;
    1430              :       }
    1431              :     default:
    1432              :       break;
    1433              :     }
    1434              : 
    1435          289 :   tree rhs_tuple_type = TYPE_MAIN_VARIANT (TREE_TYPE (init_expr));
    1436          289 :   tree init_stmt;
    1437          289 :   Bvariable *tmp_var
    1438          289 :     = Backend::temporary_variable (ctx->peek_fn ().fndecl, NULL_TREE,
    1439              :                                    rhs_tuple_type, init_expr, has_by_ref,
    1440          289 :                                    pattern.get_locus (), &init_stmt);
    1441          289 :   tree access_expr = Backend::var_expression (tmp_var, pattern.get_locus ());
    1442          289 :   ctx->add_statement (init_stmt);
    1443              : 
    1444          289 :   switch (pattern.get_items ().get_item_type ())
    1445              :     {
    1446            2 :     case HIR::TuplePatternItems::ItemType::HAS_REST:
    1447            2 :       {
    1448            2 :         size_t tuple_idx = 0;
    1449            2 :         auto &items
    1450            2 :           = static_cast<HIR::TuplePatternItemsHasRest &> (pattern.get_items ());
    1451              : 
    1452            2 :         auto &items_lower = items.get_lower_patterns ();
    1453            2 :         auto &items_upper = items.get_upper_patterns ();
    1454              : 
    1455            4 :         for (auto &sub : items_lower)
    1456              :           {
    1457            2 :             TyTy::BaseType *ty_sub = nullptr;
    1458            2 :             HirId sub_id = sub->get_mappings ().get_hirid ();
    1459            2 :             bool ok = ctx->get_tyctx ()->lookup_type (sub_id, &ty_sub);
    1460            2 :             rust_assert (ok);
    1461              : 
    1462            2 :             tree sub_init
    1463            2 :               = Backend::struct_field_expression (access_expr, tuple_idx,
    1464            2 :                                                   sub->get_locus ());
    1465            2 :             CompilePatternLet::Compile (sub.get (), sub_init, ty_sub,
    1466              :                                         rval_locus, ctx);
    1467            2 :             tuple_idx++;
    1468              :           }
    1469              : 
    1470            2 :         rust_assert (ty->get_kind () == TyTy::TypeKind::TUPLE);
    1471            2 :         tuple_idx = static_cast<TyTy::TupleType &> (*ty).num_fields ()
    1472            2 :                     - items_upper.size ();
    1473              : 
    1474            4 :         for (auto &sub : items_upper)
    1475              :           {
    1476            2 :             TyTy::BaseType *ty_sub = nullptr;
    1477            2 :             HirId sub_id = sub->get_mappings ().get_hirid ();
    1478            2 :             bool ok = ctx->get_tyctx ()->lookup_type (sub_id, &ty_sub);
    1479            2 :             rust_assert (ok);
    1480              : 
    1481            2 :             tree sub_init
    1482            2 :               = Backend::struct_field_expression (access_expr, tuple_idx,
    1483            2 :                                                   sub->get_locus ());
    1484            2 :             CompilePatternLet::Compile (sub.get (), sub_init, ty_sub,
    1485              :                                         rval_locus, ctx);
    1486            2 :             tuple_idx++;
    1487              :           }
    1488              : 
    1489              :         return;
    1490              :       }
    1491          287 :     case HIR::TuplePatternItems::ItemType::NO_REST:
    1492          287 :       {
    1493          287 :         size_t tuple_idx = 0;
    1494          287 :         auto &items
    1495          287 :           = static_cast<HIR::TuplePatternItemsNoRest &> (pattern.get_items ());
    1496              : 
    1497          873 :         for (auto &sub : items.get_patterns ())
    1498              :           {
    1499          586 :             TyTy::BaseType *ty_sub = nullptr;
    1500          586 :             HirId sub_id = sub->get_mappings ().get_hirid ();
    1501          586 :             bool ok = ctx->get_tyctx ()->lookup_type (sub_id, &ty_sub);
    1502          586 :             rust_assert (ok);
    1503              : 
    1504          586 :             tree sub_init
    1505          586 :               = Backend::struct_field_expression (access_expr, tuple_idx,
    1506          586 :                                                   sub->get_locus ());
    1507          586 :             CompilePatternLet::Compile (sub.get (), sub_init, ty_sub,
    1508              :                                         rval_locus, ctx);
    1509          586 :             tuple_idx++;
    1510              :           }
    1511              : 
    1512              :         return;
    1513              :       }
    1514            0 :     default:
    1515            0 :       {
    1516            0 :         rust_unreachable ();
    1517              :       }
    1518              :     }
    1519              : }
    1520              : 
    1521              : } // namespace Compile
    1522              : } // 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.