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 0000000000000..b65fa13c1de1e --- /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 = &&Some(5i32) else { return }; //~ ERROR mismatched types + *n += 1; + let _ = n; + + let Some(n): &mut Option = &&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 0000000000000..fdec7e7f6a753 --- /dev/null +++ b/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/let-else-binding-explicit-mut-annotated.rs:9:37 + | +LL | let Some(n): &mut Option = &&Some(5i32) else { return }; + | ^^^^^^^^^^^^ types differ in mutability + | + = note: expected mutable reference `&mut Option` + found reference `&&Option` + +error[E0308]: mismatched types + --> $DIR/let-else-binding-explicit-mut-annotated.rs:13:37 + | +LL | let Some(n): &mut Option = &&mut Some(5i32) else { return }; + | ^^^^^^^^^^^^^^^^ types differ in mutability + | + = note: expected mutable reference `&mut Option` + found reference `&&mut Option` + +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 0000000000000..63b35df76aa04 --- /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 = &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 0000000000000..023fab8fe4a3d --- /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 = &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 0000000000000..305be92219214 --- /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 = &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 0000000000000..dbe4715b1a975 --- /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 0000000000000..45f2b6b3bcee8 --- /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 0000000000000..96de0ffe26e6b --- /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 0000000000000..dd1365a9ef078 --- /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 0000000000000..d5121e744dad3 --- /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-no-double-error.rs b/src/test/ui/let-else/let-else-no-double-error.rs new file mode 100644 index 0000000000000..35dcdd3f6be3c --- /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 0000000000000..941e588b1768d --- /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`.