diff options
author | Arthur Cohen <arthur.cohen@embecosm.com> | 2024-03-06 16:19:46 +0100 |
---|---|---|
committer | CohenArthur <arthur.cohen@embecosm.com> | 2024-04-03 19:39:19 +0000 |
commit | fbf35de5dcf89706452513b2ce2926fe95b38daa (patch) | |
tree | 43bac5107d8d37e3514fabea932b4483c68a0cd0 /gcc | |
parent | d9f7604e8e8fadb4e10542d4c5f0004b19de2d96 (diff) | |
download | gcc-fbf35de5dcf89706452513b2ce2926fe95b38daa.zip gcc-fbf35de5dcf89706452513b2ce2926fe95b38daa.tar.gz gcc-fbf35de5dcf89706452513b2ce2926fe95b38daa.tar.bz2 |
unify: Always coerce `!` to the target type.
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.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/typecheck/rust-unify.cc | 36 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/match-never-ltype.rs | 17 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/match-never-rtype.rs | 17 |
3 files changed, 45 insertions, 25 deletions
diff --git a/gcc/rust/typecheck/rust-unify.cc b/gcc/rust/typecheck/rust-unify.cc index 8b43380..7d1042d 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 0000000..6516ab3 --- /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 0000000..6e4e763 --- /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, + } + } +} |