diff mbox series

[109/125] gccrs: unify: Always coerce `!` to the target type.

Message ID 20240801145809.366388-111-arthur.cohen@embecosm.com
State New
Headers show
Series [001/125] Rust: Make 'tree'-level 'MAIN_NAME_P' work | expand

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 mbox series

Patch

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,
+        }
+    }
+}