]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: Add rest pattern support for AST::SlicePattern
authorYap Zhi Heng <yapzhhg@gmail.com>
Wed, 30 Jul 2025 15:37:43 +0000 (23:37 +0800)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 5 Aug 2025 14:37:01 +0000 (16:37 +0200)
The main change can be found in ast/rust-pattern.h, which introduces 2 item types for
AST::SlicePattern - one without rest pattern (SlicePatternItemsNoRest) & the other with
it (SlicePatternItemsHasRest). This led to a number of cascading changes as seen in the
changelog.

gcc/rust/ChangeLog:

* ast/rust-ast-collector.cc: Add support for the 2 new classes.
* ast/rust-ast-collector.h: Header file update for above.
* ast/rust-ast-full-decls.h: Add forward decls for the 2 new classes.
* ast/rust-ast-visitor.cc: Add visit support for the 2 new classes.
* ast/rust-ast-visitor.h: Header file update for above.
* ast/rust-pattern.cc: Implementation of certain methods for the 2 new classes.
* ast/rust-pattern.h: Define the 2 new classes. Update SlicePattern to be able to hold
2 kinds of items - SlicePatternItemsNoRest or SlicePatternItemsRest.
* expand/rust-cfg-strip.cc: Add support for the 2 new classes.
* expand/rust-cfg-strip.h: Header file update for above.
* expand/rust-derive.h: Add visits for the 2 new classes.
* hir/rust-ast-lower-base.cc: Add visits for the 2 new classes.
* hir/rust-ast-lower-base.h: Header file update for above.
* hir/rust-ast-lower-pattern.cc: Update lowering of SlicePattern to support
SlicePatternItemsNoRest.
* parse/rust-parse-impl.h (parse_slice_pattern()): Add support for parsing DOT_DOT into
respective SlicePatternItems.
* resolve/rust-ast-resolve-base.cc: Add visits for the 2 new classes.
* resolve/rust-ast-resolve-base.h: Header file update for above.
* resolve/rust-ast-resolve-pattern.cc: Update SlicePattern resolution to support new
classes.

Signed-off-by: Yap Zhi Heng <yapzhhg@gmail.com>
17 files changed:
gcc/rust/ast/rust-ast-collector.cc
gcc/rust/ast/rust-ast-collector.h
gcc/rust/ast/rust-ast-full-decls.h
gcc/rust/ast/rust-ast-visitor.cc
gcc/rust/ast/rust-ast-visitor.h
gcc/rust/ast/rust-pattern.cc
gcc/rust/ast/rust-pattern.h
gcc/rust/expand/rust-cfg-strip.cc
gcc/rust/expand/rust-cfg-strip.h
gcc/rust/expand/rust-derive.h
gcc/rust/hir/rust-ast-lower-base.cc
gcc/rust/hir/rust-ast-lower-base.h
gcc/rust/hir/rust-ast-lower-pattern.cc
gcc/rust/parse/rust-parse-impl.h
gcc/rust/resolve/rust-ast-resolve-base.cc
gcc/rust/resolve/rust-ast-resolve-base.h
gcc/rust/resolve/rust-ast-resolve-pattern.cc

index b27a3af11e80ad493970dda55e89799d51ba33b1..677c2472e6f59a0cd07785b1145c12a2c014145e 100644 (file)
@@ -2717,11 +2717,35 @@ TokenCollector::visit (GroupedPattern &pattern)
   push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
 }
 
