Skip to content

Commit 3aaf568

Browse files
committed
Split let-else-deref-coercion
1 parent 04ec330 commit 3aaf568

File tree

3 files changed

+91
-29
lines changed

3 files changed

+91
-29
lines changed
Lines changed: 77 additions & 0 deletions
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+
}

src/test/ui/let-else/let-else-deref-coercion.rs

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Taken from https://github.com/rust-lang/rust/blob/6cc0a764e082d9c0abcf37a768d5889247ba13e2/compiler/rustc_typeck/src/check/_match.rs#L445-L462
22
//
3-
// We attempt to `let Bar::Present(_): &mut Bar = foo` where foo is meant to Deref/DerefMut to Bar.
4-
// You can do this with an irrefutable binding, so it should work with let-else too.
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 { ... }`
55

66
#![feature(let_else)]
77
use std::ops::{Deref, DerefMut};
@@ -32,12 +32,6 @@ impl Bar {
3232
}
3333
}
3434
impl Foo {
35-
fn set_bar(&mut self, value: u32) {
36-
let Bar::Present(z): &mut Bar = self else { // OK
37-
return;
38-
};
39-
*z = value;
40-
}
4135
// Try without the type annotation
4236
fn set_bar_unannotated(&mut self, value: u32) {
4337
let Bar::Present(z) = self else { //~ ERROR mismatched types
@@ -49,14 +43,12 @@ impl Foo {
4943

5044
fn main() {
5145
let mut foo = Foo(Bar::Present(1));
52-
foo.set_bar(42);
53-
assert_eq!(foo.bar(), Some(42));
5446
foo.set_bar_unannotated(54);
5547
assert_eq!(foo.bar(), Some(54));
5648
irrefutable::inner();
5749
}
5850

59-
// The original, to show it works for irrefutable let decls
51+
// The original, to show it fails for irrefutable let decls
6052
mod irrefutable {
6153
use std::ops::{Deref, DerefMut};
6254
struct Foo(Bar);
@@ -73,16 +65,9 @@ mod irrefutable {
7365
}
7466
}
7567
fn foo(x: &mut Foo) {
76-
{
77-
let Bar(z): &mut Bar = x; // OK
78-
*z = 42;
79-
}
80-
assert_eq!((x.0).0, 42);
81-
{
82-
let Bar(z) = x; //~ ERROR mismatched types
83-
*z = 42;
84-
}
85-
assert_eq!((x.0).0, 42);
68+
let Bar(z) = x; //~ ERROR mismatched types
69+
*z = 54;
70+
assert_eq!((x.0).0, 54);
8671
}
8772
pub fn inner() {
8873
foo(&mut Foo(Bar(1)));

src/test/ui/let-else/let-else-deref-coercion.stderr

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0308]: mismatched types
2-
--> $DIR/let-else-deref-coercion.rs:43:13
2+
--> $DIR/let-else-deref-coercion.rs:37:13
33
|
44
LL | let Bar::Present(z) = self else {
55
| ^^^^^^^^^^^^^^^ ---- this expression has type `&mut Foo`
@@ -12,17 +12,17 @@ LL | let Bar::Present(z) = self.0 else {
1212
| ~~~~~~
1313

1414
error[E0308]: mismatched types
15-
--> $DIR/let-else-deref-coercion.rs:82:17
15+
--> $DIR/let-else-deref-coercion.rs:68:13
1616
|
17-
LL | let Bar(z) = x;
18-
| ^^^^^^ - this expression has type `&mut irrefutable::Foo`
19-
| |
20-
| expected struct `irrefutable::Foo`, found struct `irrefutable::Bar`
17+
LL | let Bar(z) = x;
18+
| ^^^^^^ - this expression has type `&mut irrefutable::Foo`
19+
| |
20+
| expected struct `irrefutable::Foo`, found struct `irrefutable::Bar`
2121
|
2222
help: you might have meant to use field `0` whose type is `irrefutable::Bar`
2323
|
24-
LL | let Bar(z) = x.0;
25-
| ~~~
24+
LL | let Bar(z) = x.0;
25+
| ~~~
2626

2727
error: aborting due to 2 previous errors
2828

0 commit comments

Comments
 (0)