|| lookup->get_kind () == TyTy::TypeKind::SLICE
|| lookup->get_kind () == TyTy::REF);
- size_t array_element_index = 0;
+ // function ptr that points to either array_index_expression or
+ // slice_index_expression depending on the scrutinee's type
+ tree (*scrutinee_index_expr_func) (tree, tree, location_t) = nullptr;
+
switch (lookup->get_kind ())
{
case TyTy::TypeKind::ARRAY:
- for (auto &pattern_member : pattern.get_items ())
- {
- tree array_index_tree
- = Backend::size_constant_expression (array_element_index++);
- tree element_expr
- = Backend::array_index_expression (match_scrutinee_expr,
- array_index_tree,
- pattern.get_locus ());
- tree check_expr_sub
- = CompilePatternCheckExpr::Compile (*pattern_member, element_expr,
- ctx);
- check_expr = Backend::arithmetic_or_logical_expression (
- ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
- check_expr_sub, pattern.get_locus ());
- }
+ scrutinee_index_expr_func = Backend::array_index_expression;
break;
case TyTy::TypeKind::SLICE:
rust_sorry_at (
case TyTy::TypeKind::REF:
{
rust_assert (RS_DST_FLAG_P (TREE_TYPE (match_scrutinee_expr)));
+ scrutinee_index_expr_func = Backend::slice_index_expression;
tree size_field
= Backend::struct_field_expression (match_scrutinee_expr, 1,
pattern.get_locus ());
- // First compare the size
- check_expr = Backend::comparison_expression (
- ComparisonOperator::EQUAL, size_field,
- build_int_cst (size_type_node, pattern.get_items ().size ()),
- pattern.get_locus ());
+ // for slices, generate a dynamic size comparison expression tree
+ // because size checking is done at runtime.
+ switch (pattern.get_items ().get_item_type ())
+ {
+ case HIR::SlicePatternItems::ItemType::NO_REST:
+ {
+ auto &items = static_cast<HIR::SlicePatternItemsNoRest &> (
+ pattern.get_items ());
+ check_expr = Backend::comparison_expression (
+ ComparisonOperator::EQUAL, size_field,
+ build_int_cst (size_type_node, items.get_patterns ().size ()),
+ pattern.get_locus ());
+ }
+ break;
+ case HIR::SlicePatternItems::ItemType::HAS_REST:
+ {
+ auto &items = static_cast<HIR::SlicePatternItemsHasRest &> (
+ pattern.get_items ());
+ auto pattern_min_cap = items.get_lower_patterns ().size ()
+ + items.get_upper_patterns ().size ();
+ check_expr = Backend::comparison_expression (
+ ComparisonOperator::GREATER_OR_EQUAL, size_field,
+ build_int_cst (size_type_node, pattern_min_cap),
+ pattern.get_locus ());
+ }
+ break;
+ }
+ }
+ break;
+ default:
+ rust_unreachable ();
+ }
+
+ rust_assert (scrutinee_index_expr_func != nullptr);
- // Then compare each element in the slice pattern
- for (auto &pattern_member : pattern.get_items ())
+ // Generate tree to compare every element within array/slice
+ size_t element_index = 0;
+ switch (pattern.get_items ().get_item_type ())
+ {
+ case HIR::SlicePatternItems::ItemType::NO_REST:
+ {
+ auto &items
+ = static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ());
+ for (auto &pattern_member : items.get_patterns ())
{
- tree slice_index_tree
- = Backend::size_constant_expression (array_element_index++);
+ tree index_tree
+ = Backend::size_constant_expression (element_index++);
tree element_expr
- = Backend::slice_index_expression (match_scrutinee_expr,
- slice_index_tree,
- pattern.get_locus ());
+ = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
+ pattern.get_locus ());
+ tree check_expr_sub
+ = CompilePatternCheckExpr::Compile (*pattern_member, element_expr,
+ ctx);
+ check_expr = Backend::arithmetic_or_logical_expression (
+ ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
+ check_expr_sub, pattern.get_locus ());
+ }
+ break;
+ }
+ case HIR::SlicePatternItems::ItemType::HAS_REST:
+ {
+ auto &items
+ = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
+ for (auto &pattern_member : items.get_lower_patterns ())
+ {
+ tree index_tree
+ = Backend::size_constant_expression (element_index++);
+ tree element_expr
+ = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
+ pattern.get_locus ());
tree check_expr_sub
= CompilePatternCheckExpr::Compile (*pattern_member, element_expr,
ctx);
ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
check_expr_sub, pattern.get_locus ());
}
+
+ // handle codegen for upper patterns differently for both types
+ switch (lookup->get_kind ())
+ {
+ case TyTy::TypeKind::ARRAY:
+ {
+ // for array type scrutinee, we can simply get the capacity as a
+ // const and calculate how many elements to skip
+ auto array_ty = static_cast<TyTy::ArrayType *> (lookup);
+ auto cap_tree = array_ty->get_capacity ()->get_value ();
+ size_t cap_wi = (size_t) wi::to_wide (cap_tree).to_uhwi ();
+ element_index = cap_wi - items.get_upper_patterns ().size ();
+ for (auto &pattern_member : items.get_upper_patterns ())
+ {
+ tree index_tree
+ = Backend::size_constant_expression (element_index++);
+ tree element_expr
+ = scrutinee_index_expr_func (match_scrutinee_expr,
+ index_tree,
+ pattern.get_locus ());
+ tree check_expr_sub
+ = CompilePatternCheckExpr::Compile (*pattern_member,
+ element_expr, ctx);
+ check_expr = Backend::arithmetic_or_logical_expression (
+ ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
+ check_expr_sub, pattern.get_locus ());
+ }
+ }
+ break;
+ case TyTy::TypeKind::REF:
+ {
+ // for slice type scrutinee, size is dyanamic, so number of
+ // elements to skip is calculated during runtime
+ tree slice_size
+ = Backend::struct_field_expression (match_scrutinee_expr, 1,
+ pattern.get_locus ());
+ tree upper_patterns_size = Backend::size_constant_expression (
+ items.get_upper_patterns ().size ());
+ tree index_tree = Backend::arithmetic_or_logical_expression (
+ ArithmeticOrLogicalOperator::SUBTRACT, slice_size,
+ upper_patterns_size, pattern.get_locus ());
+ for (auto &pattern_member : items.get_upper_patterns ())
+ {
+ tree element_expr
+ = scrutinee_index_expr_func (match_scrutinee_expr,
+ index_tree,
+ pattern.get_locus ());
+ tree check_expr_sub
+ = CompilePatternCheckExpr::Compile (*pattern_member,
+ element_expr, ctx);
+ check_expr = Backend::arithmetic_or_logical_expression (
+ ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
+ check_expr_sub, pattern.get_locus ());
+ index_tree = Backend::arithmetic_or_logical_expression (
+ ArithmeticOrLogicalOperator::ADD, index_tree,
+ Backend::size_constant_expression (1),
+ pattern.get_locus ());
+ }
+ }
+ break;
+ default:
+ rust_unreachable ();
+ }
}
break;
- default:
- rust_unreachable ();
}
}
|| lookup->get_kind () == TyTy::TypeKind::SLICE
|| lookup->get_kind () == TyTy::REF);
- size_t array_element_index = 0;
+ // function ptr that points to either array_index_expression or
+ // slice_index_expression depending on the scrutinee's type
+ tree (*scrutinee_index_expr_func) (tree, tree, location_t) = nullptr;
+
switch (lookup->get_kind ())
{
case TyTy::TypeKind::ARRAY:
- for (auto &pattern_member : pattern.get_items ())
- {
- tree array_index_tree
- = Backend::size_constant_expression (array_element_index++);
- tree element_expr
- = Backend::array_index_expression (match_scrutinee_expr,
- array_index_tree,
- pattern.get_locus ());
- CompilePatternBindings::Compile (*pattern_member, element_expr, ctx);
- }
+ scrutinee_index_expr_func = Backend::array_index_expression;
break;
case TyTy::TypeKind::SLICE:
- rust_sorry_at (
- pattern.get_locus (),
- "SlicePattern matching against non-ref slices are not yet supported");
+ rust_sorry_at (pattern.get_locus (),
+ "SlicePattern matching against non-ref slices are "
+ "not yet supported");
break;
case TyTy::TypeKind::REF:
+ scrutinee_index_expr_func = Backend::slice_index_expression;
+ break;
+ default:
+ rust_unreachable ();
+ }
+
+ rust_assert (scrutinee_index_expr_func != nullptr);
+
+ size_t element_index = 0;
+
+ switch (pattern.get_items ().get_item_type ())
+ {
+ case HIR::SlicePatternItems::ItemType::NO_REST:
{
- for (auto &pattern_member : pattern.get_items ())
+ auto &items
+ = static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ());
+ for (auto &pattern_member : items.get_patterns ())
{
- tree slice_index_tree
- = Backend::size_constant_expression (array_element_index++);
+ tree index_tree
+ = Backend::size_constant_expression (element_index++);
tree element_expr
- = Backend::slice_index_expression (match_scrutinee_expr,
- slice_index_tree,
- pattern.get_locus ());
+ = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
+ pattern.get_locus ());
CompilePatternBindings::Compile (*pattern_member, element_expr,
ctx);
}
- break;
}
- default:
- rust_unreachable ();
+ break;
+ case HIR::SlicePatternItems::ItemType::HAS_REST:
+ {
+ auto &items
+ = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
+ for (auto &pattern_member : items.get_lower_patterns ())
+ {
+ tree index_tree
+ = Backend::size_constant_expression (element_index++);
+ tree element_expr
+ = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
+ pattern.get_locus ());
+ CompilePatternBindings::Compile (*pattern_member, element_expr,
+ ctx);
+ }
+
+ // handle codegen for upper patterns differently for both types
+ switch (lookup->get_kind ())
+ {
+ case TyTy::TypeKind::ARRAY:
+ {
+ auto array_ty = static_cast<TyTy::ArrayType *> (lookup);
+ auto cap_tree = array_ty->get_capacity ()->get_value ();
+ size_t cap_wi = (size_t) wi::to_wide (cap_tree).to_uhwi ();
+ element_index = cap_wi - items.get_upper_patterns ().size ();
+ for (auto &pattern_member : items.get_upper_patterns ())
+ {
+ tree index_tree
+ = Backend::size_constant_expression (element_index++);
+ tree element_expr
+ = scrutinee_index_expr_func (match_scrutinee_expr,
+ index_tree,
+ pattern.get_locus ());
+ CompilePatternBindings::Compile (*pattern_member,
+ element_expr, ctx);
+ }
+ }
+ break;
+ case TyTy::TypeKind::SLICE:
+ rust_sorry_at (pattern.get_locus (),
+ "SlicePattern matching against non-ref slices are "
+ "not yet supported");
+ break;
+ case TyTy::TypeKind::REF:
+ {
+ tree slice_size
+ = Backend::struct_field_expression (match_scrutinee_expr, 1,
+ pattern.get_locus ());
+ tree upper_patterns_size = Backend::size_constant_expression (
+ items.get_upper_patterns ().size ());
+ tree index_tree = Backend::arithmetic_or_logical_expression (
+ ArithmeticOrLogicalOperator::SUBTRACT, slice_size,
+ upper_patterns_size, pattern.get_locus ());
+ for (auto &pattern_member : items.get_upper_patterns ())
+ {
+ tree element_expr
+ = scrutinee_index_expr_func (match_scrutinee_expr,
+ index_tree,
+ pattern.get_locus ());
+ CompilePatternBindings::Compile (*pattern_member,
+ element_expr, ctx);
+ index_tree = Backend::arithmetic_or_logical_expression (
+ ArithmeticOrLogicalOperator::ADD, index_tree,
+ Backend::size_constant_expression (1),
+ pattern.get_locus ());
+ }
+ }
+ break;
+ default:
+ rust_unreachable ();
+ }
+ }
+ break;
}
}
return ty->as<TyTy::SliceType> ()->get_element_type ();
});
- // Regions are unchnaged.
+ // Regions are unchanged.
- for (auto &item : pattern.get_items ())
+ switch (pattern.get_items ().get_item_type ())
{
- item->accept_vis (*this);
+ case HIR::SlicePatternItems::NO_REST:
+ {
+ auto &items
+ = static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ());
+ for (auto &member : items.get_patterns ())
+ {
+ member->accept_vis (*this);
+ }
+ break;
+ }
+ case HIR::SlicePatternItems::HAS_REST:
+ {
+ auto &items
+ = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
+ for (auto &member : items.get_lower_patterns ())
+ {
+ member->accept_vis (*this);
+ }
+ for (auto &member : items.get_upper_patterns ())
+ {
+ member->accept_vis (*this);
+ }
+ break;
+ }
}
}
rust_unreachable ();
}
void visit (HIR::TuplePattern &pattern) override { rust_unreachable (); }
+ void visit (HIR::SlicePatternItemsNoRest &tuple_items) override
+ {
+ rust_unreachable ();
+ }
+ void visit (HIR::SlicePatternItemsHasRest &tuple_items) override
+ {
+ rust_unreachable ();
+ }
void visit (HIR::SlicePattern &pattern) override { rust_unreachable (); }
void visit (HIR::AltPattern &pattern) override { rust_unreachable (); }
void visit (HIR::EmptyStmt &stmt) override { rust_unreachable (); }
void visit (HIR::TuplePatternItemsNoRest &tuple_items) override {}
void visit (HIR::TuplePatternItemsHasRest &tuple_items) override {}
void visit (HIR::TuplePattern &pattern) override {}
+ void visit (HIR::SlicePatternItemsNoRest &tuple_items) override {}
+ void visit (HIR::SlicePatternItemsHasRest &tuple_items) override {}
void visit (HIR::SlicePattern &pattern) override {}
void visit (HIR::AltPattern &pattern) override {}
void visit (HIR::EmptyStmt &stmt) override {}
ConstChecker::visit (TuplePattern &)
{}
+void
+ConstChecker::visit (SlicePatternItemsNoRest &)
+{}
+
+void
+ConstChecker::visit (SlicePatternItemsHasRest &)
+{}
+
void
ConstChecker::visit (SlicePattern &)
{}
virtual void visit (TuplePatternItemsNoRest &tuple_items) override;
virtual void visit (TuplePatternItemsHasRest &tuple_items) override;
virtual void visit (TuplePattern &pattern) override;
+ virtual void visit (SlicePatternItemsNoRest &items) override;
+ virtual void visit (SlicePatternItemsHasRest &items) override;
virtual void visit (SlicePattern &pattern) override;
virtual void visit (AltPattern &pattern) override;
virtual void visit (EmptyStmt &stmt) override;
PatternChecker::visit (TuplePattern &)
{}
+void
+PatternChecker::visit (SlicePatternItemsNoRest &)
+{}
+
+void
+PatternChecker::visit (SlicePatternItemsHasRest &)
+{}
+
void
PatternChecker::visit (SlicePattern &)
{}
virtual void visit (TuplePatternItemsNoRest &tuple_items) override;
virtual void visit (TuplePatternItemsHasRest &tuple_items) override;
virtual void visit (TuplePattern &pattern) override;
+ virtual void visit (SlicePatternItemsNoRest &items) override;
+ virtual void visit (SlicePatternItemsHasRest &items) override;
virtual void visit (SlicePattern &pattern) override;
virtual void visit (AltPattern &pattern) override;
virtual void visit (EmptyStmt &stmt) override;
UnsafeChecker::visit (TuplePattern &)
{}
+void
+UnsafeChecker::visit (SlicePatternItemsNoRest &)
+{}
+
+void
+UnsafeChecker::visit (SlicePatternItemsHasRest &)
+{}
+
void
UnsafeChecker::visit (SlicePattern &)
{}
virtual void visit (TuplePatternItemsNoRest &tuple_items) override;
virtual void visit (TuplePatternItemsHasRest &tuple_items) override;
virtual void visit (TuplePattern &pattern) override;
+ virtual void visit (SlicePatternItemsNoRest &items) override;
+ virtual void visit (SlicePatternItemsHasRest &items) override;
virtual void visit (SlicePattern &pattern) override;
virtual void visit (AltPattern &pattern) override;
virtual void visit (EmptyStmt &stmt) override;
std::move (upper_patterns)));
}
+std::unique_ptr<HIR::SlicePatternItems>
+ASTLoweringBase::lower_slice_pattern_no_rest (
+ AST::SlicePatternItemsNoRest &pattern)
+{
+ std::vector<std::unique_ptr<HIR::Pattern>> patterns;
+ patterns.reserve (pattern.get_patterns ().size ());
+ for (auto &p : pattern.get_patterns ())
+ patterns.emplace_back (ASTLoweringPattern::translate (*p));
+
+ return std::unique_ptr<HIR::SlicePatternItems> (
+ new HIR::SlicePatternItemsNoRest (std::move (patterns)));
+}
+
+std::unique_ptr<HIR::SlicePatternItems>
+ASTLoweringBase::lower_slice_pattern_has_rest (
+ AST::SlicePatternItemsHasRest &pattern)
+{
+ std::vector<std::unique_ptr<HIR::Pattern>> lower_patterns;
+ lower_patterns.reserve (pattern.get_lower_patterns ().size ());
+ std::vector<std::unique_ptr<HIR::Pattern>> upper_patterns;
+ upper_patterns.reserve (pattern.get_upper_patterns ().size ());
+
+ for (auto &p : pattern.get_lower_patterns ())
+ lower_patterns.emplace_back (
+ std::unique_ptr<HIR::Pattern> (ASTLoweringPattern::translate (*p)));
+
+ for (auto &p : pattern.get_upper_patterns ())
+ upper_patterns.emplace_back (
+ std::unique_ptr<HIR::Pattern> (ASTLoweringPattern::translate (*p)));
+
+ return std::unique_ptr<HIR::SlicePatternItems> (
+ new HIR::SlicePatternItemsHasRest (std::move (lower_patterns),
+ std::move (upper_patterns)));
+}
+
std::unique_ptr<HIR::RangePatternBound>
ASTLoweringBase::lower_range_pattern_bound (AST::RangePatternBound &bound)
{
std::unique_ptr<TuplePatternItems>
lower_tuple_pattern_ranged (AST::TuplePatternItemsRanged &pattern);
+ std::unique_ptr<SlicePatternItems>
+ lower_slice_pattern_no_rest (AST::SlicePatternItemsNoRest &pattern);
+
+ std::unique_ptr<SlicePatternItems>
+ lower_slice_pattern_has_rest (AST::SlicePatternItemsHasRest &pattern);
+
std::unique_ptr<HIR::RangePatternBound>
lower_range_pattern_bound (AST::RangePatternBound &bound);
void
ASTLoweringPattern::visit (AST::SlicePattern &pattern)
{
- std::vector<std::unique_ptr<HIR::Pattern>> items;
+ std::unique_ptr<HIR::SlicePatternItems> items;
switch (pattern.get_items ().get_pattern_type ())
{
case AST::SlicePatternItems::SlicePatternItemType::NO_REST:
{
- AST::SlicePatternItemsNoRest &ref
+ auto &ref
= static_cast<AST::SlicePatternItemsNoRest &> (pattern.get_items ());
- for (auto &p : ref.get_patterns ())
- items.emplace_back (ASTLoweringPattern::translate (*p));
+ items = ASTLoweringBase::lower_slice_pattern_no_rest (ref);
}
break;
case AST::SlicePatternItems::SlicePatternItemType::HAS_REST:
{
- rust_error_at (pattern.get_locus (),
- "lowering of slice patterns with rest elements are not "
- "supported yet");
+ auto &ref
+ = static_cast<AST::SlicePatternItemsHasRest &> (pattern.get_items ());
+ items = ASTLoweringBase::lower_slice_pattern_has_rest (ref);
}
break;
}
end ("TuplePattern");
}
+void
+Dump::visit (SlicePatternItemsNoRest &e)
+{
+ begin ("SlicePatternItemsNoRest");
+ visit_collection ("patterns", e.get_patterns ());
+ end ("SlicePatternItemsNoRest");
+}
+
+void
+Dump::visit (SlicePatternItemsHasRest &e)
+{
+ begin ("SlicePatternItemsHasRest");
+ visit_collection ("lower_patterns", e.get_lower_patterns ());
+ visit_collection ("upper_patterns", e.get_upper_patterns ());
+ end ("SlicePatternItemsHasRest");
+}
+
void
Dump::visit (SlicePattern &e)
{
begin ("SlicePattern");
do_mappings (e.get_mappings ());
- visit_collection ("items", e.get_items ());
+ visit_field ("items", e.get_items ());
end ("SlicePattern");
}
virtual void visit (TuplePatternItemsNoRest &) override;
virtual void visit (TuplePatternItemsHasRest &) override;
virtual void visit (TuplePattern &) override;
+
+ virtual void visit (SlicePatternItemsNoRest &) override;
+ virtual void visit (SlicePatternItemsHasRest &) override;
virtual void visit (SlicePattern &) override;
+
virtual void visit (AltPattern &) override;
virtual void visit (EmptyStmt &) override;
class TuplePatternItemsNoRest;
class TuplePatternItemsHasRest;
class TuplePattern;
+class SlicePatternItemsNoRest;
+class SlicePatternItemsHasRest;
class SlicePattern;
class AltPattern;
}
};
+// Base abstract class representing SlicePattern patterns
+class SlicePatternItems : public PatternItems
+{
+public:
+ // Unique pointer custom clone function
+ std::unique_ptr<SlicePatternItems> clone_slice_pattern_items () const
+ {
+ return std::unique_ptr<SlicePatternItems> (clone_pattern_items_impl ());
+ }
+
+protected:
+ // pure virtual clone implementation
+ virtual SlicePatternItems *clone_pattern_items_impl () const override = 0;
+};
+
+// Class representing patterns within a SlicePattern, without a rest pattern
+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 (HIRFullVisitor &vis) override;
+
+ ItemType get_item_type () const override { return ItemType::NO_REST; }
+
+ std::vector<std::unique_ptr<Pattern>> &get_patterns () { return patterns; }
+ const std::vector<std::unique_ptr<Pattern>> &get_patterns () const
+ {
+ return patterns;
+ }
+
+protected:
+ /* Use covariance to implement clone function as returning this object rather
+ * than base */
+ SlicePatternItemsNoRest *clone_pattern_items_impl () const override
+ {
+ return new SlicePatternItemsNoRest (*this);
+ }
+};
+
+// Class representing patterns within a SlicePattern, with a rest pattern
+// included
+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 ());
+
+ lower_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 (HIRFullVisitor &vis) override;
+
+ ItemType get_item_type () const override { return ItemType::HAS_REST; }
+
+ 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;
+ }
+
+ 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;
+ }
+
+protected:
+ /* Use covariance to implement clone function as returning this object rather
+ * than base */
+ SlicePatternItemsHasRest *clone_pattern_items_impl () const override
+ {
+ return new SlicePatternItemsHasRest (*this);
+ }
+};
+
// HIR 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;
Analysis::NodeMapping mappings;
std::string as_string () const override;
SlicePattern (Analysis::NodeMapping mappings,
- std::vector<std::unique_ptr<Pattern>> items, location_t locus)
+ std::unique_ptr<SlicePatternItems> items, location_t locus)
: items (std::move (items)), locus (locus), mappings (mappings)
{}
- // Copy constructor with vector clone
+ // Copy constructor requires clone
SlicePattern (SlicePattern const &other)
- : locus (other.locus), mappings (other.mappings)
- {
- items.reserve (other.items.size ());
- for (const auto &e : other.items)
- items.push_back (e->clone_pattern ());
- }
+ : items (other.items->clone_slice_pattern_items ()), locus (other.locus),
+ mappings (other.mappings)
+ {}
// Overloaded assignment operator to vector clone
SlicePattern &operator= (SlicePattern const &other)
{
+ items = other.items->clone_slice_pattern_items ();
locus = other.locus;
mappings = other.mappings;
- items.clear ();
- items.reserve (other.items.size ());
- for (const auto &e : other.items)
- items.push_back (e->clone_pattern ());
-
return *this;
}
SlicePattern (SlicePattern &&other) = default;
SlicePattern &operator= (SlicePattern &&other) = default;
- std::vector<std::unique_ptr<Pattern>> &get_items () { return items; }
- const std::vector<std::unique_ptr<Pattern>> &get_items () const
- {
- return items;
- }
+ SlicePatternItems &get_items () { return *items; }
+ const SlicePatternItems &get_items () const { return *items; }
location_t get_locus () const override { return locus; }
pattern.get_items ().accept_vis (*this);
}
+void
+DefaultHIRVisitor::walk (SlicePatternItemsNoRest &items)
+{
+ for (auto &pattern : items.get_patterns ())
+ pattern->accept_vis (*this);
+}
+
+void
+DefaultHIRVisitor::walk (SlicePatternItemsHasRest &items)
+{
+ for (auto &lower : items.get_lower_patterns ())
+ lower->accept_vis (*this);
+ for (auto &upper : items.get_upper_patterns ())
+ upper->accept_vis (*this);
+}
+
void
DefaultHIRVisitor::walk (SlicePattern &pattern)
{
- for (auto &item : pattern.get_items ())
- item->accept_vis (*this);
+ pattern.get_items ().accept_vis (*this);
}
void
virtual void visit (TuplePatternItemsNoRest &tuple_items) = 0;
virtual void visit (TuplePatternItemsHasRest &tuple_items) = 0;
virtual void visit (TuplePattern &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 (EmptyStmt &stmt) = 0;
virtual void visit (TuplePatternItemsNoRest &node) override { walk (node); }
virtual void visit (TuplePatternItemsHasRest &node) override { walk (node); }
virtual void visit (TuplePattern &node) override { walk (node); }
+ virtual void visit (SlicePatternItemsNoRest &node) override { walk (node); }
+ virtual void visit (SlicePatternItemsHasRest &node) override { walk (node); }
virtual void visit (SlicePattern &node) override { walk (node); }
virtual void visit (AltPattern &node) override { walk (node); }
virtual void visit (EmptyStmt &node) override { walk (node); }
virtual void walk (TuplePatternItemsNoRest &) final;
virtual void walk (TuplePatternItemsHasRest &) final;
virtual void walk (TuplePattern &) final;
+ virtual void walk (SlicePatternItemsNoRest &) final;
+ virtual void walk (SlicePatternItemsHasRest &) final;
virtual void walk (SlicePattern &) final;
virtual void walk (AltPattern &) final;
virtual void walk (EmptyStmt &) final;
virtual void visit (TuplePatternItemsNoRest &) override {}
virtual void visit (TuplePatternItemsHasRest &) override {}
virtual void visit (TuplePattern &) override {}
+
+ virtual void visit (SlicePatternItemsNoRest &) override {}
+ virtual void visit (SlicePatternItemsHasRest &) override {}
virtual void visit (SlicePattern &) override {}
virtual void visit (AltPattern &) 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 (HIRFullVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+SlicePatternItemsHasRest::accept_vis (HIRFullVisitor &vis)
+{
+ vis.visit (*this);
+}
+
void
SlicePattern::accept_vis (HIRFullVisitor &vis)
{
break;
}
auto cap_wi = wi::to_wide (cap).to_uhwi ();
- if (cap_wi != pattern.get_items ().size ())
+
+ // size check during compile time
+ switch (pattern.get_items ().get_item_type ())
{
- rust_error_at (pattern.get_locus (), ErrorCode::E0527,
- "pattern requires %lu elements but array has %lu",
- (unsigned long) pattern.get_items ().size (),
- (unsigned long) cap_wi);
+ case HIR::SlicePatternItems::ItemType::NO_REST:
+ {
+ auto &ref = static_cast<HIR::SlicePatternItemsNoRest &> (
+ pattern.get_items ());
+ if (cap_wi != ref.get_patterns ().size ())
+ {
+ rust_error_at (
+ pattern.get_locus (), ErrorCode::E0527,
+ "pattern requires %lu elements but array has %lu",
+ (unsigned long) ref.get_patterns ().size (),
+ (unsigned long) cap_wi);
+ break;
+ }
+ }
+ break;
+ case HIR::SlicePatternItems::ItemType::HAS_REST:
+ {
+ auto &ref = static_cast<HIR::SlicePatternItemsHasRest &> (
+ pattern.get_items ());
+ auto pattern_min_cap = ref.get_lower_patterns ().size ()
+ + ref.get_upper_patterns ().size ();
+
+ if (cap_wi < pattern_min_cap)
+ {
+ rust_error_at (
+ pattern.get_locus (), ErrorCode::E0528,
+ "pattern requires at least %lu elements but array has %lu",
+ (unsigned long) pattern_min_cap, (unsigned long) cap_wi);
+ break;
+ }
+ }
break;
}
+
break;
}
case TyTy::SLICE:
infered->set_ref (pattern.get_mappings ().get_hirid ());
// Type check every item in the SlicePattern against parent's element ty
- // TODO update this after adding support for RestPattern in SlicePattern
- for (const auto &item : pattern.get_items ())
+ switch (pattern.get_items ().get_item_type ())
{
- TypeCheckPattern::Resolve (*item, parent_element_ty);
+ case HIR::SlicePatternItems::ItemType::NO_REST:
+ {
+ auto &ref
+ = static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ());
+ for (const auto &pattern_member : ref.get_patterns ())
+ {
+ TypeCheckPattern::Resolve (*pattern_member, parent_element_ty);
+ }
+ break;
+ }
+ case HIR::SlicePatternItems::ItemType::HAS_REST:
+ {
+ auto &ref
+ = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
+ for (const auto &pattern_member : ref.get_lower_patterns ())
+ {
+ TypeCheckPattern::Resolve (*pattern_member, parent_element_ty);
+ }
+ for (const auto &pattern_member : ref.get_upper_patterns ())
+ {
+ TypeCheckPattern::Resolve (*pattern_member, parent_element_ty);
+ }
+ break;
+ }
}
}
-// { dg-options "-fsyntax-only" }
-fn foo(a: &[u32]) {
+pub fn foo(a: &[u32]) {
match a {
[first, ..] => {}
[.., last] => {}
--- /dev/null
+// { dg-output "correct\r*" }
+extern "C" {
+ fn puts(s: *const i8);
+}
+
+fn main() -> i32 {
+ let a = [0, 4, 5, 6, 1];
+ let mut ret = 1;
+
+ match a {
+ [1, .., b] => {
+ /* should not take this path */
+ unsafe { puts("wrong\0" as *const str as *const i8) }
+ }
+ [0, .., 0] => {
+ /* should not take this path */
+ unsafe { puts("wrong\0" as *const str as *const i8) }
+ },
+ [0, .., b] => {
+ ret -= b;
+ unsafe { puts("correct\0" as *const str as *const i8) }
+ },
+ _ => {}
+ }
+
+ ret
+}
--- /dev/null
+// { dg-output "correct\r*" }
+extern "C" {
+ fn puts(s: *const i8);
+}
+
+fn main() -> i32 {
+ let arr = [0, 4, 5, 6, 1];
+ let a: &[i32] = &arr;
+ let mut ret = 1;
+
+ match a {
+ [1, .., b] => {
+ /* should not take this path */
+ unsafe { puts("wrong\0" as *const str as *const i8) }
+ }
+ [0, .., 0] => {
+ /* should not take this path */
+ unsafe { puts("wrong\0" as *const str as *const i8) }
+ },
+ [0, .., b] => {
+ ret -= b;
+ unsafe { puts("correct\0" as *const str as *const i8) }
+ },
+ _ => {}
+ }
+
+ ret
+}