LCOV - code coverage report
Current view: top level - gcc/rust/backend - rust-compile-pattern.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 95.3 % 807 769
Test Date: 2026-02-28 14:20:25 Functions: 100.0 % 25 25
Legend: Lines:     hit not hit

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