[gcc r14-8107] gccrs: Compile pattern match statements into conditional statements

Arthur Cohen cohenarthur@gcc.gnu.org
Tue Jan 16 18:19:15 GMT 2024


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

commit r14-8107-gda87ef4d692b348be41c082eabb37f21af73f392
Author: Owen Avery <powerboat9.gamer@gmail.com>
Date:   Sun Oct 22 21:44:01 2023 -0400

    gccrs: 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.gamer@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 acec57de1b5..30863e46c6f 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 93a5f7cd5e4..9e134808564 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 23c0d1b8e74..17c82fa3050 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 8368fce69bc..0a3ba356b35 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;
 }


More information about the Gcc-cvs mailing list