Skip to content

Commit

Permalink
let-else: add match-ergonomics tests adapted from rfc2005
Browse files Browse the repository at this point in the history
collect explicit-mut passing tests in one file
  • Loading branch information
cormacrelf committed Dec 13, 2021
1 parent 102b912 commit 2715c5f
Show file tree
Hide file tree
Showing 12 changed files with 228 additions and 0 deletions.
16 changes: 16 additions & 0 deletions src/test/ui/let-else/let-else-binding-explicit-mut-annotated.rs
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
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
|
= 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
|
= 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`.
13 changes: 13 additions & 0 deletions src/test/ui/let-else/let-else-binding-explicit-mut-borrow.rs
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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`.
13 changes: 13 additions & 0 deletions src/test/ui/let-else/let-else-binding-explicit-mut-pass.rs
Original file line number Diff line number Diff line change
@@ -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;
}
20 changes: 20 additions & 0 deletions src/test/ui/let-else/let-else-binding-explicit-mut.rs
Original file line number Diff line number Diff line change
@@ -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;
}
21 changes: 21 additions & 0 deletions src/test/ui/let-else/let-else-binding-explicit-mut.stderr
Original file line number Diff line number Diff line change
@@ -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`.
10 changes: 10 additions & 0 deletions src/test/ui/let-else/let-else-binding-immutable.rs
Original file line number Diff line number Diff line change
@@ -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
}
9 changes: 9 additions & 0 deletions src/test/ui/let-else/let-else-binding-immutable.stderr
Original file line number Diff line number Diff line change
@@ -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`.
75 changes: 75 additions & 0 deletions src/test/ui/let-else/let-else-bindings.rs
Original file line number Diff line number Diff line change
@@ -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);
}
12 changes: 12 additions & 0 deletions src/test/ui/let-else/let-else-no-double-error.rs
Original file line number Diff line number Diff line change
@@ -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]
}
9 changes: 9 additions & 0 deletions src/test/ui/let-else/let-else-no-double-error.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 2715c5f

Please sign in to comment.