https://gcc.gnu.org/g:e489a694c748ee205e5ac46eaafcb226f87f4538

commit e489a694c748ee205e5ac46eaafcb226f87f4538
Author: Owen Avery <powerboat9.ga...@gmail.com>
Date:   Sun Oct 22 21:44:01 2023 -0400

    Compile pattern match statements into conditional statements
    
    gcc/rust/ChangeLog:
    
            * backend/rust-compile-expr.cc
            (patterns_mergeable): Remove.
            (struct PatternMerge): Remove.
            (sort_tuple_patterns): Remove.
            (simplify_tuple_match): Remove.
            (CompileExpr::visit): Modify compilation of MatchExpr.
    
            * backend/rust-compile-pattern.cc
            (CompilePatternCaseLabelExpr::visit): Replace with...
            (CompilePatternCheckExpr::visit): ...this.
            * backend/rust-compile-pattern.h
            (class CompilePatternCaseLabelExpr): Replace with...
            (class CompilePatternCheckExpr): ...this.
    
            * backend/rust-compile-type.cc
            (TyTyResolveCompile::get_implicit_enumeral_node_type):
            Make enumeral type equivalent to isize.
    
    Signed-off-by: Owen Avery <powerboat9.ga...@gmail.com>

Diff:
---
 gcc/rust/backend/rust-compile-expr.cc    | 494 +++----------------------------
 gcc/rust/backend/rust-compile-pattern.cc | 331 ++++++++++++++++++---
 gcc/rust/backend/rust-compile-pattern.h  |  45 +--
 gcc/rust/backend/rust-compile-type.cc    |   7 +-
 4 files changed, 357 insertions(+), 520 deletions(-)

diff --git a/gcc/rust/backend/rust-compile-expr.cc 
b/gcc/rust/backend/rust-compile-expr.cc
index 5f4ce5411cee..71eeb076672a 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -929,322 +929,6 @@ CompileExpr::visit (HIR::AssignmentExpr &expr)
   ctx->add_statement (assignment);
 }
 