+void
+TokenCollector::visit (SlicePatternItemsNoRest &items)
+{
+  visit_items_joined_by_separator (items.get_patterns (), COMMA);
+}
+
+void
+TokenCollector::visit (SlicePatternItemsHasRest &items)
+{
+  if (!items.get_lower_patterns ().empty ())
+    {
+      visit_items_joined_by_separator (items.get_lower_patterns (), COMMA);
+      push (Rust::Token::make (COMMA, UNDEF_LOCATION));
+    }
+
+  push (Rust::Token::make (DOT_DOT, UNDEF_LOCATION));
+
+  if (!items.get_upper_patterns ().empty ())
+    {
+      push (Rust::Token::make (COMMA, UNDEF_LOCATION));
+      visit_items_joined_by_separator (items.get_upper_patterns (), COMMA);
+    }
+}
+
 void
 TokenCollector::visit (SlicePattern &pattern)
 {
   push (Rust::Token::make (LEFT_SQUARE, pattern.get_locus ()));
-  visit_items_joined_by_separator (pattern.get_items (), COMMA);
+  visit (pattern.get_items ());
   push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
 }
 
index 767d211ddf3ad922bb1729dfa3ebf93da80e5040..9ffbfced47d7e244ab5a2e4a04ba72854b9b0001 100644 (file)
@@ -378,6 +378,8 @@ public:
   void visit (TuplePatternItemsRanged &tuple_items);
   void visit (TuplePattern &pattern);
   void visit (GroupedPattern &pattern);
+  void visit (SlicePatternItemsNoRest &items);
+  void visit (SlicePatternItemsHasRest &items);
   void visit (SlicePattern &pattern);
   void visit (AltPattern &pattern);
 
index eb1f3ea890c76a167a1240e3abaa35c8b90bd5ef..1dfb25c4363b46d10003a34d38cd012e6ed9633d 100644 (file)
@@ -248,6 +248,8 @@ class TuplePatternItemsMultiple;
 class TuplePatternItemsRanged;
 class TuplePattern;
 class GroupedPattern;
+class SlicePatternItemsNoRest;
+class SlicePatternItemsHasRest;
 class SlicePattern;
 class AltPattern;
 
index f752b3a8f1583d86de80efbccab74c6dd8f44dfd..88dc24b570c851d8cbd97d14c038ef2bfd780e4f 100644 (file)
@@ -1347,12 +1347,27 @@ DefaultASTVisitor::visit (AST::GroupedPattern &pattern)
 }
 
 void
-DefaultASTVisitor::visit (AST::SlicePattern &pattern)
+DefaultASTVisitor::visit (AST::SlicePatternItemsNoRest &items)
 {
-  for (auto &item : pattern.get_items ())
+  for (auto &item : items.get_patterns ())
+    visit (item);
+}
+
+void
+DefaultASTVisitor::visit (AST::SlicePatternItemsHasRest &items)
+{
+  for (auto &item : items.get_lower_patterns ())
+    visit (item);
+  for (auto &item : items.get_upper_patterns ())
     visit (item);
 }
 
+void
+DefaultASTVisitor::visit (AST::SlicePattern &pattern)
+{
+  visit (pattern.get_items ());
+}
+
 void
 DefaultASTVisitor::visit (AST::AltPattern &pattern)
 {
index 020400dde3fe1e6eca3167e138ddf7701c639345..a5469cccb4233104e24e5c14a415c760dc2b3c83 100644 (file)
@@ -212,6 +212,8 @@ public:
   virtual void visit (TuplePatternItemsRanged &tuple_items) = 0;
   virtual void visit (TuplePattern &pattern) = 0;
   virtual void visit (GroupedPattern &pattern) = 0;
+  virtual void visit (SlicePatternItemsNoRest &items) = 0;
+  virtual void visit (SlicePatternItemsHasRest &items) = 0;
   virtual void visit (SlicePattern &pattern) = 0;
   virtual void visit (AltPattern &pattern) = 0;
 
@@ -386,6 +388,8 @@ public:
   virtual void visit (AST::TuplePatternItemsRanged &tuple_items) override;
   virtual void visit (AST::TuplePattern &pattern) override;
   virtual void visit (AST::GroupedPattern &pattern) override;
+  virtual void visit (AST::SlicePatternItemsNoRest &items) override;
+  virtual void visit (AST::SlicePatternItemsHasRest &items) override;
   virtual void visit (AST::SlicePattern &pattern) override;
   virtual void visit (AST::AltPattern &pattern) override;
   virtual void visit (AST::EmptyStmt &stmt) override;
index 62bf6f2c5e89bf81204b238de903cb6418c7aa6a..15ab0b75741db364d7bce8a8e3fd80ac466cd53b 100644 (file)
@@ -327,16 +327,52 @@ GroupedExpr::as_string () const
 }
 
 std::string
