summaryrefslogtreecommitdiffstats
path: root/src/test/ui/let-else
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/test/ui/let-else/let-else-allow-in-expr.rs30
-rw-r--r--src/test/ui/let-else/let-else-allow-in-expr.stderr20
-rw-r--r--src/test/ui/let-else/let-else-allow-unused.rs15
-rw-r--r--src/test/ui/let-else/let-else-allow-unused.stderr14
-rw-r--r--src/test/ui/let-else/let-else-binding-explicit-mut-annotated.rs16
-rw-r--r--src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr25
-rw-r--r--src/test/ui/let-else/let-else-binding-explicit-mut-borrow.rs13
-rw-r--r--src/test/ui/let-else/let-else-binding-explicit-mut-borrow.stderr9
-rw-r--r--src/test/ui/let-else/let-else-binding-explicit-mut-pass.rs13
-rw-r--r--src/test/ui/let-else/let-else-binding-explicit-mut.rs20
-rw-r--r--src/test/ui/let-else/let-else-binding-explicit-mut.stderr21
-rw-r--r--src/test/ui/let-else/let-else-binding-immutable.rs10
-rw-r--r--src/test/ui/let-else/let-else-binding-immutable.stderr9
-rw-r--r--src/test/ui/let-else/let-else-bindings.rs75
-rw-r--r--src/test/ui/let-else/let-else-bool-binop-init.fixed8
-rw-r--r--src/test/ui/let-else/let-else-bool-binop-init.rs8
-rw-r--r--src/test/ui/let-else/let-else-bool-binop-init.stderr24
-rw-r--r--src/test/ui/let-else/let-else-brace-before-else.fixed26
-rw-r--r--src/test/ui/let-else/let-else-brace-before-else.rs26
-rw-r--r--src/test/ui/let-else/let-else-brace-before-else.stderr46
-rw-r--r--src/test/ui/let-else/let-else-check.rs19
-rw-r--r--src/test/ui/let-else/let-else-check.stderr20
-rw-r--r--src/test/ui/let-else/let-else-deref-coercion-annotated.rs77
-rw-r--r--src/test/ui/let-else/let-else-deref-coercion.rs75
-rw-r--r--src/test/ui/let-else/let-else-deref-coercion.stderr19
-rw-r--r--src/test/ui/let-else/let-else-destructuring.rs18
-rw-r--r--src/test/ui/let-else/let-else-destructuring.stderr17
-rw-r--r--src/test/ui/let-else/let-else-if.rs10
-rw-r--r--src/test/ui/let-else/let-else-if.stderr17
-rw-r--r--src/test/ui/let-else/let-else-irrefutable.rs7
-rw-r--r--src/test/ui/let-else/let-else-irrefutable.stderr12
-rw-r--r--src/test/ui/let-else/let-else-missing-semicolon.rs11
-rw-r--r--src/test/ui/let-else/let-else-missing-semicolon.stderr18
-rw-r--r--src/test/ui/let-else/let-else-no-double-error.rs12
-rw-r--r--src/test/ui/let-else/let-else-no-double-error.stderr9
-rw-r--r--src/test/ui/let-else/let-else-non-copy.rs45
-rw-r--r--src/test/ui/let-else/let-else-non-diverging.rs13
-rw-r--r--src/test/ui/let-else/let-else-non-diverging.stderr44
-rw-r--r--src/test/ui/let-else/let-else-ref-bindings-pass.rs71
-rw-r--r--src/test/ui/let-else/let-else-ref-bindings.rs62
-rw-r--r--src/test/ui/let-else/let-else-ref-bindings.stderr83
-rw-r--r--src/test/ui/let-else/let-else-run-pass.rs35
-rw-r--r--src/test/ui/let-else/let-else-scope.rs7
-rw-r--r--src/test/ui/let-else/let-else-scope.stderr9
-rw-r--r--src/test/ui/let-else/let-else-slicing-error.rs9
-rw-r--r--src/test/ui/let-else/let-else-slicing-error.stderr11
-rw-r--r--src/test/ui/let-else/let-else-source-expr-nomove-pass.rs17
-rw-r--r--src/test/ui/let-else/let-else-temp-borrowck.rs26
-rw-r--r--src/test/ui/let-else/let-else-temporary-lifetime.rs88
49 files changed, 1289 insertions, 0 deletions
diff --git a/src/test/ui/let-else/let-else-allow-in-expr.rs b/src/test/ui/let-else/let-else-allow-in-expr.rs
new file mode 100644
index 000000000..39f4c9060
--- /dev/null
+++ b/src/test/ui/let-else/let-else-allow-in-expr.rs
@@ -0,0 +1,30 @@
+#![feature(let_else)]
+
+#![deny(unused_variables)]
+
+fn main() {
+ let Some(_): Option<u32> = ({
+ let x = 1; //~ ERROR unused variable: `x`
+ Some(1)
+ }) else {
+ return;
+ };
+
+ #[allow(unused_variables)]
+ let Some(_): Option<u32> = ({
+ let x = 1;
+ Some(1)
+ }) else {
+ return;
+ };
+
+ let Some(_): Option<u32> = ({
+ #[allow(unused_variables)]
+ let x = 1;
+ Some(1)
+ }) else {
+ return;
+ };
+
+ let x = 1; //~ ERROR unused variable: `x`
+}
diff --git a/src/test/ui/let-else/let-else-allow-in-expr.stderr b/src/test/ui/let-else/let-else-allow-in-expr.stderr
new file mode 100644
index 000000000..e86bcbc85
--- /dev/null
+++ b/src/test/ui/let-else/let-else-allow-in-expr.stderr
@@ -0,0 +1,20 @@
+error: unused variable: `x`
+ --> $DIR/let-else-allow-in-expr.rs:7:13
+ |
+LL | let x = 1;
+ | ^ help: if this is intentional, prefix it with an underscore: `_x`
+ |
+note: the lint level is defined here
+ --> $DIR/let-else-allow-in-expr.rs:3:9
+ |
+LL | #![deny(unused_variables)]
+ | ^^^^^^^^^^^^^^^^
+
+error: unused variable: `x`
+ --> $DIR/let-else-allow-in-expr.rs:29:9
+ |
+LL | let x = 1;
+ | ^ help: if this is intentional, prefix it with an underscore: `_x`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/let-else/let-else-allow-unused.rs b/src/test/ui/let-else/let-else-allow-unused.rs
new file mode 100644
index 000000000..86ebacfa7
--- /dev/null
+++ b/src/test/ui/let-else/let-else-allow-unused.rs
@@ -0,0 +1,15 @@
+// issue #89807
+
+#![feature(let_else)]
+
+#[deny(unused_variables)]
+
+fn main() {
+ let value = Some(String::new());
+ #[allow(unused)]
+ let banana = 1;
+ #[allow(unused)]
+ let Some(chaenomeles) = value.clone() else { return }; // OK
+
+ let Some(chaenomeles) = value else { return }; //~ ERROR unused variable: `chaenomeles`
+}
diff --git a/src/test/ui/let-else/let-else-allow-unused.stderr b/src/test/ui/let-else/let-else-allow-unused.stderr
new file mode 100644
index 000000000..05b8a9169
--- /dev/null
+++ b/src/test/ui/let-else/let-else-allow-unused.stderr
@@ -0,0 +1,14 @@
+error: unused variable: `chaenomeles`
+ --> $DIR/let-else-allow-unused.rs:14:14
+ |
+LL | let Some(chaenomeles) = value else { return };
+ | ^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_chaenomeles`
+ |
+note: the lint level is defined here
+ --> $DIR/let-else-allow-unused.rs:5:8
+ |
+LL | #[deny(unused_variables)]
+ | ^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.rs b/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.rs
new file mode 100644
index 000000000..b65fa13c1
--- /dev/null
+++ b/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.rs
@@ -0,0 +1,16 @@
+// from rfc2005 test suite
+
+#![feature(let_else)]
+
+// Verify the binding mode shifts - only when no `&` are auto-dereferenced is the
+// final default binding mode mutable.
+
+fn main() {
+ let Some(n): &mut Option<i32> = &&Some(5i32) else { return }; //~ ERROR mismatched types
+ *n += 1;
+ let _ = n;
+
+ let Some(n): &mut Option<i32> = &&mut Some(5i32) else { return }; //~ ERROR mismatched types
+ *n += 1;
+ let _ = n;
+}
diff --git a/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr b/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr
new file mode 100644
index 000000000..065787cab
--- /dev/null
+++ b/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr
@@ -0,0 +1,25 @@
+error[E0308]: mismatched types
+ --> $DIR/let-else-binding-explicit-mut-annotated.rs:9:37
+ |
+LL | let Some(n): &mut Option<i32> = &&Some(5i32) else { return };
+ | ---------------- ^^^^^^^^^^^^ types differ in mutability
+ | |
+ | expected due to this
+ |
+ = note: expected mutable reference `&mut Option<i32>`
+ found reference `&&Option<i32>`
+
+error[E0308]: mismatched types
+ --> $DIR/let-else-binding-explicit-mut-annotated.rs:13:37
+ |
+LL | let Some(n): &mut Option<i32> = &&mut Some(5i32) else { return };
+ | ---------------- ^^^^^^^^^^^^^^^^ types differ in mutability
+ | |
+ | expected due to this
+ |
+ = note: expected mutable reference `&mut Option<i32>`
+ found reference `&&mut Option<i32>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/let-else/let-else-binding-explicit-mut-borrow.rs b/src/test/ui/let-else/let-else-binding-explicit-mut-borrow.rs
new file mode 100644
index 000000000..63b35df76
--- /dev/null
+++ b/src/test/ui/let-else/let-else-binding-explicit-mut-borrow.rs
@@ -0,0 +1,13 @@
+#![feature(let_else)]
+
+// Slightly different from explicit-mut-annotated -- this won't show an error until borrowck.
+// Should it show a type error instead?
+
+fn main() {
+ let Some(n): &mut Option<i32> = &mut &Some(5i32) else {
+ //~^ ERROR cannot borrow data in a `&` reference as mutable
+ return
+ };
+ *n += 1;
+ let _ = n;
+}
diff --git a/src/test/ui/let-else/let-else-binding-explicit-mut-borrow.stderr b/src/test/ui/let-else/let-else-binding-explicit-mut-borrow.stderr
new file mode 100644
index 000000000..023fab8fe
--- /dev/null
+++ b/src/test/ui/let-else/let-else-binding-explicit-mut-borrow.stderr
@@ -0,0 +1,9 @@
+error[E0596]: cannot borrow data in a `&` reference as mutable
+ --> $DIR/let-else-binding-explicit-mut-borrow.rs:7:37
+ |
+LL | let Some(n): &mut Option<i32> = &mut &Some(5i32) else {
+ | ^^^^^^^^^^^^^^^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/let-else/let-else-binding-explicit-mut-pass.rs b/src/test/ui/let-else/let-else-binding-explicit-mut-pass.rs
new file mode 100644
index 000000000..305be9221
--- /dev/null
+++ b/src/test/ui/let-else/let-else-binding-explicit-mut-pass.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+#![feature(let_else)]
+
+fn main() {
+ let Some(n) = &mut &mut Some(5i32) else { return; };
+ *n += 1; // OK
+ let _ = n;
+
+ let Some(n): &mut Option<i32> = &mut &mut Some(5i32) else { return; };
+ *n += 1; // OK
+ let _ = n;
+}
diff --git a/src/test/ui/let-else/let-else-binding-explicit-mut.rs b/src/test/ui/let-else/let-else-binding-explicit-mut.rs
new file mode 100644
index 000000000..dbe4715b1
--- /dev/null
+++ b/src/test/ui/let-else/let-else-binding-explicit-mut.rs
@@ -0,0 +1,20 @@
+// from rfc2005 test suite
+
+#![feature(let_else)]
+
+// Verify the binding mode shifts - only when no `&` are auto-dereferenced is the
+// final default binding mode mutable.
+
+fn main() {
+ let Some(n) = &&Some(5i32) else { return };
+ *n += 1; //~ ERROR cannot assign to `*n`, which is behind a `&` reference
+ let _ = n;
+
+ let Some(n) = &mut &Some(5i32) else { return };
+ *n += 1; //~ ERROR cannot assign to `*n`, which is behind a `&` reference
+ let _ = n;
+
+ let Some(n) = &&mut Some(5i32) else { return };
+ *n += 1; //~ ERROR cannot assign to `*n`, which is behind a `&` reference
+ let _ = n;
+}
diff --git a/src/test/ui/let-else/let-else-binding-explicit-mut.stderr b/src/test/ui/let-else/let-else-binding-explicit-mut.stderr
new file mode 100644
index 000000000..45f2b6b3b
--- /dev/null
+++ b/src/test/ui/let-else/let-else-binding-explicit-mut.stderr
@@ -0,0 +1,21 @@
+error[E0594]: cannot assign to `*n`, which is behind a `&` reference
+ --> $DIR/let-else-binding-explicit-mut.rs:10:5
+ |
+LL | *n += 1;
+ | ^^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written
+
+error[E0594]: cannot assign to `*n`, which is behind a `&` reference
+ --> $DIR/let-else-binding-explicit-mut.rs:14:5
+ |
+LL | *n += 1;
+ | ^^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written
+
+error[E0594]: cannot assign to `*n`, which is behind a `&` reference
+ --> $DIR/let-else-binding-explicit-mut.rs:18:5
+ |
+LL | *n += 1;
+ | ^^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/let-else/let-else-binding-immutable.rs b/src/test/ui/let-else/let-else-binding-immutable.rs
new file mode 100644
index 000000000..96de0ffe2
--- /dev/null
+++ b/src/test/ui/let-else/let-else-binding-immutable.rs
@@ -0,0 +1,10 @@
+// from rfc2005 test suite
+
+#![feature(let_else)]
+
+pub fn main() {
+ let Some(x) = &Some(3) else {
+ panic!();
+ };
+ *x += 1; //~ ERROR: cannot assign to `*x`, which is behind a `&` reference
+}
diff --git a/src/test/ui/let-else/let-else-binding-immutable.stderr b/src/test/ui/let-else/let-else-binding-immutable.stderr
new file mode 100644
index 000000000..dd1365a9e
--- /dev/null
+++ b/src/test/ui/let-else/let-else-binding-immutable.stderr
@@ -0,0 +1,9 @@
+error[E0594]: cannot assign to `*x`, which is behind a `&` reference
+ --> $DIR/let-else-binding-immutable.rs:9:5
+ |
+LL | *x += 1;
+ | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/let-else/let-else-bindings.rs b/src/test/ui/let-else/let-else-bindings.rs
new file mode 100644
index 000000000..d5121e744
--- /dev/null
+++ b/src/test/ui/let-else/let-else-bindings.rs
@@ -0,0 +1,75 @@
+// run-pass
+// adapted from src/test/ui/binding/if-let.rs
+#![feature(let_else)]
+#![allow(dead_code)]
+
+fn none() -> bool {
+ let None = Some("test") else {
+ return true;
+ };
+ false
+}
+
+fn ok() -> bool {
+ let Ok(()) = Err::<(),&'static str>("test") else {
+ return true;
+ };
+ false
+}
+
+pub fn main() {
+ let x = Some(3);
+ let Some(y) = x else {
+ panic!("let-else panicked");
+ };
+ assert_eq!(y, 3);
+ let Some(_) = x else {
+ panic!("bad match");
+ };
+ assert!(none());
+ assert!(ok());
+
+ assert!((|| {
+ let 1 = 2 else {
+ return true;
+ };
+ false
+ })());
+
+ enum Foo {
+ One,
+ Two(usize),
+ Three(String, isize),
+ }
+
+ let foo = Foo::Three("three".to_string(), 42);
+ let one = || {
+ let Foo::One = foo else {
+ return true;
+ };
+ false
+ };
+ assert!(one());
+ let two = || {
+ let Foo::Two(_x) = foo else {
+ return true;
+ };
+ false
+ };
+ assert!(two());
+ let three = || {
+ let Foo::Three(s, _x) = foo else {
+ return false;
+ };
+ s == "three"
+ };
+ assert!(three());
+
+ let a@Foo::Two(_) = Foo::Two(42_usize) else {
+ panic!("bad match")
+ };
+ let Foo::Two(b) = a else {
+ panic!("panic in nested `if let`");
+ };
+ assert_eq!(b, 42_usize);
+}
diff --git a/src/test/ui/let-else/let-else-bool-binop-init.fixed b/src/test/ui/let-else/let-else-bool-binop-init.fixed
new file mode 100644
index 000000000..e47f7f23d
--- /dev/null
+++ b/src/test/ui/let-else/let-else-bool-binop-init.fixed
@@ -0,0 +1,8 @@
+// run-rustfix
+
+#![feature(let_else)]
+
+fn main() {
+ let true = (true && false) else { return }; //~ ERROR a `&&` expression cannot be directly assigned in `let...else`
+ let true = (true || false) else { return }; //~ ERROR a `||` expression cannot be directly assigned in `let...else`
+}
diff --git a/src/test/ui/let-else/let-else-bool-binop-init.rs b/src/test/ui/let-else/let-else-bool-binop-init.rs
new file mode 100644
index 000000000..e443fb0d6
--- /dev/null
+++ b/src/test/ui/let-else/let-else-bool-binop-init.rs
@@ -0,0 +1,8 @@
+// run-rustfix
+
+#![feature(let_else)]
+
+fn main() {
+ let true = true && false else { return }; //~ ERROR a `&&` expression cannot be directly assigned in `let...else`
+ let true = true || false else { return }; //~ ERROR a `||` expression cannot be directly assigned in `let...else`
+}
diff --git a/src/test/ui/let-else/let-else-bool-binop-init.stderr b/src/test/ui/let-else/let-else-bool-binop-init.stderr
new file mode 100644
index 000000000..edee65762
--- /dev/null
+++ b/src/test/ui/let-else/let-else-bool-binop-init.stderr
@@ -0,0 +1,24 @@
+error: a `&&` expression cannot be directly assigned in `let...else`
+ --> $DIR/let-else-bool-binop-init.rs:6:16
+ |
+LL | let true = true && false else { return };
+ | ^^^^^^^^^^^^^
+ |
+help: wrap the expression in parentheses
+ |
+LL | let true = (true && false) else { return };
+ | + +
+
+error: a `||` expression cannot be directly assigned in `let...else`
+ --> $DIR/let-else-bool-binop-init.rs:7:16
+ |
+LL | let true = true || false else { return };
+ | ^^^^^^^^^^^^^
+ |
+help: wrap the expression in parentheses
+ |
+LL | let true = (true || false) else { return };
+ | + +
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/let-else/let-else-brace-before-else.fixed b/src/test/ui/let-else/let-else-brace-before-else.fixed
new file mode 100644
index 000000000..fb4fd7779
--- /dev/null
+++ b/src/test/ui/let-else/let-else-brace-before-else.fixed
@@ -0,0 +1,26 @@
+// run-rustfix
+
+#![feature(let_else)]
+
+fn main() {
+ let Some(1) = ({ Some(1) }) else {
+ //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
+ return;
+ };
+ let Some(1) = (loop { break Some(1) }) else {
+ //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
+ return;
+ };
+ let 2 = 1 + (match 1 { n => n }) else {
+ //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
+ return;
+ };
+ let Some(1) = (unsafe { unsafe_fn() }) else {
+ //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
+ return;
+ };
+}
+
+unsafe fn unsafe_fn<T>() -> T {
+ unimplemented!();
+}
diff --git a/src/test/ui/let-else/let-else-brace-before-else.rs b/src/test/ui/let-else/let-else-brace-before-else.rs
new file mode 100644
index 000000000..c4c5a1ca2
--- /dev/null
+++ b/src/test/ui/let-else/let-else-brace-before-else.rs
@@ -0,0 +1,26 @@
+// run-rustfix
+
+#![feature(let_else)]
+
+fn main() {
+ let Some(1) = { Some(1) } else {
+ //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
+ return;
+ };
+ let Some(1) = loop { break Some(1) } else {
+ //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
+ return;
+ };
+ let 2 = 1 + match 1 { n => n } else {
+ //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
+ return;
+ };
+ let Some(1) = unsafe { unsafe_fn() } else {
+ //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
+ return;
+ };
+}
+
+unsafe fn unsafe_fn<T>() -> T {
+ unimplemented!();
+}
diff --git a/src/test/ui/let-else/let-else-brace-before-else.stderr b/src/test/ui/let-else/let-else-brace-before-else.stderr
new file mode 100644
index 000000000..51051bbd4
--- /dev/null
+++ b/src/test/ui/let-else/let-else-brace-before-else.stderr
@@ -0,0 +1,46 @@
+error: right curly brace `}` before `else` in a `let...else` statement not allowed
+ --> $DIR/let-else-brace-before-else.rs:6:29
+ |
+LL | let Some(1) = { Some(1) } else {
+ | ^
+ |
+help: try wrapping the expression in parentheses
+ |
+LL | let Some(1) = ({ Some(1) }) else {
+ | + +
+
+error: right curly brace `}` before `else` in a `let...else` statement not allowed
+ --> $DIR/let-else-brace-before-else.rs:10:40
+ |
+LL | let Some(1) = loop { break Some(1) } else {
+ | ^
+ |
+help: try wrapping the expression in parentheses
+ |
+LL | let Some(1) = (loop { break Some(1) }) else {
+ | + +
+
+error: right curly brace `}` before `else` in a `let...else` statement not allowed
+ --> $DIR/let-else-brace-before-else.rs:14:34
+ |
+LL | let 2 = 1 + match 1 { n => n } else {
+ | ^
+ |
+help: try wrapping the expression in parentheses
+ |
+LL | let 2 = 1 + (match 1 { n => n }) else {
+ | + +
+
+error: right curly brace `}` before `else` in a `let...else` statement not allowed
+ --> $DIR/let-else-brace-before-else.rs:18:40
+ |
+LL | let Some(1) = unsafe { unsafe_fn() } else {
+ | ^
+ |
+help: try wrapping the expression in parentheses
+ |
+LL | let Some(1) = (unsafe { unsafe_fn() }) else {
+ | + +
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/let-else/let-else-check.rs b/src/test/ui/let-else/let-else-check.rs
new file mode 100644
index 000000000..9e32cbef7
--- /dev/null
+++ b/src/test/ui/let-else/let-else-check.rs
@@ -0,0 +1,19 @@
+#![feature(let_else)]
+
+#![deny(unused_variables)]
+
+fn main() {
+ // type annotation, attributes
+ #[allow(unused_variables)]
+ let Some(_): Option<u32> = Some(Default::default()) else {
+ let x = 1; // OK
+ return;
+ };
+
+ let Some(_): Option<u32> = Some(Default::default()) else {
+ let x = 1; //~ ERROR unused variable: `x`
+ return;
+ };
+
+ let x = 1; //~ ERROR unused variable: `x`
+}
diff --git a/src/test/ui/let-else/let-else-check.stderr b/src/test/ui/let-else/let-else-check.stderr
new file mode 100644
index 000000000..3d647a4c0
--- /dev/null
+++ b/src/test/ui/let-else/let-else-check.stderr
@@ -0,0 +1,20 @@
+error: unused variable: `x`
+ --> $DIR/let-else-check.rs:14:13
+ |
+LL | let x = 1;
+ | ^ help: if this is intentional, prefix it with an underscore: `_x`
+ |
+note: the lint level is defined here
+ --> $DIR/let-else-check.rs:3:9
+ |
+LL | #![deny(unused_variables)]
+ | ^^^^^^^^^^^^^^^^
+
+error: unused variable: `x`
+ --> $DIR/let-else-check.rs:18:9
+ |
+LL | let x = 1;
+ | ^ help: if this is intentional, prefix it with an underscore: `_x`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/let-else/let-else-deref-coercion-annotated.rs b/src/test/ui/let-else/let-else-deref-coercion-annotated.rs
new file mode 100644
index 000000000..65d88a6d8
--- /dev/null
+++ b/src/test/ui/let-else/let-else-deref-coercion-annotated.rs
@@ -0,0 +1,77 @@
+// check-pass
+//
+// Taken from https://github.com/rust-lang/rust/blob/6cc0a764e082d9c0abcf37a768d5889247ba13e2/compiler/rustc_typeck/src/check/_match.rs#L445-L462
+//
+// We attempt to `let Bar::Present(_): &mut Bar = foo else { ... }` where foo is meant to
+// Deref/DerefMut to Bar. You can do this with an irrefutable binding, so it should work with
+// let-else too.
+
+#![feature(let_else)]
+use std::ops::{Deref, DerefMut};
+
+struct Foo(Bar);
+
+enum Bar {
+ Present(u32),
+ Absent,
+}
+impl Deref for Foo {
+ type Target = Bar;
+ fn deref(&self) -> &Bar {
+ &self.0
+ }
+}
+impl DerefMut for Foo {
+ fn deref_mut(&mut self) -> &mut Bar {
+ &mut self.0
+ }
+}
+impl Bar {
+ fn bar(&self) -> Option<u32> {
+ let Bar::Present(z): &Bar = self else {
+ return None;
+ };
+ return Some(*z);
+ }
+}
+impl Foo {
+ fn set_bar_annotated(&mut self, value: u32) {
+ let Bar::Present(z): &mut Bar = self else { // OK
+ return;
+ };
+ *z = value;
+ }
+}
+
+fn main() {
+ let mut foo = Foo(Bar::Present(1));
+ foo.set_bar_annotated(42);
+ assert_eq!(foo.bar(), Some(42));
+ irrefutable::inner();
+}
+
+// The original, to show it works for irrefutable let decls
+mod irrefutable {
+ use std::ops::{Deref, DerefMut};
+ struct Foo(Bar);
+ struct Bar(u32);
+ impl Deref for Foo {
+ type Target = Bar;
+ fn deref(&self) -> &Bar {
+ &self.0
+ }
+ }
+ impl DerefMut for Foo {
+ fn deref_mut(&mut self) -> &mut Bar {
+ &mut self.0
+ }
+ }
+ fn foo(x: &mut Foo) {
+ let Bar(z): &mut Bar = x; // OK
+ *z = 42;
+ assert_eq!((x.0).0, 42);
+ }
+ pub fn inner() {
+ foo(&mut Foo(Bar(1)));
+ }
+}
diff --git a/src/test/ui/let-else/let-else-deref-coercion.rs b/src/test/ui/let-else/let-else-deref-coercion.rs
new file mode 100644
index 000000000..87489d84b
--- /dev/null
+++ b/src/test/ui/let-else/let-else-deref-coercion.rs
@@ -0,0 +1,75 @@
+// Taken from https://github.com/rust-lang/rust/blob/6cc0a764e082d9c0abcf37a768d5889247ba13e2/compiler/rustc_typeck/src/check/_match.rs#L445-L462
+//
+// We attempt to `let Bar::Present(_) = foo else { ... }` where foo is meant to Deref/DerefMut to
+// Bar. This fails, you must add a type annotation like `let _: &mut Bar = _ else { ... }`
+
+#![feature(let_else)]
+use std::ops::{Deref, DerefMut};
+
+struct Foo(Bar);
+
+enum Bar {
+ Present(u32),
+ Absent,
+}
+impl Deref for Foo {
+ type Target = Bar;
+ fn deref(&self) -> &Bar {
+ &self.0
+ }
+}
+impl DerefMut for Foo {
+ fn deref_mut(&mut self) -> &mut Bar {
+ &mut self.0
+ }
+}
+impl Bar {
+ fn bar(&self) -> Option<u32> {
+ let Bar::Present(z): &Bar = self else {
+ return None;
+ };
+ return Some(*z);
+ }
+}
+impl Foo {
+ // Try without the type annotation
+ fn set_bar_unannotated(&mut self, value: u32) {
+ let Bar::Present(z) = self else { //~ ERROR mismatched types
+ return;
+ };
+ *z = value;
+ }
+}
+
+fn main() {
+ let mut foo = Foo(Bar::Present(1));
+ foo.set_bar_unannotated(54);
+ assert_eq!(foo.bar(), Some(54));
+ irrefutable::inner();
+}
+
+// The original, to show it fails for irrefutable let decls
+mod irrefutable {
+ use std::ops::{Deref, DerefMut};
+ struct Foo(Bar);
+ struct Bar(u32);
+ impl Deref for Foo {
+ type Target = Bar;
+ fn deref(&self) -> &Bar {
+ &self.0
+ }
+ }
+ impl DerefMut for Foo {
+ fn deref_mut(&mut self) -> &mut Bar {
+ &mut self.0
+ }
+ }
+ fn foo(x: &mut Foo) {
+ let Bar(z) = x; //~ ERROR mismatched types
+ *z = 54;
+ assert_eq!((x.0).0, 54);
+ }
+ pub fn inner() {
+ foo(&mut Foo(Bar(1)));
+ }
+}
diff --git a/src/test/ui/let-else/let-else-deref-coercion.stderr b/src/test/ui/let-else/let-else-deref-coercion.stderr
new file mode 100644
index 000000000..addcd798f
--- /dev/null
+++ b/src/test/ui/let-else/let-else-deref-coercion.stderr
@@ -0,0 +1,19 @@
+error[E0308]: mismatched types
+ --> $DIR/let-else-deref-coercion.rs:37:13
+ |
+LL | let Bar::Present(z) = self else {
+ | ^^^^^^^^^^^^^^^ ---- this expression has type `&mut Foo`
+ | |
+ | expected struct `Foo`, found enum `Bar`
+
+error[E0308]: mismatched types
+ --> $DIR/let-else-deref-coercion.rs:68:13
+ |
+LL | let Bar(z) = x;
+ | ^^^^^^ - this expression has type `&mut irrefutable::Foo`
+ | |
+ | expected struct `irrefutable::Foo`, found struct `irrefutable::Bar`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/let-else/let-else-destructuring.rs b/src/test/ui/let-else/let-else-destructuring.rs
new file mode 100644
index 000000000..9a09c414a
--- /dev/null
+++ b/src/test/ui/let-else/let-else-destructuring.rs
@@ -0,0 +1,18 @@
+#![feature(let_else)]
+#[derive(Debug)]
+enum Foo {
+ Done,
+ Nested(Option<&'static Foo>),
+}
+
+fn walk(mut value: &Foo) {
+ loop {
+ println!("{:?}", value);
+ &Foo::Nested(Some(value)) = value else { break }; //~ ERROR invalid left-hand side of assignment
+ //~^ERROR <assignment> ... else { ... } is not allowed
+ }
+}
+
+fn main() {
+ walk(&Foo::Done);
+}
diff --git a/src/test/ui/let-else/let-else-destructuring.stderr b/src/test/ui/let-else/let-else-destructuring.stderr
new file mode 100644
index 000000000..95efb7116
--- /dev/null
+++ b/src/test/ui/let-else/let-else-destructuring.stderr
@@ -0,0 +1,17 @@
+error: <assignment> ... else { ... } is not allowed
+ --> $DIR/let-else-destructuring.rs:11:9
+ |
+LL | &Foo::Nested(Some(value)) = value else { break };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0070]: invalid left-hand side of assignment
+ --> $DIR/let-else-destructuring.rs:11:35
+ |
+LL | &Foo::Nested(Some(value)) = value else { break };
+ | ------------------------- ^
+ | |
+ | cannot assign to this expression
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0070`.
diff --git a/src/test/ui/let-else/let-else-if.rs b/src/test/ui/let-else/let-else-if.rs
new file mode 100644
index 000000000..c3a17330d
--- /dev/null
+++ b/src/test/ui/let-else/let-else-if.rs
@@ -0,0 +1,10 @@
+#![feature(let_else)]
+
+fn main() {
+ let Some(_) = Some(()) else if true {
+ //~^ ERROR conditional `else if` is not supported for `let...else`
+ return;
+ } else {
+ return;
+ };
+}
diff --git a/src/test/ui/let-else/let-else-if.stderr b/src/test/ui/let-else/let-else-if.stderr
new file mode 100644
index 000000000..746738bbd
--- /dev/null
+++ b/src/test/ui/let-else/let-else-if.stderr
@@ -0,0 +1,17 @@
+error: conditional `else if` is not supported for `let...else`
+ --> $DIR/let-else-if.rs:4:33
+ |
+LL | let Some(_) = Some(()) else if true {
+ | ^^ expected `{`
+ |
+help: try placing this code inside a block
+ |
+LL ~ let Some(_) = Some(()) else { if true {
+LL |
+ ...
+LL | return;
+LL ~ } };
+ |
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/let-else/let-else-irrefutable.rs b/src/test/ui/let-else/let-else-irrefutable.rs
new file mode 100644
index 000000000..b1e09a124
--- /dev/null
+++ b/src/test/ui/let-else/let-else-irrefutable.rs
@@ -0,0 +1,7 @@
+// check-pass
+
+#![feature(let_else)]
+
+fn main() {
+ let x = 1 else { return }; //~ WARN irrefutable `let...else` pattern
+}
diff --git a/src/test/ui/let-else/let-else-irrefutable.stderr b/src/test/ui/let-else/let-else-irrefutable.stderr
new file mode 100644
index 000000000..e030c50d4
--- /dev/null
+++ b/src/test/ui/let-else/let-else-irrefutable.stderr
@@ -0,0 +1,12 @@
+warning: irrefutable `let...else` pattern
+ --> $DIR/let-else-irrefutable.rs:6:5
+ |
+LL | let x = 1 else { return };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(irrefutable_let_patterns)]` on by default
+ = note: this pattern will always match, so the `else` clause is useless
+ = help: consider removing the `else` clause
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/let-else/let-else-missing-semicolon.rs b/src/test/ui/let-else/let-else-missing-semicolon.rs
new file mode 100644
index 000000000..ed9d79f1e
--- /dev/null
+++ b/src/test/ui/let-else/let-else-missing-semicolon.rs
@@ -0,0 +1,11 @@
+#![feature(let_else)]
+
+fn main() {
+ let Some(x) = Some(1) else {
+ return;
+ } //~ ERROR expected `;`, found keyword `let`
+ let _ = "";
+ let Some(x) = Some(1) else {
+ panic!();
+ } //~ ERROR expected `;`, found `}`
+}
diff --git a/src/test/ui/let-else/let-else-missing-semicolon.stderr b/src/test/ui/let-else/let-else-missing-semicolon.stderr
new file mode 100644
index 000000000..1818a0b12
--- /dev/null
+++ b/src/test/ui/let-else/let-else-missing-semicolon.stderr
@@ -0,0 +1,18 @@
+error: expected `;`, found keyword `let`
+ --> $DIR/let-else-missing-semicolon.rs:6:6
+ |
+LL | }
+ | ^ help: add `;` here
+LL | let _ = "";
+ | --- unexpected token
+
+error: expected `;`, found `}`
+ --> $DIR/let-else-missing-semicolon.rs:10:6
+ |
+LL | }
+ | ^ help: add `;` here
+LL | }
+ | - unexpected token
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/let-else/let-else-no-double-error.rs b/src/test/ui/let-else/let-else-no-double-error.rs
new file mode 100644
index 000000000..35dcdd3f6
--- /dev/null
+++ b/src/test/ui/let-else/let-else-no-double-error.rs
@@ -0,0 +1,12 @@
+// from rfc2005 test suite
+
+#![feature(let_else)]
+
+// Without caching type lookups in FnCtxt.resolve_ty_and_def_ufcs
+// the error below would be reported twice (once when checking
+// for a non-ref pattern, once when processing the pattern).
+
+fn main() {
+ let foo = 22;
+ let u32::XXX = foo else { return }; //~ ERROR: no associated item named `XXX` found for type `u32` in the current scope [E0599]
+}
diff --git a/src/test/ui/let-else/let-else-no-double-error.stderr b/src/test/ui/let-else/let-else-no-double-error.stderr
new file mode 100644
index 000000000..941e588b1
--- /dev/null
+++ b/src/test/ui/let-else/let-else-no-double-error.stderr
@@ -0,0 +1,9 @@
+error[E0599]: no associated item named `XXX` found for type `u32` in the current scope
+ --> $DIR/let-else-no-double-error.rs:11:14
+ |
+LL | let u32::XXX = foo else { return };
+ | ^^^ associated item not found in `u32`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/let-else/let-else-non-copy.rs b/src/test/ui/let-else/let-else-non-copy.rs
new file mode 100644
index 000000000..79ed82dd1
--- /dev/null
+++ b/src/test/ui/let-else/let-else-non-copy.rs
@@ -0,0 +1,45 @@
+// run-pass
+//
+// This is derived from a change to compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs, in
+// preparation for adopting let-else within the compiler (thanks @est31):
+//
+// ```
+// - let place = if let mir::VarDebugInfoContents::Place(p) = var.value { p } else { continue };
+// + let mir::VarDebugInfoContents::Place(place) = var.value else { continue };
+// ```
+//
+// The move was due to mir::Place being Copy, but mir::VarDebugInfoContents not being Copy.
+
+#![feature(let_else)]
+
+#[derive(Copy, Clone)]
+struct Copyable;
+
+enum NonCopy {
+ Thing(Copyable),
+ #[allow(unused)]
+ Other,
+}
+
+struct Wrapper {
+ field: NonCopy,
+}
+
+fn let_else() {
+ let vec = vec![Wrapper { field: NonCopy::Thing(Copyable) }];
+ for item in &vec {
+ let NonCopy::Thing(_copyable) = item.field else { continue };
+ }
+}
+
+fn if_let() {
+ let vec = vec![Wrapper { field: NonCopy::Thing(Copyable) }];
+ for item in &vec {
+ let _copyable = if let NonCopy::Thing(copyable) = item.field { copyable } else { continue };
+ }
+}
+
+fn main() {
+ let_else();
+ if_let();
+}
diff --git a/src/test/ui/let-else/let-else-non-diverging.rs b/src/test/ui/let-else/let-else-non-diverging.rs
new file mode 100644
index 000000000..a1cee335a
--- /dev/null
+++ b/src/test/ui/let-else/let-else-non-diverging.rs
@@ -0,0 +1,13 @@
+#![feature(let_else)]
+
+fn main() {
+ let Some(x) = Some(1) else { //~ ERROR does not diverge
+ Some(2)
+ };
+ let Some(x) = Some(1) else { //~ ERROR does not diverge
+ if 1 == 1 {
+ panic!();
+ }
+ };
+ let Some(x) = Some(1) else { Some(2) }; //~ ERROR does not diverge
+}
diff --git a/src/test/ui/let-else/let-else-non-diverging.stderr b/src/test/ui/let-else/let-else-non-diverging.stderr
new file mode 100644
index 000000000..05e45f689
--- /dev/null
+++ b/src/test/ui/let-else/let-else-non-diverging.stderr
@@ -0,0 +1,44 @@
+error[E0308]: `else` clause of `let...else` does not diverge
+ --> $DIR/let-else-non-diverging.rs:4:32
+ |
+LL | let Some(x) = Some(1) else {
+ | ________________________________^
+LL | | Some(2)
+LL | | };
+ | |_____^ expected `!`, found enum `Option`
+ |
+ = note: expected type `!`
+ found enum `Option<{integer}>`
+ = help: try adding a diverging expression, such as `return` or `panic!(..)`
+ = help: ...or use `match` instead of `let...else`
+
+error[E0308]: `else` clause of `let...else` does not diverge
+ --> $DIR/let-else-non-diverging.rs:7:32
+ |
+LL | let Some(x) = Some(1) else {
+ | ________________________________^
+LL | | if 1 == 1 {
+LL | | panic!();
+LL | | }
+LL | | };
+ | |_____^ expected `!`, found `()`
+ |
+ = note: expected type `!`
+ found unit type `()`
+ = help: try adding a diverging expression, such as `return` or `panic!(..)`
+ = help: ...or use `match` instead of `let...else`
+
+error[E0308]: `else` clause of `let...else` does not diverge
+ --> $DIR/let-else-non-diverging.rs:12:32
+ |
+LL | let Some(x) = Some(1) else { Some(2) };
+ | ^^^^^^^^^^^ expected `!`, found enum `Option`
+ |
+ = note: expected type `!`
+ found enum `Option<{integer}>`
+ = help: try adding a diverging expression, such as `return` or `panic!(..)`
+ = help: ...or use `match` instead of `let...else`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/let-else/let-else-ref-bindings-pass.rs b/src/test/ui/let-else/let-else-ref-bindings-pass.rs
new file mode 100644
index 000000000..f4abd6cc2
--- /dev/null
+++ b/src/test/ui/let-else/let-else-ref-bindings-pass.rs
@@ -0,0 +1,71 @@
+// check-pass
+
+#![feature(let_else)]
+#![allow(unused_variables)]
+
+fn ref_() {
+ let bytes: Vec<u8> = b"Hello"[..].to_vec();
+ let some = Some(bytes);
+
+ let Some(ref a) = Some(()) else { return };
+
+ // | ref | type annotation | & |
+ // | --- | --------------- | - |
+ // | x | x | | error
+ // | x | x | x | error
+ // | | x | | error
+ // | | x | x | error
+ // | x | | |
+ let Some(ref a) = some else { return }; // OK
+ let b: &[u8] = a;
+
+ // | x | | x |
+ let Some(ref a) = &some else { return }; // OK
+ let b: &[u8] = a;
+
+
+ // | | | x |
+ let Some(a) = &some else { return }; // OK
+ let b: &[u8] = a;
+
+ let Some(a): Option<&[u8]> = some.as_deref() else { return }; // OK
+ let b: &[u8] = a;
+ let Some(ref a): Option<&[u8]> = some.as_deref() else { return }; // OK
+ let b: &[u8] = a;
+}
+
+fn ref_mut() {
+ // This `ref mut` case had an ICE, see issue #89960
+ let Some(ref mut a) = Some(()) else { return };
+
+ let bytes: Vec<u8> = b"Hello"[..].to_vec();
+ let mut some = Some(bytes);
+
+ // | ref mut | type annotation | &mut |
+ // | ------- | --------------- | ---- |
+ // | x | x | | error
+ // | x | x | x | error
+ // | | x | | error
+ // | | x | x | error
+ // | x | | |
+ let Some(ref mut a) = some else { return }; // OK
+ let b: &mut [u8] = a;
+
+ // | x | | x |
+ let Some(ref mut a) = &mut some else { return }; // OK
+ let b: &mut [u8] = a;
+
+ // | | | x |
+ let Some(a) = &mut some else { return }; // OK
+ let b: &mut [u8] = a;
+
+ let Some(a): Option<&mut [u8]> = some.as_deref_mut() else { return }; // OK
+ let b: &mut [u8] = a;
+ let Some(ref mut a): Option<&mut [u8]> = some.as_deref_mut() else { return }; // OK
+ let b: &mut [u8] = a;
+}
+
+fn main() {
+ ref_();
+ ref_mut();
+}
diff --git a/src/test/ui/let-else/let-else-ref-bindings.rs b/src/test/ui/let-else/let-else-ref-bindings.rs
new file mode 100644
index 000000000..a4cd8e8c4
--- /dev/null
+++ b/src/test/ui/let-else/let-else-ref-bindings.rs
@@ -0,0 +1,62 @@
+#![feature(let_else)]
+#![allow(unused_variables)]
+
+fn ref_() {
+ let bytes: Vec<u8> = b"Hello"[..].to_vec();
+ let some = Some(bytes);
+
+ let Some(ref a) = Some(()) else { return };
+
+ // | ref | type annotation | & |
+ // | --- | --------------- | - |
+ // | x | | | OK
+ // | x | | x | OK
+ // | | | x | OK
+ // | x | x | |
+ let Some(ref a): Option<&[u8]> = some else { return }; //~ ERROR mismatched types
+ let b: & [u8] = a;
+
+ // | x | x | x |
+ let Some(ref a): Option<&[u8]> = &some else { return }; //~ ERROR mismatched types
+ let b: & [u8] = a;
+
+ // | | x | |
+ let Some(a): Option<&[u8]> = some else { return }; //~ ERROR mismatched types
+ let b: &[u8] = a;
+ // | | x | x |
+ let Some(a): Option<&[u8]> = &some else { return }; //~ ERROR mismatched types
+ let b: &[u8] = a;
+}
+
+fn ref_mut() {
+ // This `ref mut` case had an ICE, see issue #89960
+ let Some(ref mut a) = Some(()) else { return };
+
+ let bytes: Vec<u8> = b"Hello"[..].to_vec();
+ let mut some = Some(bytes);
+
+ // | ref mut | type annotation | &mut |
+ // | ------- | --------------- | ---- |
+ // | x | | | OK
+ // | x | | x | OK
+ // | | | x | OK
+ // | x | x | |
+ let Some(ref mut a): Option<&mut [u8]> = some else { return }; //~ ERROR mismatched types
+ let b: &mut [u8] = a;
+
+ // | x | x | x | (nope)
+ let Some(ref mut a): Option<&mut [u8]> = &mut some else { return }; //~ ERROR mismatched types
+ let b: &mut [u8] = a;
+
+ // | | x | |
+ let Some(a): Option<&mut [u8]> = some else { return }; //~ ERROR mismatched types
+ let b: &mut [u8] = a;
+ // | | x | x |
+ let Some(a): Option<&mut [u8]> = &mut some else { return }; //~ ERROR mismatched types
+ let b: &mut [u8] = a;
+}
+
+fn main() {
+ ref_();
+ ref_mut();
+}
diff --git a/src/test/ui/let-else/let-else-ref-bindings.stderr b/src/test/ui/let-else/let-else-ref-bindings.stderr
new file mode 100644
index 000000000..56b9e0733
--- /dev/null
+++ b/src/test/ui/let-else/let-else-ref-bindings.stderr
@@ -0,0 +1,83 @@
+error[E0308]: mismatched types
+ --> $DIR/let-else-ref-bindings.rs:16:38
+ |
+LL | let Some(ref a): Option<&[u8]> = some else { return };
+ | ^^^^ expected `&[u8]`, found struct `Vec`
+ |
+ = note: expected enum `Option<&[u8]>`
+ found enum `Option<Vec<u8>>`
+
+error[E0308]: mismatched types
+ --> $DIR/let-else-ref-bindings.rs:20:38
+ |
+LL | let Some(ref a): Option<&[u8]> = &some else { return };
+ | ^^^^^ expected enum `Option`, found `&Option<Vec<u8>>`
+ |
+ = note: expected enum `Option<&[u8]>`
+ found reference `&Option<Vec<u8>>`
+
+error[E0308]: mismatched types
+ --> $DIR/let-else-ref-bindings.rs:24:34
+ |
+LL | let Some(a): Option<&[u8]> = some else { return };
+ | ------------- ^^^^ expected `&[u8]`, found struct `Vec`
+ | |
+ | expected due to this
+ |
+ = note: expected enum `Option<&[u8]>`
+ found enum `Option<Vec<u8>>`
+
+error[E0308]: mismatched types
+ --> $DIR/let-else-ref-bindings.rs:27:34
+ |
+LL | let Some(a): Option<&[u8]> = &some else { return };
+ | ------------- ^^^^^ expected enum `Option`, found `&Option<Vec<u8>>`
+ | |
+ | expected due to this
+ |
+ = note: expected enum `Option<&[u8]>`
+ found reference `&Option<Vec<u8>>`
+
+error[E0308]: mismatched types
+ --> $DIR/let-else-ref-bindings.rs:44:46
+ |
+LL | let Some(ref mut a): Option<&mut [u8]> = some else { return };
+ | ^^^^ expected `&mut [u8]`, found struct `Vec`
+ |
+ = note: expected enum `Option<&mut [u8]>`
+ found enum `Option<Vec<u8>>`
+
+error[E0308]: mismatched types
+ --> $DIR/let-else-ref-bindings.rs:48:46
+ |
+LL | let Some(ref mut a): Option<&mut [u8]> = &mut some else { return };
+ | ^^^^^^^^^ expected enum `Option`, found mutable reference
+ |
+ = note: expected enum `Option<&mut [u8]>`
+ found mutable reference `&mut Option<Vec<u8>>`
+
+error[E0308]: mismatched types
+ --> $DIR/let-else-ref-bindings.rs:52:38
+ |
+LL | let Some(a): Option<&mut [u8]> = some else { return };
+ | ----------------- ^^^^ expected `&mut [u8]`, found struct `Vec`
+ | |
+ | expected due to this
+ |
+ = note: expected enum `Option<&mut [u8]>`
+ found enum `Option<Vec<u8>>`
+
+error[E0308]: mismatched types
+ --> $DIR/let-else-ref-bindings.rs:55:38
+ |
+LL | let Some(a): Option<&mut [u8]> = &mut some else { return };
+ | ----------------- ^^^^^^^^^ expected enum `Option`, found mutable reference
+ | |
+ | expected due to this
+ |
+ = note: expected enum `Option<&mut [u8]>`
+ found mutable reference `&mut Option<Vec<u8>>`
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/let-else/let-else-run-pass.rs b/src/test/ui/let-else/let-else-run-pass.rs
new file mode 100644
index 000000000..5d9662323
--- /dev/null
+++ b/src/test/ui/let-else/let-else-run-pass.rs
@@ -0,0 +1,35 @@
+// run-pass
+
+#![feature(let_else)]
+
+fn main() {
+ #[allow(dead_code)]
+ enum MyEnum {
+ A(String),
+ B { f: String },
+ C,
+ }
+ // ref binding to non-copy value and or-pattern
+ let (MyEnum::A(ref x) | MyEnum::B { f: ref x }) = (MyEnum::B { f: String::new() }) else {
+ panic!();
+ };
+ assert_eq!(x, "");
+
+ // nested let-else
+ let mut x = 1;
+ loop {
+ let 4 = x else {
+ let 3 = x else {
+ x += 1;
+ continue;
+ };
+ break;
+ };
+ panic!();
+ }
+ assert_eq!(x, 3);
+
+ // else return
+ let Some(1) = Some(2) else { return };
+ panic!();
+}
diff --git a/src/test/ui/let-else/let-else-scope.rs b/src/test/ui/let-else/let-else-scope.rs
new file mode 100644
index 000000000..f17682db4
--- /dev/null
+++ b/src/test/ui/let-else/let-else-scope.rs
@@ -0,0 +1,7 @@
+#![feature(let_else)]
+
+fn main() {
+ let Some(x) = Some(2) else {
+ panic!("{}", x); //~ ERROR cannot find value `x` in this scope
+ };
+}
diff --git a/src/test/ui/let-else/let-else-scope.stderr b/src/test/ui/let-else/let-else-scope.stderr
new file mode 100644
index 000000000..4b3936eac
--- /dev/null
+++ b/src/test/ui/let-else/let-else-scope.stderr
@@ -0,0 +1,9 @@
+error[E0425]: cannot find value `x` in this scope
+ --> $DIR/let-else-scope.rs:5:22
+ |
+LL | panic!("{}", x);
+ | ^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/let-else/let-else-slicing-error.rs b/src/test/ui/let-else/let-else-slicing-error.rs
new file mode 100644
index 000000000..4022656a8
--- /dev/null
+++ b/src/test/ui/let-else/let-else-slicing-error.rs
@@ -0,0 +1,9 @@
+// issue #92069
+#![feature(let_else)]
+
+fn main() {
+ let nums = vec![5, 4, 3, 2, 1];
+ let [x, y] = nums else { //~ ERROR expected an array or slice
+ return;
+ };
+}
diff --git a/src/test/ui/let-else/let-else-slicing-error.stderr b/src/test/ui/let-else/let-else-slicing-error.stderr
new file mode 100644
index 000000000..064025e03
--- /dev/null
+++ b/src/test/ui/let-else/let-else-slicing-error.stderr
@@ -0,0 +1,11 @@
+error[E0529]: expected an array or slice, found `Vec<{integer}>`
+ --> $DIR/let-else-slicing-error.rs:6:9
+ |
+LL | let [x, y] = nums else {
+ | ^^^^^^ ---- help: consider slicing here: `nums[..]`
+ | |
+ | pattern cannot match with input type `Vec<{integer}>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0529`.
diff --git a/src/test/ui/let-else/let-else-source-expr-nomove-pass.rs b/src/test/ui/let-else/let-else-source-expr-nomove-pass.rs
new file mode 100644
index 000000000..2aa17ae8c
--- /dev/null
+++ b/src/test/ui/let-else/let-else-source-expr-nomove-pass.rs
@@ -0,0 +1,17 @@
+// run-pass
+// issue #89688
+
+#![feature(let_else)]
+
+fn example_let_else(value: Option<String>) {
+ let Some(inner) = value else {
+ println!("other: {:?}", value); // OK
+ return;
+ };
+ println!("inner: {}", inner);
+}
+
+fn main() {
+ example_let_else(Some("foo".into()));
+ example_let_else(None);
+}
diff --git a/src/test/ui/let-else/let-else-temp-borrowck.rs b/src/test/ui/let-else/let-else-temp-borrowck.rs
new file mode 100644
index 000000000..3910d35e7
--- /dev/null
+++ b/src/test/ui/let-else/let-else-temp-borrowck.rs
@@ -0,0 +1,26 @@
+// run-pass
+//
+// from issue #93951, where borrowck complained the temporary that `foo(&x)` was stored in was to
+// be dropped sometime after `x` was. It then suggested adding a semicolon that was already there.
+
+#![feature(let_else)]
+use std::fmt::Debug;
+
+fn foo<'a>(x: &'a str) -> Result<impl Debug + 'a, ()> {
+ Ok(x)
+}
+
+fn let_else() {
+ let x = String::from("Hey");
+ let Ok(_) = foo(&x) else { return };
+}
+
+fn if_let() {
+ let x = String::from("Hey");
+ let _ = if let Ok(s) = foo(&x) { s } else { return };
+}
+
+fn main() {
+ let_else();
+ if_let();
+}
diff --git a/src/test/ui/let-else/let-else-temporary-lifetime.rs b/src/test/ui/let-else/let-else-temporary-lifetime.rs
new file mode 100644
index 000000000..9c86901b9
--- /dev/null
+++ b/src/test/ui/let-else/let-else-temporary-lifetime.rs
@@ -0,0 +1,88 @@
+// run-pass
+#![feature(let_else)]
+
+use std::fmt::Display;
+use std::rc::Rc;
+use std::sync::atomic::{AtomicU8, Ordering};
+
+static TRACKER: AtomicU8 = AtomicU8::new(0);
+
+#[derive(Default)]
+struct Droppy {
+ inner: u32,
+}
+
+impl Drop for Droppy {
+ fn drop(&mut self) {
+ TRACKER.store(1, Ordering::Release);
+ println!("I've been dropped");
+ }
+}
+
+fn foo<'a>(x: &'a str) -> Result<impl Display + 'a, ()> {
+ Ok(x)
+}
+
+fn main() {
+ assert_eq!(TRACKER.load(Ordering::Acquire), 0);
+ let 0 = Droppy::default().inner else { return };
+ assert_eq!(TRACKER.load(Ordering::Acquire), 1);
+ println!("Should have dropped 👆");
+
+ {
+ // cf. https://github.com/rust-lang/rust/pull/99518#issuecomment-1191520030
+ struct Foo<'a>(&'a mut u32);
+
+ impl<'a> Drop for Foo<'a> {
+ fn drop(&mut self) {
+ *self.0 = 0;
+ }
+ }
+ let mut foo = 0;
+ let Foo(0) = Foo(&mut foo) else {
+ *&mut foo = 1;
+ todo!()
+ };
+ }
+ {
+ let x = String::from("Hey");
+
+ let Ok(s) = foo(&x) else { panic!() };
+ assert_eq!(s.to_string(), x);
+ }
+ {
+ // test let-else drops temps after statement
+ let rc = Rc::new(0);
+ let 0 = *rc.clone() else { unreachable!() };
+ Rc::try_unwrap(rc).unwrap();
+ }
+ {
+ let mut rc = Rc::new(0);
+ let mut i = 0;
+ loop {
+ if i > 3 {
+ break;
+ }
+ let 1 = *rc.clone() else {
+ if let Ok(v) = Rc::try_unwrap(rc) {
+ rc = Rc::new(v);
+ } else {
+ panic!()
+ }
+ i += 1;
+ continue
+ };
+ }
+ }
+ {
+ // test let-else drops temps before else block
+ // NOTE: this test has to be the last block in the `main`
+ // body.
+ let rc = Rc::new(0);
+ let 1 = *rc.clone() else {
+ Rc::try_unwrap(rc).unwrap();
+ return;
+ };
+ unreachable!();
+ }
+}