-// Helper for sort_tuple_patterns.
-// Determine whether Patterns a and b are really the same pattern.
-// FIXME: This is a nasty hack to avoid properly implementing a comparison
-//        for Patterns, which we really probably do want at some point.
-static bool
-patterns_mergeable (HIR::Pattern *a, HIR::Pattern *b)
-{
-  if (!a || !b)
-    return false;
-
-  HIR::Pattern::PatternType pat_type = a->get_pattern_type ();
-  if (b->get_pattern_type () != pat_type)
-    return false;
-
-  switch (pat_type)
-    {
-      case HIR::Pattern::PatternType::PATH: {
-       // FIXME: this is far too naive
-       HIR::PathPattern &aref = *static_cast<HIR::PathPattern *> (a);
-       HIR::PathPattern &bref = *static_cast<HIR::PathPattern *> (b);
-       if (aref.get_num_segments () != bref.get_num_segments ())
-         return false;
-
-       const auto &asegs = aref.get_segments ();
-       const auto &bsegs = bref.get_segments ();
-       for (size_t i = 0; i < asegs.size (); i++)
-         {
-           if (asegs[i].as_string () != bsegs[i].as_string ())
-             return false;
-         }
-       return true;
-      }
-      break;
-      case HIR::Pattern::PatternType::LITERAL: {
-       HIR::LiteralPattern &aref = *static_cast<HIR::LiteralPattern *> (a);
-       HIR::LiteralPattern &bref = *static_cast<HIR::LiteralPattern *> (b);
-       return aref.get_literal ().is_equal (bref.get_literal ());
-      }
-      break;
-      case HIR::Pattern::PatternType::IDENTIFIER: {
-       // TODO
-      }
-      break;
-    case HIR::Pattern::PatternType::WILDCARD:
-      return true;
-      break;
-
-      // TODO
-
-    default:;
-    }
-  return false;
-}
-
-// A little container for rearranging the patterns and cases in a match
-// expression while simplifying.
-struct PatternMerge
-{
-  std::unique_ptr<HIR::MatchCase> wildcard;
-  std::vector<std::unique_ptr<HIR::Pattern>> heads;
-  std::vector<std::vector<HIR::MatchCase>> cases;
-};
-
-// Helper for simplify_tuple_match.
-// For each tuple pattern in a given match, pull out the first elt of the
-// tuple and construct a new MatchCase with the remaining tuple elts as the
-// pattern. Return a mapping from each _unique_ first tuple element to a
-// vec of cases for a new match.
-//
-// FIXME: This used to be a std::map<Pattern, Vec<MatchCase>>, but it doesn't
-// actually work like we want - the Pattern includes an HIR ID, which is unique
-// per Pattern object. This means we don't have a good means for comparing
-// Patterns. It would probably be best to actually implement a means of
-// properly comparing patterns, and then use an actual map.
-//
-static struct PatternMerge
-sort_tuple_patterns (HIR::MatchExpr &expr)
-{
-  rust_assert (expr.get_scrutinee_expr ()->get_expression_type ()
-              == HIR::Expr::ExprType::Tuple);
-
-  struct PatternMerge result;
-  result.wildcard = nullptr;
-  result.heads = std::vector<std::unique_ptr<HIR::Pattern>> ();
-  result.cases = std::vector<std::vector<HIR::MatchCase>> ();
-
-  for (auto &match_case : expr.get_match_cases ())
-    {
-      HIR::MatchArm &case_arm = match_case.get_arm ();
-
-      // FIXME: Note we are only dealing with the first pattern in the arm.
-      // The patterns vector in the arm might hold many patterns, which are the
-      // patterns separated by the '|' token. Rustc abstracts these as "Or"
-      // patterns, and part of its simplification process is to get rid of 
them.
-      // We should get rid of the ORs too, maybe here or earlier than here?
-      auto pat = case_arm.get_patterns ()[0]->clone_pattern ();
-
-      // Record wildcards so we can add them in inner matches.
-      if (pat->get_pattern_type () == HIR::Pattern::PatternType::WILDCARD)
-       {
-         // The *whole* pattern is a wild card (_).
-         result.wildcard
-           = std::unique_ptr<HIR::MatchCase> (new HIR::MatchCase (match_case));
-         continue;
-       }
-
-      rust_assert (pat->get_pattern_type ()
-                  == HIR::Pattern::PatternType::TUPLE);
-
-      auto ref = *static_cast<HIR::TuplePattern *> (pat.get ());
-
-      rust_assert (ref.has_tuple_pattern_items ());
-
-      auto items
-       = HIR::TuplePattern (ref).get_items ()->clone_tuple_pattern_items ();
-      if (items->get_item_type ()
-         == HIR::TuplePatternItems::TuplePatternItemType::MULTIPLE)
-       {
-         auto items_ref
-           = *static_cast<HIR::TuplePatternItemsMultiple *> (items.get ());
-
-         // Pop the first pattern out
-         auto patterns = std::vector<std::unique_ptr<HIR::Pattern>> ();
-         auto first = items_ref.get_patterns ()[0]->clone_pattern ();
-         for (auto p = items_ref.get_patterns ().begin () + 1;
-              p != items_ref.get_patterns ().end (); p++)
-           {
-             patterns.push_back ((*p)->clone_pattern ());
-           }
-
-         // if there is only one pattern left, don't make a tuple out of it
-         std::unique_ptr<HIR::Pattern> result_pattern;
-         if (patterns.size () == 1)
-           {
-             result_pattern = std::move (patterns[0]);
-           }
-         else
-           {
-             auto new_items = std::unique_ptr<HIR::TuplePatternItems> (
-               new HIR::TuplePatternItemsMultiple (std::move (patterns)));
-
-             // Construct a TuplePattern from the rest of the patterns
-             result_pattern = std::unique_ptr<HIR::Pattern> (
-               new HIR::TuplePattern (ref.get_mappings (),
-                                      std::move (new_items),
-                                      ref.get_locus ()));
-           }
-
-         // I don't know why we need to make foo separately here but
-         // using the { new_tuple } syntax in new_arm constructor does not
-         // compile.
-         auto foo = std::vector<std::unique_ptr<HIR::Pattern>> ();
-         foo.emplace_back (std::move (result_pattern));
-         HIR::MatchArm new_arm (std::move (foo), UNDEF_LOCATION, nullptr,
-                                AST::AttrVec ());
-
-         HIR::MatchCase new_case (match_case.get_mappings (), new_arm,
-                                  match_case.get_expr ()->clone_expr ());
-
-         bool pushed = false;
-         for (size_t i = 0; i < result.heads.size (); i++)
-           {
-             if (patterns_mergeable (result.heads[i].get (), first.get ()))
-               {
-                 result.cases[i].push_back (new_case);
-                 pushed = true;
-               }
-           }
-
-         if (!pushed)
-           {
-             result.heads.push_back (std::move (first));
-             result.cases.push_back ({new_case});
-           }
-       }
-      else /* TuplePatternItemType::RANGED */
-       {
-         // FIXME
-         rust_unreachable ();
-       }
-    }
-
-  return result;
-}
-
-// Helper for CompileExpr::visit (HIR::MatchExpr).
-// Given a MatchExpr where the scrutinee is some kind of tuple, build an
-// equivalent match where only one element of the tuple is examined at a time.
-// This resulting match can then be lowered to a SWITCH_EXPR tree directly.
-//
-// The approach is as follows:
-// 1. Split the scrutinee and each pattern into the first (head) and the
-//    rest (tail).
-// 2. Build a mapping of unique pattern heads to the cases (tail and expr)
-//    that shared that pattern head in the original match.
-//    (This is the job of sort_tuple_patterns ()).
-// 3. For each unique pattern head, build a new MatchCase where the pattern
-//    is the unique head, and the expression is a new match where:
-//    - The scrutinee is the tail of the original scrutinee
-//    - The cases are are those built by the mapping in step 2, i.e. the
-//      tails of the patterns and the corresponing expressions from the
-//      original match expression.
-// 4. Do this recursively for each inner match, until there is nothing more
-//    to simplify.
-// 5. Build the resulting match which scrutinizes the head of the original
-//    scrutinee, using the cases built in step 3.
-static HIR::MatchExpr
-simplify_tuple_match (HIR::MatchExpr &expr)
-{
-  if (expr.get_scrutinee_expr ()->get_expression_type ()
-      != HIR::Expr::ExprType::Tuple)
-    return expr;
-
-  auto ref = *static_cast<HIR::TupleExpr *> (expr.get_scrutinee_expr ().get 
());
-
-  auto &tail = ref.get_tuple_elems ();
-  rust_assert (tail.size () > 1);
-
-  auto head = std::move (tail[0]);
-  tail.erase (tail.begin (), tail.begin () + 1);
-
-  // e.g.
-  // match (tupA, tupB, tupC) {
-  //   (a1, b1, c1) => { blk1 },
-  //   (a2, b2, c2) => { blk2 },
-  //   (a1, b3, c3) => { blk3 },
-  // }
-  // tail = (tupB, tupC)
-  // head = tupA
-
-  // Make sure the tail is only a tuple if it consists of at least 2 elements.
-  std::unique_ptr<HIR::Expr> remaining;
-  if (tail.size () == 1)
-    remaining = std::move (tail[0]);
-  else
-    remaining = std::unique_ptr<HIR::Expr> (
-      new HIR::TupleExpr (ref.get_mappings (), std::move (tail),
-                         AST::AttrVec (), ref.get_outer_attrs (),
-                         ref.get_locus ()));
-
-  // e.g.
-  // a1 -> [(b1, c1) => { blk1 },
-  //        (b3, c3) => { blk3 }]
-  // a2 -> [(b2, c2) => { blk2 }]
-  struct PatternMerge map = sort_tuple_patterns (expr);
-
-  std::vector<HIR::MatchCase> cases;
-  // Construct the inner match for each unique first elt of the tuple
-  // patterns
-  for (size_t i = 0; i < map.heads.size (); i++)
-    {
-      auto inner_match_cases = map.cases[i];
-
-      // If there is a wildcard at the outer match level, then need to
-      // propegate the wildcard case into *every* inner match.
-      // FIXME: It is probably not correct to add this unconditionally, what if
-      // we have a pattern like (a, _, c)? Then there is already a wildcard in
-      // the inner matches, and having two will cause two 'default:' blocks
-      // which is an error.
-      if (map.wildcard != nullptr)
-       {
-         inner_match_cases.push_back (*(map.wildcard.get ()));
-       }
-
-      // match (tupB, tupC) {
-      //   (b1, c1) => { blk1 },
-      //   (b3, c3) => { blk3 }
-      // }
-      HIR::MatchExpr inner_match (expr.get_mappings (),
-                                 remaining->clone_expr (), inner_match_cases,
-                                 AST::AttrVec (), expr.get_outer_attrs (),
-                                 expr.get_locus ());
-
-      inner_match = simplify_tuple_match (inner_match);
-
-      auto outer_arm_pat = std::vector<std::unique_ptr<HIR::Pattern>> ();
-      outer_arm_pat.emplace_back (map.heads[i]->clone_pattern ());
-
-      HIR::MatchArm outer_arm (std::move (outer_arm_pat), expr.get_locus ());
-
-      // Need to move the inner match to the heap and put it in a unique_ptr to
-      // build the actual match case of the outer expression
-      // auto inner_expr = std::unique_ptr<HIR::Expr> (new HIR::MatchExpr
-      // (inner_match));
-      auto inner_expr = inner_match.clone_expr ();
-
-      // a1 => match (tupB, tupC) { ... }
-      HIR::MatchCase outer_case (expr.get_mappings (), outer_arm,
-                                std::move (inner_expr));
-
-      cases.push_back (outer_case);
-    }
-
-  // If there was a wildcard, make sure to include it at the outer match level
-  // too.
-  if (map.wildcard != nullptr)
-    {
-      cases.push_back (*(map.wildcard.get ()));
-    }
-
-  // match tupA {
-  //   a1 => match (tupB, tupC) {
-  //     (b1, c1) => { blk1 },
-  //     (b3, c3) => { blk3 }
-  //   }
-  //   a2 => match (tupB, tupC) {
-  //     (b2, c2) => { blk2 }
-  //   }
-  // }
-  HIR::MatchExpr outer_match (expr.get_mappings (), std::move (head), cases,
-                             AST::AttrVec (), expr.get_outer_attrs (),
-                             expr.get_locus ());
-
-  return outer_match;
-}
-
 // Helper for CompileExpr::visit (HIR::MatchExpr).
 // Check that the scrutinee of EXPR is a valid kind of expression to match on.
 // Return the TypeKind of the scrutinee if it is valid, or 