-SlicePattern::as_string () const
+SlicePatternItemsNoRest::as_string () const
 {
-  std::string str ("SlicePattern: ");
+  std::string str;
 
-  for (const auto &pattern : items)
+  for (const auto &pattern : patterns)
     str += "\n " + pattern->as_string ();
 
   return str;
 }
 
+std::string
+SlicePatternItemsHasRest::as_string () const
+{
+  std::string str;
+
+  str += "\n Lower patterns: ";
+  if (lower_patterns.empty ())
+    {
+      str += "none";
+    }
+  else
+    {
+      for (const auto &lower : lower_patterns)
+       str += "\n  " + lower->as_string ();
+    }
+
+  str += "\n Upper patterns: ";
+  if (upper_patterns.empty ())
+    {
+      str += "none";
+    }
+  else
+    {
+      for (const auto &upper : upper_patterns)
+       str += "\n  " + upper->as_string ();
+    }
+
+  return str;
+}
+
+std::string
+SlicePattern::as_string () const
+{
+  return "SlicePattern: " + items->as_string ();
+}
+
 std::string
 AltPattern::as_string () const
 {
@@ -366,6 +402,18 @@ GroupedExpr::accept_vis (ASTVisitor &vis)
   vis.visit (*this);
 }
 
+void
+SlicePatternItemsNoRest::accept_vis (ASTVisitor &vis)
+{
+  vis.visit (*this);
+}
+
+void
+SlicePatternItemsHasRest::accept_vis (ASTVisitor &vis)
+{
+  vis.visit (*this);
+}
+
 void
 SlicePattern::accept_vis (ASTVisitor &vis)
 {
index 57c065ff69559bb554633ecb2b3d8401de1049ef..4945ec4480dd4171489b7653182e2585603d7429 100644 (file)
@@ -1521,41 +1521,217 @@ protected:
   }
 };
 
