Skip to content

Commit fec8a50

Browse files
committed
let-else: add deref-coercion tests
1 parent 2715c5f commit fec8a50

File tree

3 files changed

+171
-0
lines changed

3 files changed

+171
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// check-pass
2+
//
3+
// Taken from https://github.com/rust-lang/rust/blob/6cc0a764e082d9c0abcf37a768d5889247ba13e2/compiler/rustc_typeck/src/check/_match.rs#L445-L462
4+
//
5+
// We attempt to `let Bar::Present(_): &mut Bar = foo else { ... }` where foo is meant to
6+
// Deref/DerefMut to Bar. You can do this with an irrefutable binding, so it should work with
7+
// let-else too.
8+
9+
#![feature(let_else)]
10+
use std::ops::{Deref, DerefMut};
11+
12+
struct Foo(Bar);
13+
14+
enum Bar {
15+
Present(u32),
16+
Absent,
17+
}
18+
impl Deref for Foo {
19+
type Target = Bar;
20+
fn deref(&self) -> &Bar {
21+
&self.0
22+
}
23+
}
24+
impl DerefMut for Foo {
25+
fn deref_mut(&mut self) -> &mut Bar {
26+
&mut self.0
27+
}
28+
}
29+
impl Bar {
30+
fn bar(&self) -> Option<u32> {
31+
let Bar::Present(z): &Bar = self else {
32+
return None;
33+
};
34+
return Some(*z);
35+
}
36+
}
37+
impl Foo {
38+
fn set_bar_annotated(&mut self, value: u32) {
39+
let Bar::Present(z): &mut Bar = self else { // OK
40+
return;
41+
};
42+
*z = value;
43+
}
44+
}
45+
46+
fn main() {
47+
let mut foo = Foo(Bar::Present(1));
48+
foo.set_bar_annotated(42);
49+
assert_eq!(foo.bar(), Some(42));
50+
irrefutable::inner();
51+
}
52+
53+
// The original, to show it works for irrefutable let decls
54+
mod irrefutable {
55+
use std::ops::{Deref, DerefMut};
56+
struct Foo(Bar);
57+
struct Bar(u32);
58+
impl Deref for Foo {
59+
type Target = Bar;
60+
fn deref(&self) -> &Bar {
61+
&self.0
62+
}
63+
}
64+
impl DerefMut for Foo {
65+
fn deref_mut(&mut self) -> &mut Bar {
66+
&mut self.0
67+
}
68+
}
69+
fn foo(x: &mut Foo) {
70+
let Bar(z): &mut Bar = x; // OK
71+
*z = 42;
72+
assert_eq!((x.0).0, 42);
73+
}
74+
pub fn inner() {
75+
foo(&mut Foo(Bar(1)));
76+
}
77+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Taken from https://github.com/rust-lang/rust/blob/6cc0a764e082d9c0abcf37a768d5889247ba13e2/compiler/rustc_typeck/src/check/_match.rs#L445-L462
2+
//
3+
// We attempt to `let Bar::Present(_) = foo else { ... }` where foo is meant to Deref/DerefMut to
4+
// Bar. This fails, you must add a type annotation like `let _: &mut Bar = _ else { ... }`
5+
6+
#![feature(let_else)]
7+
use std::ops::{Deref, DerefMut};
8+
9+
struct Foo(Bar);
10+
11+
enum Bar {
12+
Present(u32),
13+
Absent,
14+
}
15+
impl Deref for Foo {
16+
type Target = Bar;
17+
fn deref(&self) -> &Bar {
18+
&self.0
19+
}
20+
}
21+
impl DerefMut for Foo {
22+
fn deref_mut(&mut self) -> &mut Bar {
23+
&mut self.0
24+
}
25+
}
26+
impl Bar {
27+
fn bar(&self) -> Option<u32> {
28+
let Bar::Present(z): &Bar = self else {
29+
return None;
30+
};
31+
return Some(*z);
32+
}
33+
}
34+
impl Foo {
35+
// Try without the type annotation
36+
fn set_bar_unannotated(&mut self, value: u32) {
37+
let Bar::Present(z) = self else { //~ ERROR mismatched types
38+
return;
39+
};
40+
*z = value;
41+
}
42+
}
43+
44+
fn main() {
45+
let mut foo = Foo(Bar::Present(1));
46+
foo.set_bar_unannotated(54);
47+
assert_eq!(foo.bar(), Some(54));
48+
irrefutable::inner();
49+
}
50+
51+
// The original, to show it fails for irrefutable let decls
52+
mod irrefutable {
53+
use std::ops::{Deref, DerefMut};
54+
struct Foo(Bar);
55+
struct Bar(u32);
56+
impl Deref for Foo {
57+
type Target = Bar;
58+
fn deref(&self) -> &Bar {
59+
&self.0
60+
}
61+
}
62+
impl DerefMut for Foo {
63+
fn deref_mut(&mut self) -> &mut Bar {
64+
&mut self.0
65+
}
66+
}
67+
fn foo(x: &mut Foo) {
68+
let Bar(z) = x; //~ ERROR mismatched types
69+
*z = 54;
70+
assert_eq!((x.0).0, 54);
71+
}
72+
pub fn inner() {
73+
foo(&mut Foo(Bar(1)));
74+
}
75+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/let-else-deref-coercion.rs:37:13
3+
|
4+
LL | let Bar::Present(z) = self else {
5+
| ^^^^^^^^^^^^^^^ ---- this expression has type `&mut Foo`
6+
| |
7+
| expected struct `Foo`, found enum `Bar`
8+
9+
error[E0308]: mismatched types
10+
--> $DIR/let-else-deref-coercion.rs:68:13
11+
|
12+
LL | let Bar(z) = x;
13+
| ^^^^^^ - this expression has type `&mut irrefutable::Foo`
14+
| |
15+
| expected struct `irrefutable::Foo`, found struct `irrefutable::Bar`
16+
17+
error: aborting due to 2 previous errors
18+
19+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)