Skip to content

Commit

Permalink
gccrs: empty match expressions should resolve to !
Browse files Browse the repository at this point in the history
This is a special case in Rust and the ! type can unify with pretty much
anything its almost a inference variable and a unit-type for special cases.

Fixes #3231
Fixes #2567

gcc/rust/ChangeLog:

	* backend/rust-compile-expr.cc (check_match_scrutinee): check for empty match
	(CompileExpr::visit): fix assertion
	* checks/errors/rust-hir-pattern-analysis.cc (check_match_usefulness): check for empty
	* typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): resolve to !

gcc/testsuite/ChangeLog:

	* rust/compile/exhaustiveness1.rs: remove bad check
	* rust/compile/issue-2567-1.rs: New test.
	* rust/compile/issue-2567-2.rs: New test.
	* rust/compile/issue-2567-3.rs: New test.
	* rust/compile/issue-3231.rs: New test.

Signed-off-by: Philip Herron <[email protected]>
  • Loading branch information
philberty authored and CohenArthur committed Nov 22, 2024
1 parent b3f0d72 commit 433a092
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 14 deletions.
21 changes: 10 additions & 11 deletions gcc/rust/backend/rust-compile-expr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1013,17 +1013,7 @@ check_match_scrutinee (HIR::MatchExpr &expr, Context *ctx)
|| scrutinee_kind == TyTy::TypeKind::TUPLE
|| scrutinee_kind == TyTy::TypeKind::REF);

if (scrutinee_kind == TyTy::TypeKind::ADT)
{
// this will need to change but for now the first pass implementation,
// lets assert this is the case
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (scrutinee_expr_tyty);
if (adt->is_enum ())
rust_assert (adt->number_of_variants () > 0);
else
rust_assert (adt->number_of_variants () == 1);
}
else if (scrutinee_kind == TyTy::TypeKind::FLOAT)
if (scrutinee_kind == TyTy::TypeKind::FLOAT)
{
// FIXME: CASE_LABEL_EXPR does not support floating point types.
// Find another way to compile these.
Expand Down Expand Up @@ -1064,6 +1054,15 @@ CompileExpr::visit (HIR::MatchExpr &expr)
return;
}

// if the result of this expression is meant to be never type then we can
// optimise this away but there is the case where match arms resolve to !
// because of return statements we need to special case this
if (!expr.has_match_arms () && expr_tyty->is<TyTy::NeverType> ())
{
translated = unit_expression (expr.get_locus ());
return;
}

fncontext fnctx = ctx->peek_fn ();
Bvariable *tmp = NULL;
tree enclosing_scope = ctx->peek_enclosing_scope ();
Expand Down
3 changes: 3 additions & 0 deletions gcc/rust/checks/errors/rust-hir-pattern-analysis.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1530,6 +1530,9 @@ void
check_match_usefulness (Resolver::TypeCheckContext *ctx,
TyTy::BaseType *scrutinee_ty, HIR::MatchExpr &expr)
{
if (!expr.has_match_arms ())
return;

// Lower the arms to a more convenient representation.
std::vector<MatrixRow> rows;
for (auto &arm : expr.get_match_cases ())
Expand Down
12 changes: 12 additions & 0 deletions gcc/rust/typecheck/rust-hir-type-check-expr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1456,6 +1456,18 @@ TypeCheckExpr::visit (HIR::MatchExpr &expr)
TyTy::BaseType *scrutinee_tyty
= TypeCheckExpr::Resolve (expr.get_scrutinee_expr ());

// https://github.com/Rust-GCC/gccrs/issues/3231#issuecomment-2462660048
// https://github.com/rust-lang/rust/blob/3d1dba830a564d1118361345d7ada47a05241f45/compiler/rustc_hir_typeck/src/_match.rs#L32-L36
if (!expr.has_match_arms ())
{
// this is a special case where rustc returns !
TyTy::BaseType *lookup = nullptr;
bool ok = context->lookup_builtin ("!", &lookup);
rust_assert (ok);
infered = lookup->clone ();
return;
}

bool saw_error = false;
std::vector<TyTy::BaseType *> kase_block_tys;
for (auto &kase : expr.get_match_cases ())
Expand Down
4 changes: 1 addition & 3 deletions gcc/testsuite/rust/compile/exhaustiveness1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ fn s2(s: S) {
}

fn s3(s: S) {
match s {
// { dg-error "non-exhaustive patterns: '_' not covered" "" { target *-*-* } .-1 }
}
match s {}
}

enum E {
Expand Down
8 changes: 8 additions & 0 deletions gcc/testsuite/rust/compile/issue-2567-1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// { dg-options "-w" }
enum Empty {}

fn foo(x: Empty) {
let x: Empty = match x {
// empty
};
}
8 changes: 8 additions & 0 deletions gcc/testsuite/rust/compile/issue-2567-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// { dg-options "-w" }
enum Empty {}

fn foo(x: Empty) {
let x: i32 = match x {
// empty
};
}
8 changes: 8 additions & 0 deletions gcc/testsuite/rust/compile/issue-2567-3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// { dg-options "-w" }
enum Empty {}

fn foo(x: Empty) {
match x {
// empty
}
}
8 changes: 8 additions & 0 deletions gcc/testsuite/rust/compile/issue-3231.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// { dg-options "-w" }
pub enum X {}

pub fn foo(x: X) {
let _a: i32 = match x {};
}

pub fn main() {}

0 comments on commit 433a092

Please sign in to comment.