+// Base abstract class representing patterns in a SlicePattern
+class SlicePatternItems
+{
+public:
+  enum SlicePatternItemType
+  {
+    NO_REST,
+    HAS_REST,
+  };
+
+  virtual ~SlicePatternItems () {}
+
+  // TODO: should this store location data?
+
+  // Unique pointer custom clone function
+  std::unique_ptr<SlicePatternItems> clone_slice_pattern_items () const
+  {
+    return std::unique_ptr<SlicePatternItems> (
+      clone_slice_pattern_items_impl ());
+  }
+
+  virtual std::string as_string () const = 0;
+
+  virtual void accept_vis (ASTVisitor &vis) = 0;
+
+  virtual SlicePatternItemType get_pattern_type () const = 0;
+
+protected:
+  // pure virtual clone implementation
+  virtual SlicePatternItems *clone_slice_pattern_items_impl () const = 0;
+};
+
+// Class representing the patterns in a SlicePattern without `..`
+class SlicePatternItemsNoRest : public SlicePatternItems
+{
+  std::vector<std::unique_ptr<Pattern>> patterns;
+
+public:
+  SlicePatternItemsNoRest (std::vector<std::unique_ptr<Pattern>> patterns)
+    : patterns (std::move (patterns))
+  {}
+
+  // Copy constructor with vector clone
+  SlicePatternItemsNoRest (SlicePatternItemsNoRest const &other)
+  {
+    patterns.reserve (other.patterns.size ());
+    for (const auto &e : other.patterns)
+      patterns.push_back (e->clone_pattern ());
+  }
+
+  // Overloaded assignment operator to vector clone
+  SlicePatternItemsNoRest &operator= (SlicePatternItemsNoRest const &other)
+  {
+    patterns.clear ();
+    patterns.reserve (other.patterns.size ());
+    for (const auto &e : other.patterns)
+      patterns.push_back (e->clone_pattern ());
+
+    return *this;
+  }
+
+  // move constructors
+  SlicePatternItemsNoRest (SlicePatternItemsNoRest &&other) = default;
+  SlicePatternItemsNoRest &operator= (SlicePatternItemsNoRest &&other)
+    = default;
+
+  std::string as_string () const override;
+
+  void accept_vis (ASTVisitor &vis) override;
+
+  // TODO: seems kinda dodgy. Think of better way.
+  std::vector<std::unique_ptr<Pattern>> &get_patterns () { return patterns; }
+  const std::vector<std::unique_ptr<Pattern>> &get_patterns () const
+  {
+    return patterns;
+  }
+
+  SlicePatternItemType get_pattern_type () const override
+  {
+    return SlicePatternItemType::NO_REST;
+  }
+
+protected:
+  /* Use covariance to implement clone function as returning this object rather
+   * than base */
+  SlicePatternItemsNoRest *clone_slice_pattern_items_impl () const override
+  {
+    return new SlicePatternItemsNoRest (*this);
+  }
+};
+
+// Class representing the patterns in a SlicePattern that contains a `..`
+class SlicePatternItemsHasRest : public SlicePatternItems
+{
+  std::vector<std::unique_ptr<Pattern>> lower_patterns;
+  std::vector<std::unique_ptr<Pattern>> upper_patterns;
+
+public:
+  SlicePatternItemsHasRest (
+    std::vector<std::unique_ptr<Pattern>> lower_patterns,
+    std::vector<std::unique_ptr<Pattern>> upper_patterns)
+    : lower_patterns (std::move (lower_patterns)),
+      upper_patterns (std::move (upper_patterns))
+  {}
+
+  // Copy constructor with vector clone
+  SlicePatternItemsHasRest (SlicePatternItemsHasRest const &other)
+  {
+    lower_patterns.reserve (other.lower_patterns.size ());
+    for (const auto &e : other.lower_patterns)
+      lower_patterns.push_back (e->clone_pattern ());
+
+    upper_patterns.reserve (other.upper_patterns.size ());
+    for (const auto &e : other.upper_patterns)
+      upper_patterns.push_back (e->clone_pattern ());
+  }
+
+  // Overloaded assignment operator to clone
+  SlicePatternItemsHasRest &operator= (SlicePatternItemsHasRest const &other)
+  {
+    lower_patterns.clear ();
+    lower_patterns.reserve (other.lower_patterns.size ());
+    for (const auto &e : other.lower_patterns)
+      lower_patterns.push_back (e->clone_pattern ());
+
+    upper_patterns.clear ();
+    upper_patterns.reserve (other.upper_patterns.size ());
+    for (const auto &e : other.upper_patterns)
+      upper_patterns.push_back (e->clone_pattern ());
+
+    return *this;
+  }
+
+  // move constructors
+  SlicePatternItemsHasRest (SlicePatternItemsHasRest &&other) = default;
+  SlicePatternItemsHasRest &operator= (SlicePatternItemsHasRest &&other)
+    = default;
+
+  std::string as_string () const override;
+
+  void accept_vis (ASTVisitor &vis) override;
+
+  // TODO: seems kinda dodgy. Think of better way.
+  std::vector<std::unique_ptr<Pattern>> &get_lower_patterns ()
+  {
+    return lower_patterns;
+  }
+  const std::vector<std::unique_ptr<Pattern>> &get_lower_patterns () const
+  {
+    return lower_patterns;
+  }
+
+  // TODO: seems kinda dodgy. Think of better way.
+  std::vector<std::unique_ptr<Pattern>> &get_upper_patterns ()
+  {
+    return upper_patterns;
+  }
+  const std::vector<std::unique_ptr<Pattern>> &get_upper_patterns () const
+  {
+    return upper_patterns;
+  }
+
+  SlicePatternItemType get_pattern_type () const override
+  {
+    return SlicePatternItemType::HAS_REST;
+  }
+
+protected:
+  /* Use covariance to implement clone function as returning this object rather
+   * than base */
+  SlicePatternItemsHasRest *clone_slice_pattern_items_impl () const override
+  {
+    return new SlicePatternItemsHasRest (*this);
+  }
+};
+
 // AST node representing patterns that can match slices and arrays
 class SlicePattern : public Pattern
 {
-  std::vector<std::unique_ptr<Pattern>> items;
+  std::unique_ptr<SlicePatternItems> items;
   location_t locus;
   NodeId node_id;
 
 public:
   std::string as_string () const override;
 
-  SlicePattern (std::vector<std::unique_ptr<Pattern>> items, location_t locus)
+  SlicePattern (std::unique_ptr<SlicePatternItems> items, location_t locus)
     : items (std::move (items)), locus (locus),
       node_id (Analysis::Mappings::get ().get_next_node_id ())
   {}
 
-  // Copy constructor with vector clone
+  // Copy constructor requires clone
   SlicePattern (SlicePattern const &other) : locus (other.locus)
   {
+    // guard to prevent null dereference
+    rust_assert (other.items != nullptr);
+
     node_id = other.node_id;
-    items.reserve (other.items.size ());
-    for (const auto &e : other.items)
-      items.push_back (e->clone_pattern ());
+    items = other.items->clone_slice_pattern_items ();
   }
 
-  // Overloaded assignment operator to vector clone
+  // Overloaded assignment operator to clone
   SlicePattern &operator= (SlicePattern const &other)
   {
     locus = other.locus;
     node_id = other.node_id;
 
-    items.clear ();
-    items.reserve (other.items.size ());
-    for (const auto &e : other.items)
-      items.push_back (e->clone_pattern ());
+    // guard to prevent null dereference
+    rust_assert (other.items != nullptr);
 
+    items = other.items->clone_slice_pattern_items ();
     return *this;
   }
 
@@ -1568,10 +1744,10 @@ public:
   void accept_vis (ASTVisitor &vis) override;
 
   // TODO: seems kinda dodgy. Think of better way.
-  std::vector<std::unique_ptr<Pattern>> &get_items () { return items; }
-  const std::vector<std::unique_ptr<Pattern>> &get_items () const
+  SlicePatternItems &get_items ()
   {
-    return items;
+    rust_assert (items != nullptr);
+    return *items;
   }
 
   NodeId get_node_id () const override { return node_id; }
index ac795f7259d76afde2eb2cd5c234fb292ccb40f0..58d8071600945784fcd3aa65ce82516ee6fad437 100644 (file)
@@ -2478,19 +2478,43 @@ CfgStrip::visit (AST::GroupedPattern &pattern)
 }
 
 void
