From: Owen Avery <[email protected]>

Slice patterns with bound rest patterns still aren't supported in type
checking and compilation to GENERIC.

gcc/rust/ChangeLog:

        * backend/rust-compile-pattern.cc
        (CompilePatternBindings::visit (SlicePattern)): Assert that the
        rest pattern isn't bound (currently unsupported).
        * checks/errors/borrowck/rust-bir-builder-pattern.cc
        (PatternBindingBuilder::visit (SlicePattern)): Handle bound rest
        pattern.
        * checks/errors/rust-ast-validation.cc
        (ASTValidation::visit (AST::SlicePattern)): Likewise.
        * hir/rust-ast-lower-pattern.cc
        (ASTLoweringPattern::visit (AST::SlicePattern)): Likewise.
        * hir/rust-hir-dump.cc (Dump::visit (SlicePatternItemsHasRest)):
        Likewise.
        * hir/tree/rust-hir-pattern.h
        (SlicePatternItemsHasRest::rest_bind): New member variable.
        (SlicePatternItemsHasRest::SlicePatternItemsHasRest): Initialize
        rest_bind.
        (SlicePatternItemsHasRest::operator=): Likewise.
        (SlicePatternItemsHasRest::has_rest_bind): New member function.
        (SlicePatternItemsHasRest::get_rest_bind): Likewise.
        * hir/tree/rust-hir-visitor.cc
        (DefaultHIRVisitor::walk (SlicePatternItemsHasRest)): Handle
        bound rest pattern.
        * hir/tree/rust-hir.cc (SlicePatternItemsHasRest::to_string):
        Likewise.
        * typecheck/rust-hir-type-check-pattern.cc
        (TypeCheckPattern::visit (SlicePattern)): Assert that the rest
        pattern isn't bound (currently unsupported).

gcc/testsuite/ChangeLog:

        * rust/compile/slice_rest_pattern_2.rs: New test.

Signed-off-by: Owen Avery <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/78016dea955c55b476aef6a2d54786b060246c51

The commit has NOT been mentioned in any issue.

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4774

 gcc/rust/backend/rust-compile-pattern.cc      |  4 ++
 .../borrowck/rust-bir-builder-pattern.cc      |  4 ++
 gcc/rust/checks/errors/rust-ast-validation.cc | 21 +++++++++--
 gcc/rust/hir/rust-ast-lower-pattern.cc        | 37 +++++++++++++++++--
 gcc/rust/hir/rust-hir-dump.cc                 |  2 +
 gcc/rust/hir/tree/rust-hir-pattern.h          | 26 ++++++++++++-
 gcc/rust/hir/tree/rust-hir-visitor.cc         |  2 +
 gcc/rust/hir/tree/rust-hir.cc                 |  6 +++
 .../typecheck/rust-hir-type-check-pattern.cc  |  4 ++
 .../rust/compile/slice_rest_pattern_2.rs      | 11 ++++++
 10 files changed, 107 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/slice_rest_pattern_2.rs

