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