-CfgStrip::visit (AST::SlicePattern &pattern)
+CfgStrip::visit (AST::SlicePatternItemsNoRest &items)
 {
-  AST::DefaultASTVisitor::visit (pattern);
+  AST::DefaultASTVisitor::visit (items);
   // can't strip individual patterns, only sub-patterns
-  for (auto &item : pattern.get_items ())
+  for (auto &pattern : items.get_patterns ())
     {
-      if (item->is_marked_for_strip ())
-       rust_error_at (item->get_locus (),
+      if (pattern->is_marked_for_strip ())
+       rust_error_at (pattern->get_locus (),
                       "cannot strip pattern in this position");
-      // TODO: quit stripping now? or keep going?
     }
 }
 
+void
+CfgStrip::visit (AST::SlicePatternItemsHasRest &items)
+{
+  AST::DefaultASTVisitor::visit (items);
+  // can't strip individual patterns, only sub-patterns
+  for (auto &pattern : items.get_lower_patterns ())
+    {
+      if (pattern->is_marked_for_strip ())
+       rust_error_at (pattern->get_locus (),
+                      "cannot strip pattern in this position");
+    }
+  for (auto &pattern : items.get_upper_patterns ())
+    {
+      if (pattern->is_marked_for_strip ())
+       rust_error_at (pattern->get_locus (),
+                      "cannot strip pattern in this position");
+    }
+}
+
+void
+CfgStrip::visit (AST::SlicePattern &pattern)
+{
+  AST::DefaultASTVisitor::visit (pattern);
+}
+
 void
 CfgStrip::visit (AST::AltPattern &pattern)
 {
index 4900ae893edddd514e81c6c0896550dacac20894..767cf28a7123d5b379498bec951e485de6553cb9 100644 (file)
@@ -172,6 +172,8 @@ public:
   void visit (AST::TuplePatternItemsMultiple &tuple_items) override;
   void visit (AST::TuplePatternItemsRanged &tuple_items) override;
   void visit (AST::GroupedPattern &pattern) override;
+  void visit (AST::SlicePatternItemsNoRest &items) override;
+  void visit (AST::SlicePatternItemsHasRest &items) override;
   void visit (AST::SlicePattern &pattern) override;
   void visit (AST::AltPattern &pattern) override;
 
index 297d0799122ec17f1a7e166b19461ef608cbda59..283b4434dd335bb464fa0d392a95279e18378386 100644 (file)
@@ -231,6 +231,8 @@ private:
   virtual void visit (TuplePatternItemsRanged &tuple_items) override final{};
   virtual void visit (TuplePattern &pattern) override final{};
   virtual void visit (GroupedPattern &pattern) override final{};
+  virtual void visit (SlicePatternItemsNoRest &items) override final{};
+  virtual void visit (SlicePatternItemsHasRest &items) override final{};
   virtual void visit (SlicePattern &pattern) override final{};
   virtual void visit (AltPattern &pattern) override final{};
   virtual void visit (EmptyStmt &stmt) override final{};
index 9098a9fc6cff50873e67eddb44f15379f4d5bf35..09f4b930963999a3d230b2960ec964927693ced0 100644 (file)
@@ -495,6 +495,12 @@ void
 ASTLoweringBase::visit (AST::GroupedPattern &)
 {}
 void
+ASTLoweringBase::visit (AST::SlicePatternItemsNoRest &)
+{}
+void
+ASTLoweringBase::visit (AST::SlicePatternItemsHasRest &)
+{}
+void
 ASTLoweringBase::visit (AST::SlicePattern &)
 {}
 void
index 6437b2e9dbb6ba4a3d1fbc06c0437b6357e50e5f..af21c40d5c5409399ba80a5b2d26f735c8d47211 100644 (file)
@@ -236,6 +236,8 @@ public:
   virtual void visit (AST::TuplePatternItemsRanged &tuple_items) override;
   virtual void visit (AST::TuplePattern &pattern) override;
   virtual void visit (AST::GroupedPattern &pattern) override;
+  virtual void visit (AST::SlicePatternItemsNoRest &items) override;
+  virtual void visit (AST::SlicePatternItemsHasRest &items) override;
   virtual void visit (AST::SlicePattern &pattern) override;
   virtual void visit (AST::AltPattern &pattern) override;
 
index bb5b93b2c49bac7d5a25e47ef36494a4efe67bdd..b9d7b620aa2382ed56260f6feae0945c7a5993e8 100644 (file)
@@ -321,10 +321,27 @@ void
 ASTLoweringPattern::visit (AST::SlicePattern &pattern)
 {
   std::vector<std::unique_ptr<HIR::Pattern>> items;
-  for (auto &p : pattern.get_items ())
+
+  switch (pattern.get_items ().get_pattern_type ())
     {
-      HIR::Pattern *item = ASTLoweringPattern::translate (*p);
-      items.push_back (std::unique_ptr<HIR::Pattern> (item));
+    case AST::SlicePatternItems::SlicePatternItemType::NO_REST:
+      {
+       AST::SlicePatternItemsNoRest &ref
+         = static_cast<AST::SlicePatternItemsNoRest &> (pattern.get_items ());
+       for (auto &p : ref.get_patterns ())
+         {
+           HIR::Pattern *item = ASTLoweringPattern::translate (*p);
+           items.push_back (std::unique_ptr<HIR::Pattern> (item));
+         }
+      }
+      break;
+    case AST::SlicePatternItems::SlicePatternItemType::HAS_REST:
+      {
+       rust_error_at (pattern.get_locus (),
+                      "lowering of slice patterns with rest elements are not "
+                      "supported yet");
+      }
+      break;
     }
 
   auto crate_num = mappings.get_current_crate ();
index 6d996ca602631de812c7070d9c4f504f758eb3f2..80b529c05e484f96bce1765df8b9f7a751519ded 100644 (file)
@@ -10962,27 +10962,47 @@ Parser<ManagedTokenSource>::parse_slice_pattern ()
 {
   location_t square_locus = lexer.peek_token ()->get_locus ();
   std::vector<std::unique_ptr<AST::Pattern>> patterns;
+  tl::optional<std::vector<std::unique_ptr<AST::Pattern>>> upper_patterns
+    = tl::nullopt;
+
+  // lambda function to determine which vector to push new patterns into
+  auto get_pattern_ref
+    = [&] () -> std::vector<std::unique_ptr<AST::Pattern>> & {
+    return upper_patterns.has_value () ? upper_patterns.value () : patterns;
+  };
+
   skip_token (LEFT_SQUARE);
 
   if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
     {
       skip_token (RIGHT_SQUARE);
+      std::unique_ptr<AST::SlicePatternItemsNoRest> items (
+       new AST::SlicePatternItemsNoRest (std::move (patterns)));
       return std::unique_ptr<AST::SlicePattern> (
-       new AST::SlicePattern (std::move (patterns), square_locus));
+       new AST::SlicePattern (std::move (items), square_locus));
     }
 
   // parse initial pattern (required)
-  std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
-  if (initial_pattern == nullptr)
+  if (lexer.peek_token ()->get_id () == DOT_DOT)
     {
-      Error error (lexer.peek_token ()->get_locus (),
-                  "failed to parse initial pattern in slice pattern");
-      add_error (std::move (error));
-
-      return nullptr;
+      lexer.skip_token ();
+      upper_patterns = std::vector<std::unique_ptr<AST::Pattern>> ();
     }
+  else
+    {
+      // Not a rest pattern `..`, parse normally
+      std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
+      if (initial_pattern == nullptr)
+       {
+         Error error (lexer.peek_token ()->get_locus (),
+                      "failed to parse initial pattern in slice pattern");
+         add_error (std::move (error));
 
-  patterns.push_back (std::move (initial_pattern));
+         return nullptr;
+       }
+
+      patterns.push_back (std::move (initial_pattern));
+    }
 
   const_TokenPtr t = lexer.peek_token ();
   while (t->get_id () == COMMA)
@@ -10993,6 +11013,23 @@ Parser<ManagedTokenSource>::parse_slice_pattern ()
       if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
        break;
 
+      if (lexer.peek_token ()->get_id () == DOT_DOT)
+       {
+         if (upper_patterns.has_value ())
+           {
+             // DOT_DOT has been parsed before
+             Error error (lexer.peek_token ()->get_locus (), "%s",
+                          "`..` can only be used once per slice pattern");
+             add_error (std::move (error));
+
+             return nullptr;
+           }
+         upper_patterns = std::vector<std::unique_ptr<AST::Pattern>> ();
+         lexer.skip_token ();
+         t = lexer.peek_token ();
+         continue;
+       }
+
       // parse pattern (required)
       std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
       if (pattern == nullptr)
@@ -11003,7 +11040,7 @@ Parser<ManagedTokenSource>::parse_slice_pattern ()
 
          return nullptr;
        }
-      patterns.push_back (std::move (pattern));
+      get_pattern_ref ().push_back (std::move (pattern));
 
       t = lexer.peek_token ();
     }
@@ -11013,8 +11050,21 @@ Parser<ManagedTokenSource>::parse_slice_pattern ()
       return nullptr;
     }
 