diff --git a/gcc/rust/backend/rust-compile-pattern.cc 
b/gcc/rust/backend/rust-compile-pattern.cc
index e2f54d7ac..19f5bc4ed 100644
--- a/gcc/rust/backend/rust-compile-pattern.cc
+++ b/gcc/rust/backend/rust-compile-pattern.cc
@@ -1233,6 +1233,10 @@ CompilePatternBindings::visit (HIR::SlicePattern 
&pattern)
       {
        auto &items
          = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
+
+       // TODO: support rest_bind (c in [a, b, c @ ..])
+       rust_assert (!items.has_rest_bind ());
+
        for (auto &pattern_member : items.get_lower_patterns ())
          {
            tree index_tree
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc 
b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc
index e78d75050..5bd061470 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc
@@ -92,6 +92,10 @@ PatternBindingBuilder::visit (HIR::SlicePattern &pattern)
          {
            member->accept_vis (*this);
          }
+       if (items.has_rest_bind ())
+         {
+           items.get_rest_bind ().accept_vis (*this);
+         }
        for (auto &member : items.get_upper_patterns ())
          {
            member->accept_vis (*this);
diff --git a/gcc/rust/checks/errors/rust-ast-validation.cc 
b/gcc/rust/checks/errors/rust-ast-validation.cc
index e3262b947..b2825fb2c 100644
--- a/gcc/rust/checks/errors/rust-ast-validation.cc
+++ b/gcc/rust/checks/errors/rust-ast-validation.cc
@@ -205,14 +205,27 @@ ASTValidation::visit (AST::SlicePattern &pattern)
   //       for nicer errors
   bool had_rest = false;
 
+  auto note_rest = [&] (location_t locus) {
+    if (had_rest)
+      rust_error_at (locus, "%<..%> can only be used once per slice pattern");
+    had_rest = true;
+  };
+
   for (auto &pat : pattern.get_patterns ())
     {
       if (pat->get_pattern_kind () == AST::Pattern::Kind::Rest)
        {
-         if (had_rest)
-           rust_error_at (pat->get_locus (),
-                          "%<..%> can only be used once per slice pattern");
-         had_rest = true;
+         note_rest (pat->get_locus ());
+       }
+      else if (pat->get_pattern_kind () == AST::Pattern::Kind::Identifier)
+       {
+         auto &ident_pat = static_cast<AST::IdentifierPattern &> (*pat);
+         if (ident_pat.has_subpattern ())
+           {
+             auto &ident_sub_pat = ident_pat.get_subpattern ();
+             if (ident_sub_pat.get_pattern_kind () == AST::Pattern::Kind::Rest)
+               note_rest (ident_sub_pat.get_locus ());
+           }
        }
     }
 }
diff --git a/gcc/rust/hir/rust-ast-lower-pattern.cc 
b/gcc/rust/hir/rust-ast-lower-pattern.cc
index b19a6411d..17d4dc981 100644
--- a/gcc/rust/hir/rust-ast-lower-pattern.cc
+++ b/gcc/rust/hir/rust-ast-lower-pattern.cc
@@ -353,17 +353,46 @@ void
 ASTLoweringPattern::visit (AST::SlicePattern &pattern)
 {
   tl::optional<size_t> rest_index;
+  tl::optional<HIR::IdentifierPattern> rest_bind;
 
   std::vector<std::unique_ptr<AST::Pattern>> &sub_patterns
     = pattern.get_patterns ();
 
+  // need this earlier than usual
+  // since we might need to produce rest_bind
+  auto crate_num = mappings.get_current_crate ();
+
   for (size_t i = 0; i < sub_patterns.size (); i++)
     {
       auto &pat = sub_patterns[i];
-      if (pat->get_pattern_kind () == AST::Pattern::Kind::Rest)
+
+      // ASTValidation verified there's only one Rest pattern
+      // so we can break once we find the first one
+      if (pat->get_pattern_kind () == AST::Pattern::Kind::Identifier)
+       {
+         auto &ident_pat = static_cast<AST::IdentifierPattern &> (*pat);
+         if (ident_pat.has_subpattern ())
+           {
+             if (ident_pat.get_subpattern ().get_pattern_kind ()
+                 == AST::Pattern::Kind::Rest)
+               {
+                 Analysis::NodeMapping rest_bind_mapping (
+                   crate_num, ident_pat.get_node_id (),
+                   mappings.get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID);
+
+                 rest_bind = HIR::IdentifierPattern (
+                   std::move (rest_bind_mapping), ident_pat.get_ident (),
+                   ident_pat.get_locus (), ident_pat.get_is_ref (),
+                   ident_pat.get_is_mut () ? Mutability::Mut
+                                           : Mutability::Imm);
+                 rest_index = i;
+                 break;
+               }
+           }
+       }
+      else if (pat->get_pattern_kind () == AST::Pattern::Kind::Rest)
        {
          rest_index = i;
-         // ASTValidation verified there's only one Rest pattern
          break;
        }
     }
@@ -375,7 +404,8 @@ ASTLoweringPattern::visit (AST::SlicePattern &pattern)
       auto rest_it = sub_patterns.begin () + *rest_index;
       items = std::make_unique<HIR::SlicePatternItemsHasRest> (
        lower_pattern_seq (sub_patterns.begin (), rest_it),
-       lower_pattern_seq (rest_it + 1, sub_patterns.end ()));
+       lower_pattern_seq (rest_it + 1, sub_patterns.end ()),
+       std::move (rest_bind));
     }
   else
     {
@@ -383,7 +413,6 @@ ASTLoweringPattern::visit (AST::SlicePattern &pattern)
        lower_pattern_seq (sub_patterns.begin (), sub_patterns.end ()));
     }
 
-  auto crate_num = mappings.get_current_crate ();
   Analysis::NodeMapping mapping (crate_num, pattern.get_node_id (),
                                 mappings.get_next_hir_id (crate_num),
                                 UNKNOWN_LOCAL_DEFID);
diff --git a/gcc/rust/hir/rust-hir-dump.cc b/gcc/rust/hir/rust-hir-dump.cc
index 29b3ff92a..f21522b4d 100644
--- a/gcc/rust/hir/rust-hir-dump.cc
+++ b/gcc/rust/hir/rust-hir-dump.cc
@@ -2375,6 +2375,8 @@ Dump::visit (SlicePatternItemsHasRest &e)
 {
   begin ("SlicePatternItemsHasRest");
   visit_collection ("lower_patterns", e.get_lower_patterns ());
+  if (e.has_rest_bind ())
+    visit_field ("rest_bind", e.get_rest_bind ());
   visit_collection ("upper_patterns", e.get_upper_patterns ());
   end ("SlicePatternItemsHasRest");
 }
