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>
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));
}
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);
class TuplePatternItemsRanged;
class TuplePattern;
class GroupedPattern;
+class SlicePatternItemsNoRest;
+class SlicePatternItemsHasRest;
class SlicePattern;
class AltPattern;
}
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)
{
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;
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;
}
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
{
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)
{
}
};
+// 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;
}
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; }
}
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)
{
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;
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{};
ASTLoweringBase::visit (AST::GroupedPattern &)
{}
void
+ASTLoweringBase::visit (AST::SlicePatternItemsNoRest &)
+{}
+void
+ASTLoweringBase::visit (AST::SlicePatternItemsHasRest &)
+{}
+void
ASTLoweringBase::visit (AST::SlicePattern &)
{}
void
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;
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 ();
{
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)
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)
return nullptr;
}
- patterns.push_back (std::move (pattern));
+ get_pattern_ref ().push_back (std::move (pattern));
t = lexer.peek_token ();
}
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
ResolverBase::visit (AST::GroupedPattern &)
{}
+void
+ResolverBase::visit (AST::SlicePatternItemsNoRest &)
+{}
+
+void
+ResolverBase::visit (AST::SlicePatternItemsHasRest &)
+{}
+
void
ResolverBase::visit (AST::SlicePattern &)
{}
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 &);
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;
}
}