TyTy::TypeKind::ERROR
@@ -1347,111 +1031,6 @@ CompileExpr::visit (HIR::MatchExpr &expr)
                                     expr.get_locus ());
   ctx->add_statement (assignment);
 
-  tree match_scrutinee_expr_qualifier_expr;
-  if (TyTy::is_primitive_type_kind (scrutinee_kind))
-    {
-      match_scrutinee_expr_qualifier_expr = match_scrutinee_expr;
-    }
-  else if (scrutinee_kind == TyTy::TypeKind::ADT)
-    {
-      // need to access qualifier the field, if we use QUAL_UNION_TYPE this
-      // would be DECL_QUALIFIER i think. For now this will just access the
-      // first record field and its respective qualifier because it will always
-      // be set because this is all a big special union
-      tree scrutinee_first_record_expr = Backend::struct_field_expression (
-       match_scrutinee_expr, 0, expr.get_scrutinee_expr ()->get_locus ());
-      match_scrutinee_expr_qualifier_expr = Backend::struct_field_expression (
-       scrutinee_first_record_expr, 0,
-       expr.get_scrutinee_expr ()->get_locus ());
-    }
-  else if (scrutinee_kind == TyTy::TypeKind::REF)
-    {
-      tree indirect
-       = indirect_expression (match_scrutinee_expr, expr.get_locus ());
-      match_scrutinee_expr_qualifier_expr = indirect;
-    }
-  else if (scrutinee_kind == TyTy::TypeKind::TUPLE)
-    {
-      // match on tuple becomes a series of nested switches, with one level
-      // for each element of the tuple from left to right.
-      auto exprtype = expr.get_scrutinee_expr ()->get_expression_type ();
-      switch (exprtype)
-       {
-         case HIR::Expr::ExprType::Tuple: {
-           // Build an equivalent expression which is nicer to lower.
-           HIR::MatchExpr outer_match = simplify_tuple_match (expr);
-
-           // We've rearranged the match into something that lowers better
-           // to GENERIC trees.
-           // For actually doing the lowering we need to compile the match
-           // we've just made. But we're half-way through compiling the
-           // original one.
-           // ...
-           // For now, let's just replace the original with the rearranged one
-           // we just made, and compile that instead. What could go wrong? :)
-           //
-           // FIXME: What about when we decide a temporary is needed above?
-           //        We might have already pushed a statement for it that
-           //        we no longer need. Probably need to rearrange the order
-           //        of these steps.
-           expr = outer_match;
-
-           scrutinee_kind = check_match_scrutinee (expr, ctx);
-           if (scrutinee_kind == TyTy::TypeKind::ERROR)
-             {
-               translated = error_mark_node;
-               return;
-             }
-
-           // Now compile the scrutinee of the simplified match.
-           // FIXME: this part is duplicated from above.
-           match_scrutinee_expr
-             = CompileExpr::Compile (expr.get_scrutinee_expr ().get (), ctx);
-
-           if (TyTy::is_primitive_type_kind (scrutinee_kind))
-             {
-               match_scrutinee_expr_qualifier_expr = match_scrutinee_expr;
-             }
-           else if (scrutinee_kind == TyTy::TypeKind::ADT)
-             {
-               // need to access qualifier the field, if we use QUAL_UNION_TYPE
-               // this would be DECL_QUALIFIER i think. For now this will just
-               // access the first record field and its respective qualifier
-               // because it will always be set because this is all a big
-               // special union
-               tree scrutinee_first_record_expr
-                 = Backend::struct_field_expression (
-                   match_scrutinee_expr, 0,
-                   expr.get_scrutinee_expr ()->get_locus ());
-               match_scrutinee_expr_qualifier_expr
-                 = Backend::struct_field_expression (
-                   scrutinee_first_record_expr, 0,
-                   expr.get_scrutinee_expr ()->get_locus ());
-             }
-           else
-             {
-               // FIXME: There are other cases, but it better not be a Tuple
-               rust_unreachable ();
-             }
-         }
-         break;
-
-         case HIR::Expr::ExprType::Path: {
-           // FIXME
-           rust_unreachable ();
-         }
-         break;
-
-       default:
-         rust_unreachable ();
-       }
-    }
-  else
-    {
-      // FIXME: match on other types of expressions not yet implemented.
-      rust_unreachable ();
-    }
-
   // setup the end label so the cases can exit properly
   tree fndecl = fnctx.fndecl;
   location_t end_label_locus = expr.get_locus (); // FIXME
