Commit Message
Arthur Cohen
Aug. 1, 2024, 2:57 p.m. UTC
Never can... never... exist, so it should always be coerced to the type it is being matched against. This is useful for breaking off of a loop from inside a match, or an if condition, for example. gcc/rust/ChangeLog: * typecheck/rust-unify.cc (UnifyRules::go): Always unify to `ltype` if we are matching against a `Never` in `rtype`. (UnifyRules::expect_never): Always unify to the expected type. gcc/testsuite/ChangeLog: * rust/compile/match-never-ltype.rs: New test. * rust/compile/match-never-rtype.rs: New test. --- gcc/rust/typecheck/rust-unify.cc | 36 ++++++------------- .../rust/compile/match-never-ltype.rs | 17 +++++++++ .../rust/compile/match-never-rtype.rs | 17 +++++++++ 3 files changed, 45 insertions(+), 25 deletions(-) create mode 100644 gcc/testsuite/rust/compile/match-never-ltype.rs create mode 100644 gcc/testsuite/rust/compile/match-never-rtype.rs
diff --git a/gcc/rust/typecheck/rust-unify.cc b/gcc/rust/typecheck/rust-unify.cc index 8b43380cc59..7d1042d8e63 100644 --- a/gcc/rust/typecheck/rust-unify.cc +++ b/gcc/rust/typecheck/rust-unify.cc @@ -17,6 +17,7 @@ // <http://www.gnu.org/licenses/>. #include "rust-unify.h" +#include "rust-tyty.h" namespace Rust { namespace Resolver { @@ -237,6 +238,15 @@ UnifyRules::go () } } + // The never type should always get coerced to the type it's being matched + // against, so in that case, ltype. This avoids doing the same check in all + // the `expect_*` functions. + // However, this does not work if we have an annoying ltype - like INFER. + // TODO: Is ltype == Infer the only special case here? What about projections? + // references? + if (rtype->get_kind () == TyTy::NEVER && ltype->get_kind () != TyTy::INFER) + return ltype->clone (); + switch (ltype->get_kind ()) { case TyTy::INFER: @@ -1536,32 +1546,8 @@ UnifyRules::expect_never (TyTy::NeverType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::NEVER: + default: return rtype->clone (); - - case TyTy::PLACEHOLDER: - case TyTy::PROJECTION: - case TyTy::DYNAMIC: - case TyTy::CLOSURE: - case TyTy::SLICE: - case TyTy::PARAM: - case TyTy::POINTER: - case TyTy::STR: - case TyTy::ADT: - case TyTy::REF: - case TyTy::ARRAY: - case TyTy::FNDEF: - case TyTy::FNPTR: - case TyTy::TUPLE: - case TyTy::BOOL: - case TyTy::CHAR: - case TyTy::INT: - case TyTy::UINT: - case TyTy::FLOAT: - case TyTy::USIZE: - case TyTy::ISIZE: - case TyTy::ERROR: - return new TyTy::ErrorType (0); } return new TyTy::ErrorType (0); } diff --git a/gcc/testsuite/rust/compile/match-never-ltype.rs b/gcc/testsuite/rust/compile/match-never-ltype.rs new file mode 100644 index 00000000000..6516ab3c1ea --- /dev/null +++ b/gcc/testsuite/rust/compile/match-never-ltype.rs @@ -0,0 +1,17 @@ +fn foo() {} + +enum Foo { + A, + B, +} + +fn main() { + let a = Foo::A; + + loop { + match a { + Foo::A => break, + Foo::B => foo(), + } + } +} diff --git a/gcc/testsuite/rust/compile/match-never-rtype.rs b/gcc/testsuite/rust/compile/match-never-rtype.rs new file mode 100644 index 00000000000..6e4e7638f67 --- /dev/null +++ b/gcc/testsuite/rust/compile/match-never-rtype.rs @@ -0,0 +1,17 @@ +fn foo() {} + +enum Foo { + A, + B, +} + +fn main() { + let a = Foo::A; + + loop { + match a { + Foo::B => foo(), + Foo::A => break, + } + } +}