Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 73 additions & 12 deletions gcc/rust/backend/rust-compile-pattern.cc
Original file line number Diff line number Diff line change
Expand Up @@ -358,8 +358,42 @@ CompilePatternCheckExpr::visit (HIR::TupleStructPattern &pattern)
{
case HIR::TupleStructItems::HAS_REST:
{
// TODO
rust_unreachable ();
HIR::TupleStructItemsHasRest &items_has_rest
= static_cast<HIR::TupleStructItemsHasRest &> (items);
size_t num_patterns = items_has_rest.get_lower_patterns ().size ()
+ items_has_rest.get_upper_patterns ().size ();

// enums cases shouldn't reach here
rust_assert (num_patterns <= variant->num_fields ()
&& (!adt->is_enum ()));

size_t tuple_field_index = 0;
for (auto &pattern : items_has_rest.get_lower_patterns ())
{
tree field_expr
= Backend::struct_field_expression (match_scrutinee_expr,
tuple_field_index++,
pattern->get_locus ());
tree check_expr_sub
= CompilePatternCheckExpr::Compile (*pattern, field_expr, ctx);
check_expr = Backend::arithmetic_or_logical_expression (
ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
check_expr_sub, pattern->get_locus ());
}
tuple_field_index = variant->num_fields ()
- items_has_rest.get_upper_patterns ().size ();
for (auto &pattern : items_has_rest.get_upper_patterns ())
{
tree field_expr
= Backend::struct_field_expression (match_scrutinee_expr,
tuple_field_index++,
pattern->get_locus ());
tree check_expr_sub
= CompilePatternCheckExpr::Compile (*pattern, field_expr, ctx);
check_expr = Backend::arithmetic_or_logical_expression (
ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
check_expr_sub, pattern->get_locus ());
}
}
break;

Expand Down Expand Up @@ -738,23 +772,52 @@ CompilePatternBindings::visit (HIR::TupleStructPattern &pattern)
{
case HIR::TupleStructItems::HAS_REST:
{
// TODO
rust_unreachable ();
HIR::TupleStructItemsHasRest &items_has_rest
= static_cast<HIR::TupleStructItemsHasRest &> (items);
size_t num_patterns = items_has_rest.get_lower_patterns ().size ()
+ items_has_rest.get_upper_patterns ().size ();

// enums cases shouldn't reach here
rust_assert (num_patterns <= variant->num_fields ()
&& (!adt->is_enum ()));

size_t tuple_field_index = 0;
for (auto &pattern : items_has_rest.get_lower_patterns ())
{
tree binding
= Backend::struct_field_expression (match_scrutinee_expr,
tuple_field_index++,
pattern->get_locus ());

CompilePatternBindings::Compile (*pattern, binding, ctx);
}

tuple_field_index = variant->num_fields ()
- items_has_rest.get_upper_patterns ().size ();

for (auto &pattern : items_has_rest.get_upper_patterns ())
{
tree binding
= Backend::struct_field_expression (match_scrutinee_expr,
tuple_field_index++,
pattern->get_locus ());

CompilePatternBindings::Compile (*pattern, binding, ctx);
}
}
break;

case HIR::TupleStructItems::NO_REST:
{
HIR::TupleStructItemsNoRest &items_no_range
HIR::TupleStructItemsNoRest &items_no_rest
= static_cast<HIR::TupleStructItemsNoRest &> (items);

rust_assert (items_no_range.get_patterns ().size ()
rust_assert (items_no_rest.get_patterns ().size ()
== variant->num_fields ());

if (adt->is_enum ())
{
size_t tuple_field_index = 0;
for (auto &pattern : items_no_range.get_patterns ())
for (auto &pattern : items_no_rest.get_patterns ())
{
tree payload_accessor_union
= Backend::struct_field_expression (match_scrutinee_expr, 1,
Expand All @@ -776,12 +839,10 @@ CompilePatternBindings::visit (HIR::TupleStructPattern &pattern)
else
{
size_t tuple_field_index = 0;
for (auto &pattern : items_no_range.get_patterns ())
for (auto &pattern : items_no_rest.get_patterns ())
{
tree variant_accessor = match_scrutinee_expr;

tree binding
= Backend::struct_field_expression (variant_accessor,
= Backend::struct_field_expression (match_scrutinee_expr,
tuple_field_index++,
pattern->get_locus ());

Expand Down
39 changes: 33 additions & 6 deletions gcc/rust/checks/errors/rust-hir-pattern-analysis.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1212,25 +1212,52 @@ lower_tuple_pattern (Resolver::TypeCheckContext *ctx,
{
case HIR::TupleStructItems::ItemType::NO_REST:
{
HIR::TupleStructItemsNoRest &multiple
HIR::TupleStructItemsNoRest &items_no_rest
= static_cast<HIR::TupleStructItemsNoRest &> (elems);

rust_assert (variant->get_fields ().size ()
== multiple.get_patterns ().size ());
== items_no_rest.get_patterns ().size ());

for (size_t i = 0; i < multiple.get_patterns ().size (); i++)
for (size_t i = 0; i < items_no_rest.get_patterns ().size (); i++)
{
fields.push_back (
lower_pattern (ctx, *multiple.get_patterns ().at (i),
lower_pattern (ctx, *items_no_rest.get_patterns ().at (i),
variant->get_fields ().at (i)->get_field_type ()));
}
return DeconstructedPat (ctor, arity, fields, pattern.get_locus ());
}
break;
case HIR::TupleStructItems::ItemType::HAS_REST:
{
// TODO: ranged tuple struct items
rust_unreachable ();
HIR::TupleStructItemsHasRest &items_has_rest
= static_cast<HIR::TupleStructItemsHasRest &> (elems);

size_t num_patterns = items_has_rest.get_lower_patterns ().size ()
+ items_has_rest.get_upper_patterns ().size ();

rust_assert (num_patterns <= variant->num_fields ());

size_t i = 0;
for (auto &pattern_member : items_has_rest.get_lower_patterns ())
{
fields.push_back (lower_pattern (
ctx, *pattern_member,
variant->get_fields ().at (i++)->get_field_type ()));
}
while (i < variant->num_fields ()
- items_has_rest.get_upper_patterns ().size ())
{
fields.push_back (
DeconstructedPat::make_wildcard (pattern.get_locus ()));
i++;
}
for (auto &pattern_member : items_has_rest.get_upper_patterns ())
{
fields.push_back (lower_pattern (
ctx, *pattern_member,
variant->get_fields ().at (i++)->get_field_type ()));
}
return DeconstructedPat (ctor, arity, fields, pattern.get_locus ());
}
break;
default:
Expand Down
29 changes: 24 additions & 5 deletions gcc/rust/hir/rust-ast-lower-pattern.cc
Original file line number Diff line number Diff line change
Expand Up @@ -83,20 +83,39 @@ ASTLoweringPattern::visit (AST::TupleStructPattern &pattern)
{
case AST::TupleStructItems::HAS_REST:
{
// TODO
rust_unreachable ();
AST::TupleStructItemsHasRest &items_has_rest
= static_cast<AST::TupleStructItemsHasRest &> (items);

std::vector<std::unique_ptr<HIR::Pattern>> lower_patterns;
lower_patterns.reserve (items_has_rest.get_lower_patterns ().size ());
for (auto &pattern_member : items_has_rest.get_lower_patterns ())
{
lower_patterns.emplace_back (
ASTLoweringPattern::translate (*pattern_member));
}

std::vector<std::unique_ptr<HIR::Pattern>> upper_patterns;
upper_patterns.reserve (items_has_rest.get_upper_patterns ().size ());
for (auto &pattern_member : items_has_rest.get_upper_patterns ())
{
upper_patterns.emplace_back (
ASTLoweringPattern::translate (*pattern_member));
}

lowered = new HIR::TupleStructItemsHasRest (std::move (lower_patterns),
std::move (upper_patterns));
}
break;

case AST::TupleStructItems::NO_REST:
{
AST::TupleStructItemsNoRest &items_no_range
AST::TupleStructItemsNoRest &items_no_rest
= static_cast<AST::TupleStructItemsNoRest &> (items);

std::vector<std::unique_ptr<HIR::Pattern>> patterns;
patterns.reserve (items_no_range.get_patterns ().size ());
patterns.reserve (items_no_rest.get_patterns ().size ());

for (auto &inner_pattern : items_no_range.get_patterns ())
for (auto &inner_pattern : items_no_rest.get_patterns ())
patterns.emplace_back (
ASTLoweringPattern::translate (*inner_pattern));

Expand Down
133 changes: 122 additions & 11 deletions gcc/rust/typecheck/rust-hir-type-check-pattern.cc
Original file line number Diff line number Diff line change
Expand Up @@ -202,31 +202,142 @@ TypeCheckPattern::visit (HIR::TupleStructPattern &pattern)
{
case HIR::TupleStructItems::HAS_REST:
{
// TODO
rust_unreachable ();
HIR::TupleStructItemsHasRest &items_has_rest
= static_cast<HIR::TupleStructItemsHasRest &> (items);
auto &lower_patterns = items_has_rest.get_lower_patterns ();
auto &upper_patterns = items_has_rest.get_upper_patterns ();
size_t pattern_min_cap
= lower_patterns.size () + upper_patterns.size ();
if (variant->num_fields () < pattern_min_cap)
{
if (!lower_patterns.empty ())
{
// TODO initialize rich_locus with loc of ADT definition instead
rich_location rich_locus (line_table,
lower_patterns[0]->get_locus ());
for (auto &pattern : lower_patterns)
{
if (pattern == lower_patterns[0])
continue;
rich_locus.add_range (pattern->get_locus (),
SHOW_RANGE_WITH_CARET);
}
for (auto &pattern : upper_patterns)
{
rich_locus.add_range (pattern->get_locus (),
SHOW_RANGE_WITH_CARET);
}
rust_error_at (rich_locus, ErrorCode::E0023,
"this pattern has %lu %s but the corresponding "
"tuple variant has %lu %s",
(unsigned long) (pattern_min_cap),
pattern_min_cap == 1 ? "field" : "fields",
(unsigned long) variant->num_fields (),
variant->num_fields () == 1 ? "field"
: "fields");
}
else
{
// TODO initialize rich_locus with loc of ADT definition instead
rich_location rich_locus (line_table,
upper_patterns[0]->get_locus ());
for (auto &pattern : upper_patterns)
{
if (pattern == upper_patterns[0])
continue;
rich_locus.add_range (pattern->get_locus (),
SHOW_RANGE_WITH_CARET);
}
rust_error_at (rich_locus, ErrorCode::E0023,
"this pattern has %lu %s but the corresponding "
"tuple variant has %lu %s",
(unsigned long) (pattern_min_cap),
pattern_min_cap == 1 ? "field" : "fields",
(unsigned long) variant->num_fields (),
variant->num_fields () == 1 ? "field"
: "fields");
}
// we continue on to try and setup the types as best we can for
// type checking
}

// iterate the fields manually to set them up
size_t i = 0;
for (auto &pattern : lower_patterns)
{
if (i >= variant->num_fields ())
break;

TyTy::StructFieldType *field = variant->get_field_at_index (i++);
TyTy::BaseType *fty = field->get_field_type ();

// setup the type on this pattern type
context->insert_type (pattern->get_mappings (), fty);
TypeCheckPattern::Resolve (*pattern, fty);
}

i = variant->num_fields () - upper_patterns.size ();
for (auto &pattern : upper_patterns)
{
if (i >= variant->num_fields ())
break;

TyTy::StructFieldType *field = variant->get_field_at_index (i++);
TyTy::BaseType *fty = field->get_field_type ();

// setup the type on this pattern type
context->insert_type (pattern->get_mappings (), fty);
TypeCheckPattern::Resolve (*pattern, fty);
}
}
break;

case HIR::TupleStructItems::NO_REST:
{
HIR::TupleStructItemsNoRest &items_no_range
HIR::TupleStructItemsNoRest &items_no_rest
= static_cast<HIR::TupleStructItemsNoRest &> (items);
auto &patterns = items_no_rest.get_patterns ();

if (items_no_range.get_patterns ().size () != variant->num_fields ())
if (patterns.size () != variant->num_fields ())
{
rust_error_at (
pattern.get_locus (), ErrorCode::E0023,
"this pattern has %lu fields but the corresponding "
"tuple variant has %lu field",
(unsigned long) items_no_range.get_patterns ().size (),
(unsigned long) variant->num_fields ());
if (patterns.empty ())
{
rust_error_at (pattern.get_locus (), ErrorCode::E0023,
"this pattern has %lu %s but the corresponding "
"tuple variant has %lu %s",
(unsigned long) patterns.size (),
patterns.size () == 1 ? "field" : "fields",
(unsigned long) variant->num_fields (),
variant->num_fields () == 1 ? "field"
: "fields");
}
else
{
rich_location rich_locus (line_table,
patterns[0]->get_locus ());
for (auto &pattern : items_no_rest.get_patterns ())
{
if (pattern == patterns[0])
continue;
rich_locus.add_range (pattern->get_locus (),
SHOW_RANGE_WITH_CARET);
}
rust_error_at (rich_locus, ErrorCode::E0023,
"this pattern has %lu %s but the corresponding "
"tuple variant has %lu %s",
(unsigned long) patterns.size (),
patterns.size () == 1 ? "field" : "fields",
(unsigned long) variant->num_fields (),
variant->num_fields () == 1 ? "field"
: "fields");
}
// we continue on to try and setup the types as best we can for
// type checking
}

// iterate the fields and set them up, I wish we had ZIP
size_t i = 0;
for (auto &pattern : items_no_range.get_patterns ())
for (auto &pattern : items_no_rest.get_patterns ())
{
if (i >= variant->num_fields ())
break;
Expand Down
14 changes: 14 additions & 0 deletions gcc/testsuite/rust/compile/match-tuplestructpattern-err.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
fn main() {
struct A (i32, i32);
let a = A (0, 1);

match a {
A (1, 2, 3, 4) => {},
// { dg-error "this pattern has 4 fields but the corresponding tuple variant has 2 fields .E0023." "" { target *-*-* } .-1 }
A (1, 2, .., 3, 4) => {},
// { dg-error "this pattern has 4 fields but the corresponding tuple variant has 2 fields .E0023." "" { target *-*-* } .-1 }
A (.., 3, 4, 5) => {},
// { dg-error "this pattern has 3 fields but the corresponding tuple variant has 2 fields .E0023." "" { target *-*-* } .-1 }
_ => {}
}
}
Loading
Loading