@@ -1461,58 +1040,57 @@ CompileExpr::visit (HIR::MatchExpr &expr)
   tree end_label_decl_statement
     = Backend::label_definition_statement (end_label);
 
-  // setup the switch-body-block
-  location_t start_location = UNKNOWN_LOCATION; // FIXME
-  location_t end_location = UNKNOWN_LOCATION;  // FIXME
-  tree switch_body_block = Backend::block (fndecl, enclosing_scope, {},
-                                          start_location, end_location);
-  ctx->push_block (switch_body_block);
-
   for (auto &kase : expr.get_match_cases ())
     {
       // for now lets just get single pattern's working
       HIR::MatchArm &kase_arm = kase.get_arm ();
       rust_assert (kase_arm.get_patterns ().size () > 0);
 
-      // generate implicit label
-      location_t arm_locus = kase_arm.get_locus ();
-      tree case_label
-       = Backend::label (fndecl, "" /* empty creates an artificial label */,
-                         arm_locus);
-
-      // setup the bindings for the block
       for (auto &kase_pattern : kase_arm.get_patterns ())
        {
-         tree switch_kase_expr
-           = CompilePatternCaseLabelExpr::Compile (kase_pattern.get (),
-                                                   case_label, ctx);
-         ctx->add_statement (switch_kase_expr);
+         // setup the match-arm-body-block
+         location_t start_location = UNKNOWN_LOCATION; // FIXME
+         location_t end_location = UNKNOWN_LOCATION;   // FIXME
+         tree arm_body_block = Backend::block (fndecl, enclosing_scope, {},
+                                               start_location, end_location);
+
+         ctx->push_block (arm_body_block);
 
+         // setup the bindings for the block
          CompilePatternBindings::Compile (kase_pattern.get (),
                                           match_scrutinee_expr, ctx);
-       }
 
-      // compile the expr and setup the assignment if required when tmp != NULL
-      tree kase_expr_tree = CompileExpr::Compile (kase.get_expr ().get (), 
ctx);
-      tree result_reference = Backend::var_expression (tmp, arm_locus);
-      tree assignment
-       = Backend::assignment_statement (result_reference, kase_expr_tree,
-                                        arm_locus);
-      ctx->add_statement (assignment);
-
-      // go to end label
-      tree goto_end_label
-       = build1_loc (arm_locus, GOTO_EXPR, void_type_node, end_label);
-      ctx->add_statement (goto_end_label);
+         // compile the expr and setup the assignment if required when tmp !=
+         // NULL
+         location_t arm_locus = kase_arm.get_locus ();
+         tree kase_expr_tree
+           = CompileExpr::Compile (kase.get_expr ().get (), ctx);
+         tree result_reference = Backend::var_expression (tmp, arm_locus);
+         tree assignment
+           = Backend::assignment_statement (result_reference, kase_expr_tree,
+                                            arm_locus);
+         ctx->add_statement (assignment);
+
+         // go to end label
+         tree goto_end_label
+           = build1_loc (arm_locus, GOTO_EXPR, void_type_node, end_label);
+         ctx->add_statement (goto_end_label);
+
+         ctx->pop_block ();
+
+         tree check_expr
+           = CompilePatternCheckExpr::Compile (kase_pattern.get (),
+                                               match_scrutinee_expr, ctx);
+
+         tree check_stmt
+           = Backend::if_statement (NULL_TREE, check_expr, arm_body_block,
+                                    NULL_TREE, kase_pattern->get_locus ());
+
+         ctx->add_statement (check_stmt);
+       }
     }
 
   // setup the switch expression