diff --git a/gcc/rust/hir/tree/rust-hir-pattern.h 
b/gcc/rust/hir/tree/rust-hir-pattern.h
index 90f8f5792..a56379d4a 100644
--- a/gcc/rust/hir/tree/rust-hir-pattern.h
+++ b/gcc/rust/hir/tree/rust-hir-pattern.h
@@ -1437,16 +1437,22 @@ class SlicePatternItemsHasRest : public 
SlicePatternItems
   std::vector<std::unique_ptr<Pattern>> lower_patterns;
   std::vector<std::unique_ptr<Pattern>> upper_patterns;
 
+  // c in [a, b, c @ ..]
+  tl::optional<IdentifierPattern> rest_bind;
+
 public:
   SlicePatternItemsHasRest (
     std::vector<std::unique_ptr<Pattern>> lower_patterns,
-    std::vector<std::unique_ptr<Pattern>> upper_patterns)
+    std::vector<std::unique_ptr<Pattern>> upper_patterns,
+    tl::optional<IdentifierPattern> rest_bind)
     : lower_patterns (std::move (lower_patterns)),
-      upper_patterns (std::move (upper_patterns))
+      upper_patterns (std::move (upper_patterns)),
+      rest_bind (std::move (rest_bind))
   {}
 
   // Copy constructor with vector clone
   SlicePatternItemsHasRest (SlicePatternItemsHasRest const &other)
+    : rest_bind (other.rest_bind)
   {
     lower_patterns.reserve (other.lower_patterns.size ());
     for (const auto &e : other.lower_patterns)
@@ -1470,6 +1476,8 @@ public:
     for (const auto &e : other.upper_patterns)
       upper_patterns.push_back (e->clone_pattern ());
 
+    rest_bind = other.rest_bind;
+
     return *this;
   }
 
@@ -1502,6 +1510,20 @@ public:
     return upper_patterns;
   }
 
+  bool has_rest_bind () const { return rest_bind.has_value (); }
+
+  IdentifierPattern &get_rest_bind ()
+  {
+    rust_assert (has_rest_bind ());
+    return *rest_bind;
+  }
+
+  const IdentifierPattern &get_rest_bind () const
+  {
+    rust_assert (has_rest_bind ());
+    return *rest_bind;
+  }
+
 protected:
   /* Use covariance to implement clone function as returning this object rather
    * than base */
diff --git a/gcc/rust/hir/tree/rust-hir-visitor.cc 
b/gcc/rust/hir/tree/rust-hir-visitor.cc
index 00b46e742..544c83db8 100644
--- a/gcc/rust/hir/tree/rust-hir-visitor.cc
+++ b/gcc/rust/hir/tree/rust-hir-visitor.cc
@@ -1077,6 +1077,8 @@ DefaultHIRVisitor::walk (SlicePatternItemsHasRest &items)
 {
   for (auto &lower : items.get_lower_patterns ())
     lower->accept_vis (*this);
+  if (items.has_rest_bind ())
+    items.get_rest_bind ().accept_vis (*this);
   for (auto &upper : items.get_upper_patterns ())
     upper->accept_vis (*this);
 }
diff --git a/gcc/rust/hir/tree/rust-hir.cc b/gcc/rust/hir/tree/rust-hir.cc
index 51b588a02..7d611ed5c 100644
--- a/gcc/rust/hir/tree/rust-hir.cc
+++ b/gcc/rust/hir/tree/rust-hir.cc
@@ -2449,6 +2449,12 @@ SlicePatternItemsHasRest::to_string () const
        }
     }
 
+  str += "\n Rest binding pattern: ";
+  if (rest_bind)
+    str += rest_bind->to_string ();
+  else
+    str += "none";
+
   str += "\n Upper patterns: ";
   if (upper_patterns.empty ())
     {
diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc 
b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
index 7d12bc7b4..83104833d 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
@@ -942,6 +942,10 @@ TypeCheckPattern::visit (HIR::SlicePattern &pattern)
       {
        auto &ref
          = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
+
+       // TODO: support rest_bind (c in [a, b, c @ ..])
+       rust_assert (!ref.has_rest_bind ());
+
        for (const auto &pattern_member : ref.get_lower_patterns ())
          {
            TypeCheckPattern::Resolve (*pattern_member, parent_element_ty);
diff --git a/gcc/testsuite/rust/compile/slice_rest_pattern_2.rs 
b/gcc/testsuite/rust/compile/slice_rest_pattern_2.rs
new file mode 100644
index 000000000..10316f750
--- /dev/null
+++ b/gcc/testsuite/rust/compile/slice_rest_pattern_2.rs
@@ -0,0 +1,11 @@
+// { dg-additional-options "-frust-compile-until=typecheck" }
+#![feature(no_core)]
+#![no_core]
+
+pub fn foo(x: &[u8]) -> i32 {
+    match x {
+        [] => 0,
+        [1, xs @ ..] => foo (xs),
+        [x, ..] => *x as i32
+    }
+}

base-commit: 84167f9bff1edb231d611e9b851f27bd4fe79b9e
-- 
2.54.0

Reply via email to