+  if (upper_patterns.has_value ())
+    {
+      // Slice pattern with rest
+      std::unique_ptr<AST::SlicePatternItemsHasRest> items (
+       new AST::SlicePatternItemsHasRest (
+         std::move (patterns), std::move (upper_patterns.value ())));
+      return std::unique_ptr<AST::SlicePattern> (
+       new AST::SlicePattern (std::move (items), square_locus));
+    }
+
+  // Rest-less slice pattern
+  std::unique_ptr<AST::SlicePatternItemsNoRest> items (
+    new AST::SlicePatternItemsNoRest (std::move (patterns)));
   return std::unique_ptr<AST::SlicePattern> (
-    new AST::SlicePattern (std::move (patterns), square_locus));
+    new AST::SlicePattern (std::move (items), square_locus));
 }
 
 /* Parses an identifier pattern (pattern that binds a value matched to a
index 4890d8e519c149f0c17f18545987542bc64c9342..6b57c6d62a81e7110634e47c4cf175834006a27e 100644 (file)
@@ -583,6 +583,14 @@ void
 ResolverBase::visit (AST::GroupedPattern &)
 {}
 
+void
+ResolverBase::visit (AST::SlicePatternItemsNoRest &)
+{}
+
+void
+ResolverBase::visit (AST::SlicePatternItemsHasRest &)
+{}
+
 void
 ResolverBase::visit (AST::SlicePattern &)
 {}
index dce8e7bfc7505c9e3bf5e1da163c07ead61c249b..febfc6126d522f0448a5e1cd96df3d1a9bc32934 100644 (file)
@@ -186,6 +186,8 @@ public:
   void visit (AST::TuplePatternItemsRanged &);
   void visit (AST::TuplePattern &);
   void visit (AST::GroupedPattern &);
+  void visit (AST::SlicePatternItemsNoRest &);
+  void visit (AST::SlicePatternItemsHasRest &);
   void visit (AST::SlicePattern &);
   void visit (AST::AltPattern &);
 
index fce45bcf1e62dc22ccc5d44ffb4bf1250abda80f..3b80f9f0508fd437b8f05b6da6733adc9cf9da5b 100644 (file)
@@ -388,9 +388,30 @@ PatternDeclaration::visit (AST::RangePattern &pattern)
 void
 PatternDeclaration::visit (AST::SlicePattern &pattern)
 {
-  for (auto &p : pattern.get_items ())
+  auto &items = pattern.get_items ();
+  switch (items.get_pattern_type ())
     {
-      p->accept_vis (*this);
+    case AST::SlicePatternItems::SlicePatternItemType::NO_REST:
+      {
+       auto &ref
+         = static_cast<AST::SlicePatternItemsNoRest &> (pattern.get_items ());
+
+       for (auto &p : ref.get_patterns ())
+         p->accept_vis (*this);
+      }
+      break;
+
+    case AST::SlicePatternItems::SlicePatternItemType::HAS_REST:
+      {
+       auto &ref
+         = static_cast<AST::SlicePatternItemsHasRest &> (pattern.get_items ());
+
+       for (auto &p : ref.get_lower_patterns ())
+         p->accept_vis (*this);
+       for (auto &p : ref.get_upper_patterns ())
+         p->accept_vis (*this);
+      }
+      break;
     }
 }