-  tree match_body = ctx->pop_block ();
-  tree match_expr_stmt
-    = build2_loc (expr.get_locus (), SWITCH_EXPR,
-                 TREE_TYPE (match_scrutinee_expr_qualifier_expr),
-                 match_scrutinee_expr_qualifier_expr, match_body);
-  ctx->add_statement (match_expr_stmt);
   ctx->add_statement (end_label_decl_statement);
 
   translated = Backend::var_expression (tmp, expr.get_locus ());
diff --git a/gcc/rust/backend/rust-compile-pattern.cc 
b/gcc/rust/backend/rust-compile-pattern.cc
index 5358c8a6dc4e..5e3026996aed 100644
--- a/gcc/rust/backend/rust-compile-pattern.cc
+++ b/gcc/rust/backend/rust-compile-pattern.cc
@@ -26,7 +26,7 @@ namespace Rust {
 namespace Compile {
 
 void
-CompilePatternCaseLabelExpr::visit (HIR::PathInExpression &pattern)
+CompilePatternCheckExpr::visit (HIR::PathInExpression &pattern)
 {
   // lookup the type
   TyTy::BaseType *lookup = nullptr;
@@ -36,6 +36,7 @@ CompilePatternCaseLabelExpr::visit (HIR::PathInExpression 
&pattern)
   rust_assert (ok);
 
   // this must be an enum
+  // TODO: might not be
   rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
   rust_assert (adt->is_enum ());
@@ -50,38 +51,28 @@ CompilePatternCaseLabelExpr::visit (HIR::PathInExpression 
&pattern)
   ok = adt->lookup_variant_by_id (variant_id, &variant);
   rust_assert (ok);
 
-  HIR::Expr *discrim_expr = variant->get_discriminant ();
-  tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
-  tree folded_discrim_expr = fold_expr (discrim_expr_node);
-  tree case_low = folded_discrim_expr;
+  // find discriminant field of scrutinee
+  tree scrutinee_record_expr
+    = Backend::struct_field_expression (match_scrutinee_expr, 0,
+                                       pattern.get_locus ());
+  tree scrutinee_expr_qualifier_expr
+    = Backend::struct_field_expression (scrutinee_record_expr, 0,
+                                       pattern.get_locus ());
 
-  case_label_expr
-    = build_case_label (case_low, NULL_TREE, associated_case_label);
-}
-
-void
-CompilePatternCaseLabelExpr::visit (HIR::StructPattern &pattern)
-{
-  CompilePatternCaseLabelExpr::visit (pattern.get_path ());
-}
+  // must be enum
+  match_scrutinee_expr = scrutinee_expr_qualifier_expr;
 
-void
-CompilePatternCaseLabelExpr::visit (HIR::TupleStructPattern &pattern)
-{
-  CompilePatternCaseLabelExpr::visit (pattern.get_path ());
-}
+  HIR::Expr *discrim_expr = variant->get_discriminant ();
+  tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
 
-void
-CompilePatternCaseLabelExpr::visit (HIR::WildcardPattern &pattern)
-{
-  // operand 0 being NULL_TREE signifies this is the default case label see:
-  // tree.def for documentation for CASE_LABEL_EXPR
-  case_label_expr
-    = build_case_label (NULL_TREE, NULL_TREE, associated_case_label);
+  check_expr
+    = Backend::comparison_expression (ComparisonOperator::EQUAL,
+                                     match_scrutinee_expr, discrim_expr_node,
+                                     pattern.get_locus ());
 }
 
 void
-CompilePatternCaseLabelExpr::visit (HIR::LiteralPattern &pattern)
+CompilePatternCheckExpr::visit (HIR::LiteralPattern &pattern)
 {
   // Compile the literal
   HIR::LiteralExpr *litexpr
@@ -101,18 +92,9 @@ CompilePatternCaseLabelExpr::visit (HIR::LiteralPattern 
&pattern)
 
   tree lit = CompileExpr::Compile (litexpr, ctx);
 
-  case_label_expr = build_case_label (lit, NULL_TREE, associated_case_label);
-}
-
-void
-CompilePatternCaseLabelExpr::visit (HIR::AltPattern &pattern)
-{
-  const auto &alts = pattern.get_alts ();
-  for (auto &alt_pattern : alts)
-    {
-      CompilePatternCaseLabelExpr::Compile (alt_pattern.get (),
-                                           associated_case_label, ctx);
-    }
+  check_expr = Backend::comparison_expression (ComparisonOperator::EQUAL,
+                                              match_scrutinee_expr, lit,
+                                              pattern.get_locus ());
 }
 
 static tree
@@ -161,7 +143,7 @@ compile_range_pattern_bound (HIR::RangePatternBound *bound,
 }
 
 void
-CompilePatternCaseLabelExpr::visit (HIR::RangePattern &pattern)
+CompilePatternCheckExpr::visit (HIR::RangePattern &pattern)
 {
   tree upper = compile_range_pattern_bound (pattern.get_upper_bound ().get (),
                                            pattern.get_mappings (),
@@ -170,7 +152,274 @@ CompilePatternCaseLabelExpr::visit (HIR::RangePattern 
&pattern)
                                            pattern.get_mappings (),
                                            pattern.get_locus (), ctx);
 
-  case_label_expr = build_case_label (lower, upper, associated_case_label);
+  tree check_lower
+    = Backend::comparison_expression (ComparisonOperator::GREATER_OR_EQUAL,
+                                     match_scrutinee_expr, lower,
+                                     pattern.get_locus ());
+  tree check_upper
+    = Backend::comparison_expression (ComparisonOperator::LESS_OR_EQUAL,
+                                     match_scrutinee_expr, upper,
+                                     pattern.get_locus ());
+  check_expr = Backend::arithmetic_or_logical_expression (
+    ArithmeticOrLogicalOperator::BITWISE_AND, check_lower, check_upper,
+    pattern.get_locus ());
+}
+
+void
+CompilePatternCheckExpr::visit (HIR::ReferencePattern &pattern)
+{
+  match_scrutinee_expr
+    = indirect_expression (match_scrutinee_expr, pattern.get_locus ());
+  pattern.get_referenced_pattern ()->accept_vis (*this);
+}
+
+void
+CompilePatternCheckExpr::visit (HIR::AltPattern &pattern)
+{
+  auto &alts = pattern.get_alts ();
+
+  check_expr = CompilePatternCheckExpr::Compile (alts.at (0).get (),
+                                                match_scrutinee_expr, ctx);
+  auto end = alts.end ();
+  for (auto i = alts.begin () + 1; i != end; i++)
+    {
+      tree next_expr
+       = CompilePatternCheckExpr::Compile (i->get (), match_scrutinee_expr,
+                                           ctx);
+      check_expr = Backend::arithmetic_or_logical_expression (
+       ArithmeticOrLogicalOperator::BITWISE_OR, check_expr, next_expr,
+       (*i)->get_locus ());
+    }
+}
+
+void
+CompilePatternCheckExpr::visit (HIR::StructPattern &pattern)
+{
+  // lookup the type
+  TyTy::BaseType *lookup = nullptr;
+  bool ok = ctx->get_tyctx ()->lookup_type (
+    pattern.get_path ().get_mappings ().get_hirid (), &lookup);
+  rust_assert (ok);
+
+  // this might be an enum
+  rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
+  TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
+
+  rust_assert (adt->number_of_variants () > 0);
+  TyTy::VariantDef *variant = nullptr;
+  if (adt->is_enum ())
+    {
+      // lookup the variant
+      HirId variant_id;
+      ok = ctx->get_tyctx ()->lookup_variant_definition (
+       pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
+      rust_assert (ok);
+
+      int variant_index = 0;
+      ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
+      rust_assert (ok);
+
+      // find expected discriminant
+      // // need to access qualifier the field, if we use QUAL_UNION_TYPE this
+      // // would be DECL_QUALIFIER i think. For now this will just access the
+      // // first record field and its respective qualifier because it will
+      // // always be set because this is all a big special union
+      HIR::Expr *discrim_expr = variant->get_discriminant ();
+      tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
+
+      // find discriminant field of scrutinee
+      tree scrutinee_record_expr
+       = Backend::struct_field_expression (match_scrutinee_expr, variant_index,
+                                           pattern.get_path ().get_locus ());
+      tree scrutinee_expr_qualifier_expr
+       = Backend::struct_field_expression (scrutinee_record_expr, 0,
+                                           pattern.get_path ().get_locus ());
+
+      check_expr
+       = Backend::comparison_expression (ComparisonOperator::EQUAL,
+                                         scrutinee_expr_qualifier_expr,
+                                         discrim_expr_node,
+                                         pattern.get_path ().get_locus ());
+
+      match_scrutinee_expr = scrutinee_record_expr;
+    }
+  else
+    {
+      variant = adt->get_variants ().at (0);
+      check_expr = boolean_true_node;
+    }
+
+  auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
+  for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
+    {
+      switch (field->get_item_type ())
+       {
+         case HIR::StructPatternField::ItemType::TUPLE_PAT: {
+           // TODO
+           rust_unreachable ();
+         }
+         break;
+
+         case HIR::StructPatternField::ItemType::IDENT_PAT: {
+           HIR::StructPatternFieldIdentPat &ident
+             = static_cast<HIR::StructPatternFieldIdentPat &> (*field.get ());
+
+           size_t offs = 0;
+           ok = variant->lookup_field (ident.get_identifier ().as_string (),
+                                       nullptr, &offs);
+           rust_assert (ok);
+
+           // we may be offsetting by + 1 here since the first field in the
+           // record is always the discriminator
+           offs += adt->is_enum ();
+           tree field_expr
+             = Backend::struct_field_expression (match_scrutinee_expr, offs,
+                                                 ident.get_locus ());
+
+           tree check_expr_sub
+             = CompilePatternCheckExpr::Compile (ident.get_pattern ().get (),
+                                                 field_expr, ctx);
+           check_expr = Backend::arithmetic_or_logical_expression (
+             ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
+             check_expr_sub, ident.get_pattern ()->get_locus ());
+         }
+         break;
+
+         case HIR::StructPatternField::ItemType::IDENT: {
+           // ident pattern always matches - do nothing
+         }
+         break;
+       }
+    }
+}
+
+void
+CompilePatternCheckExpr::visit (HIR::TupleStructPattern &pattern)
+{
+  size_t tuple_field_index;
+
+  // lookup the type
+  TyTy::BaseType *lookup = nullptr;
+  bool ok = ctx->get_tyctx ()->lookup_type (
+    pattern.get_path ().get_mappings ().get_hirid (), &lookup);
+  rust_assert (ok);
+
+  // this might be an enum
+  rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
+  TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
+
+  rust_assert (adt->number_of_variants () > 0);
+  TyTy::VariantDef *variant = nullptr;
+  if (adt->is_enum ())
+    {
+      // lookup the variant
+      HirId variant_id;
+      ok = ctx->get_tyctx ()->lookup_variant_definition (
+       pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
+      rust_assert (ok);
+
+      int variant_index = 0;
+      ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
+      rust_assert (ok);
+
+      // find expected discriminant
+      HIR::Expr *discrim_expr = variant->get_discriminant ();
+      tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
+
+      // find discriminant field of scrutinee
+      tree scrutinee_record_expr
+       = Backend::struct_field_expression (match_scrutinee_expr, variant_index,
+                                           pattern.get_path ().get_locus ());
+      tree scrutinee_expr_qualifier_expr
+       = Backend::struct_field_expression (scrutinee_record_expr, 0,
+                                           pattern.get_path ().get_locus ());
+
+      check_expr
+       = Backend::comparison_expression (ComparisonOperator::EQUAL,
+                                         scrutinee_expr_qualifier_expr,
+                                         discrim_expr_node,
+                                         pattern.get_path ().get_locus ());
+
+      match_scrutinee_expr = scrutinee_record_expr;
+      // we are offsetting by + 1 here since the first field in the record
+      // is always the discriminator
+      tuple_field_index = 1;
+    }
+  else
+    {
+      variant = adt->get_variants ().at (0);
+      check_expr = boolean_true_node;
+      tuple_field_index = 0;
+    }
+
+  std::unique_ptr<HIR::TupleStructItems> &items = pattern.get_items ();
+  switch (items->get_item_type ())
+    {
+      case HIR::TupleStructItems::RANGE: {
+       // TODO
+       rust_unreachable ();
+      }
+      break;
+
+      case HIR::TupleStructItems::NO_RANGE: {
+       HIR::TupleStructItemsNoRange &items_no_range
+         = static_cast<HIR::TupleStructItemsNoRange &> (*items.get ());
+
+       rust_assert (items_no_range.get_patterns ().size ()
+                    == variant->num_fields ());
+
+       for (auto &pattern : items_no_range.get_patterns ())
+         {
+           tree field_expr
+             = Backend::struct_field_expression (match_scrutinee_expr,
+                                                 tuple_field_index++,
+                                                 pattern->get_locus ());
+
+           tree check_expr_sub
+             = CompilePatternCheckExpr::Compile (pattern.get (), field_expr,
+                                                 ctx);
+           check_expr = Backend::arithmetic_or_logical_expression (
+             ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
+             check_expr_sub, pattern->get_locus ());
+         }
+      }
+      break;
+    }
+}
+
+void
+CompilePatternCheckExpr::visit (HIR::TuplePattern &pattern)
+{
+  check_expr = boolean_true_node;
+
+  switch (pattern.get_items ()->get_item_type ())
+    {
+      case HIR::TuplePatternItems::RANGED: {
+       // TODO
+       gcc_unreachable ();
+      }
+      break;
+
+      case HIR::TuplePatternItems::MULTIPLE: {
+       auto &items = static_cast<HIR::TuplePatternItemsMultiple &> (
+         *pattern.get_items ());
+       size_t tuple_field_index = 0;
+
+       for (auto &pat : items.get_patterns ())
+         {
+           tree field_expr
+             = Backend::struct_field_expression (match_scrutinee_expr,
+                                                 tuple_field_index++,
+                                                 pat->get_locus ());
+
+           tree check_expr_sub
+             = CompilePatternCheckExpr::Compile (pat.get (), field_expr, ctx);
+           check_expr = Backend::arithmetic_or_logical_expression (
+             ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
+             check_expr_sub, pat->get_locus ());
+         }
+      }
+    }
 }
 
 // setup the bindings
diff --git a/gcc/rust/backend/rust-compile-pattern.h 
b/gcc/rust/backend/rust-compile-pattern.h
index 78121e51ddcb..0cf26ccc7554 100644
--- a/gcc/rust/backend/rust-compile-pattern.h
+++ b/gcc/rust/backend/rust-compile-pattern.h
@@ -22,40 +22,49 @@
 namespace Rust {
 namespace Compile {
 
-class CompilePatternCaseLabelExpr : public HIRCompileBase,
-                                   public HIR::HIRPatternVisitor
+class CompilePatternCheckExpr : public HIRCompileBase,
+                               public HIR::HIRPatternVisitor
 {
 public:
-  static tree Compile (HIR::Pattern *pattern, tree associated_case_label,
+  static tree Compile (HIR::Pattern *pattern, tree match_scrutinee_expr,
                       Context *ctx)
   {
-    CompilePatternCaseLabelExpr compiler (ctx, associated_case_label);
+    CompilePatternCheckExpr compiler (ctx, match_scrutinee_expr);
     pattern->accept_vis (compiler);
-    return compiler.case_label_expr;
+    rust_assert (compiler.check_expr);
+    return compiler.check_expr;
   }
 
   void visit (HIR::PathInExpression &pattern) override;
-  void visit (HIR::StructPattern &pattern) override;
-  void visit (HIR::TupleStructPattern &pattern) override;
-  void visit (HIR::WildcardPattern &pattern) override;
+  void visit (HIR::LiteralPattern &) override;
   void visit (HIR::RangePattern &pattern) override;
-  void visit (HIR::AltPattern &pattern) override;
+  void visit (HIR::ReferencePattern &) override;
+  void visit (HIR::AltPattern &) override;
+  void visit (HIR::StructPattern &) override;
+  void visit (HIR::TupleStructPattern &) override;
+  void visit (HIR::TuplePattern &) override;
+
+  // Always succeeds
+  void visit (HIR::IdentifierPattern &) override
+  {
+    check_expr = boolean_true_node;
+  }
+  void visit (HIR::WildcardPattern &) override
+  {
+    check_expr = boolean_true_node;
+  }
 
   // Empty visit for unused Pattern HIR nodes.
-  void visit (HIR::IdentifierPattern &) override {}
-  void visit (HIR::LiteralPattern &) override;
   void visit (HIR::QualifiedPathInExpression &) override {}
-  void visit (HIR::ReferencePattern &) override {}
   void visit (HIR::SlicePattern &) override {}
-  void visit (HIR::TuplePattern &) override {}
 
-  CompilePatternCaseLabelExpr (Context *ctx, tree associated_case_label)
-    : HIRCompileBase (ctx), case_label_expr (error_mark_node),
-      associated_case_label (associated_case_label)
+  CompilePatternCheckExpr (Context *ctx, tree match_scrutinee_expr)
+    : HIRCompileBase (ctx), match_scrutinee_expr (match_scrutinee_expr),
+      check_expr (NULL_TREE)
   {}
 
-  tree case_label_expr;
-  tree associated_case_label;
+  tree match_scrutinee_expr;
+  tree check_expr;
 };
 
 class CompilePatternBindings : public HIRCompileBase,
diff --git a/gcc/rust/backend/rust-compile-type.cc 
b/gcc/rust/backend/rust-compile-type.cc
index 232f965bd7a4..9ca65b331267 100644
--- a/gcc/rust/backend/rust-compile-type.cc
+++ b/gcc/rust/backend/rust-compile-type.cc
@@ -79,9 +79,10 @@ TyTyResolveCompile::get_implicit_enumeral_node_type (Context 
*ctx)
   static tree enum_node = NULL_TREE;
   if (enum_node == NULL_TREE)
     {
-      enum_node
-       = Backend::named_type ("enumeral", Backend::integer_type (false, 64),
-                              BUILTINS_LOCATION);
+      // equivalent to isize
+      enum_node = Backend::named_type (
+       "enumeral", Backend::integer_type (false, Backend::get_pointer_size ()),
+       BUILTINS_LOCATION);
     }
   return enum_node;
 }

Reply via email to