Skip to content

Commit 03da505

Browse files
Implement feature gate for eat-one-layer on edition 2024
1 parent f37a4d5 commit 03da505

10 files changed

+474
-51
lines changed

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,8 @@ declare_features! (
339339
(incomplete, adt_const_params, "1.56.0", Some(95174)),
340340
/// Allows defining an `#[alloc_error_handler]`.
341341
(unstable, alloc_error_handler, "1.29.0", Some(51540)),
342+
/// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024.
343+
(incomplete, and_eat_one_layer_2024, "CURRENT_RUSTC_VERSION", Some(123076)),
342344
/// Allows `&` and `&mut` patterns to consume match-ergonomics-inserted references.
343345
(incomplete, and_pat_everywhere, "CURRENT_RUSTC_VERSION", Some(123076)),
344346
/// Allows trait methods with arbitrary self types.

compiler/rustc_hir_typeck/src/pat.rs

+71-51
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
292292
match adjust_mode {
293293
AdjustMode::Pass => (expected, def_bm, false),
294294
AdjustMode::Reset => (expected, INITIAL_BM, false),
295-
AdjustMode::RefReset(mutbl) => (expected, INITIAL_BM, def_bm.0 == ByRef::Yes(mutbl)),
295+
AdjustMode::RefReset(mutbl) => {
296+
let mutbls_match = def_bm.0 == ByRef::Yes(mutbl);
297+
if pat.span.at_least_rust_2024() && self.tcx.features().and_eat_one_layer_2024 {
298+
if mutbls_match {
299+
(expected, INITIAL_BM, true)
300+
} else {
301+
(expected, def_bm, false)
302+
}
303+
} else {
304+
(expected, INITIAL_BM, mutbls_match)
305+
}
306+
}
296307
AdjustMode::Peel => {
297308
let peeled = self.peel_off_references(pat, expected, def_bm);
298309
(peeled.0, peeled.1, false)
@@ -2060,61 +2071,70 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20602071
pat_info: PatInfo<'tcx, '_>,
20612072
already_consumed: bool,
20622073
) -> Ty<'tcx> {
2063-
let tcx = self.tcx;
2064-
let expected = self.shallow_resolve(expected);
2065-
let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
2066-
Ok(()) => {
2067-
// `demand::subtype` would be good enough, but using `eqtype` turns
2068-
// out to be equally general. See (note_1) for details.
2069-
2070-
// Take region, inner-type from expected type if we can,
2071-
// to avoid creating needless variables. This also helps with
2072-
// the bad interactions of the given hack detailed in (note_1).
2073-
debug!("check_pat_ref: expected={:?}", expected);
2074-
match *expected.kind() {
2075-
ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
2076-
_ => {
2077-
if already_consumed && self.tcx.features().and_pat_everywhere {
2078-
// We already matched against a match-ergonmics inserted reference,
2079-
// so we don't need to match against a reference from the original type.
2080-
// Save this infor for use in lowering later
2081-
self.typeck_results
2082-
.borrow_mut()
2083-
.ref_pats_that_dont_deref_mut()
2084-
.insert(pat.hir_id);
2085-
(expected, expected)
2086-
} else {
2087-
let inner_ty = self.next_ty_var(TypeVariableOrigin {
2088-
kind: TypeVariableOriginKind::TypeInference,
2089-
span: inner.span,
2090-
});
2091-
let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
2092-
debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
2093-
let err = self.demand_eqtype_pat_diag(
2094-
pat.span,
2095-
expected,
2096-
ref_ty,
2097-
pat_info.top_info,
2098-
);
2074+
if already_consumed
2075+
&& pat.span.at_least_rust_2024()
2076+
&& self.tcx.features().and_eat_one_layer_2024
2077+
{
2078+
self.typeck_results.borrow_mut().ref_pats_that_dont_deref_mut().insert(pat.hir_id);
2079+
self.check_pat(inner, expected, pat_info);
2080+
expected
2081+
} else {
2082+
let tcx = self.tcx;
2083+
let expected = self.shallow_resolve(expected);
2084+
let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
2085+
Ok(()) => {
2086+
// `demand::subtype` would be good enough, but using `eqtype` turns
2087+
// out to be equally general. See (note_1) for details.
2088+
2089+
// Take region, inner-type from expected type if we can,
2090+
// to avoid creating needless variables. This also helps with
2091+
// the bad interactions of the given hack detailed in (note_1).
2092+
debug!("check_pat_ref: expected={:?}", expected);
2093+
match *expected.kind() {
2094+
ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
2095+
_ => {
2096+
if already_consumed && self.tcx.features().and_pat_everywhere {
2097+
// We already matched against a match-ergonmics inserted reference,
2098+
// so we don't need to match against a reference from the original type.
2099+
// Save this infor for use in lowering later
2100+
self.typeck_results
2101+
.borrow_mut()
2102+
.ref_pats_that_dont_deref_mut()
2103+
.insert(pat.hir_id);
2104+
(expected, expected)
2105+
} else {
2106+
let inner_ty = self.next_ty_var(TypeVariableOrigin {
2107+
kind: TypeVariableOriginKind::TypeInference,
2108+
span: inner.span,
2109+
});
2110+
let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
2111+
debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
2112+
let err = self.demand_eqtype_pat_diag(
2113+
pat.span,
2114+
expected,
2115+
ref_ty,
2116+
pat_info.top_info,
2117+
);
20992118

2100-
// Look for a case like `fn foo(&foo: u32)` and suggest
2101-
// `fn foo(foo: &u32)`
2102-
if let Some(mut err) = err {
2103-
self.borrow_pat_suggestion(&mut err, pat);
2104-
err.emit();
2119+
// Look for a case like `fn foo(&foo: u32)` and suggest
2120+
// `fn foo(foo: &u32)`
2121+
if let Some(mut err) = err {
2122+
self.borrow_pat_suggestion(&mut err, pat);
2123+
err.emit();
2124+
}
2125+
(ref_ty, inner_ty)
21052126
}
2106-
(ref_ty, inner_ty)
21072127
}
21082128
}
21092129
}
2110-
}
2111-
Err(guar) => {
2112-
let err = Ty::new_error(tcx, guar);
2113-
(err, err)
2114-
}
2115-
};
2116-
self.check_pat(inner, inner_ty, pat_info);
2117-
ref_ty
2130+
Err(guar) => {
2131+
let err = Ty::new_error(tcx, guar);
2132+
(err, err)
2133+
}
2134+
};
2135+
self.check_pat(inner, inner_ty, pat_info);
2136+
ref_ty
2137+
}
21182138
}
21192139

21202140
/// Create a reference type with a fresh region variable.

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@ symbols! {
380380
alu32,
381381
always,
382382
and,
383+
and_eat_one_layer_2024,
383384
and_pat_everywhere,
384385
and_then,
385386
anon,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//@ edition: 2021
2+
#![allow(incomplete_features)]
3+
#![feature(and_eat_one_layer_2024)]
4+
pub fn main() {
5+
if let Some(Some(&x)) = &Some(&Some(0)) {
6+
//~^ ERROR: mismatched types
7+
let _: u32 = x;
8+
}
9+
if let Some(Some(&x)) = &Some(Some(&0)) {
10+
let _: &u32 = x;
11+
//~^ ERROR: mismatched types
12+
}
13+
if let Some(Some(&&x)) = &Some(Some(&0)) {
14+
//~^ ERROR: mismatched types
15+
let _: u32 = x;
16+
}
17+
if let Some(&Some(x)) = &Some(Some(0)) {
18+
//~^ ERROR: mismatched types
19+
let _: u32 = x;
20+
}
21+
if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
22+
//~^ ERROR: mismatched types
23+
let _: u32 = x;
24+
}
25+
if let Some(Some(&x)) = &Some(&Some(0)) {
26+
//~^ ERROR: mismatched types
27+
let _: u32 = x;
28+
}
29+
if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
30+
//~^ ERROR: mismatched types
31+
let _: u32 = x;
32+
}
33+
if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
34+
//~^ ERROR: mismatched types
35+
let _: u32 = x;
36+
}
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/and_eat_one_layer_2021.rs:5:22
3+
|
4+
LL | if let Some(Some(&x)) = &Some(&Some(0)) {
5+
| ^^ --------------- this expression has type `&Option<&Option<{integer}>>`
6+
| |
7+
| expected integer, found `&_`
8+
|
9+
= note: expected type `{integer}`
10+
found reference `&_`
11+
help: consider removing `&` from the pattern
12+
|
13+
LL | if let Some(Some(x)) = &Some(&Some(0)) {
14+
| ~
15+
16+
error[E0308]: mismatched types
17+
--> $DIR/and_eat_one_layer_2021.rs:10:23
18+
|
19+
LL | let _: &u32 = x;
20+
| ---- ^ expected `&u32`, found integer
21+
| |
22+
| expected due to this
23+
|
24+
help: consider borrowing here
25+
|
26+
LL | let _: &u32 = &x;
27+
| +
28+
29+
error[E0308]: mismatched types
30+
--> $DIR/and_eat_one_layer_2021.rs:13:23
31+
|
32+
LL | if let Some(Some(&&x)) = &Some(Some(&0)) {
33+
| ^^ --------------- this expression has type `&Option<Option<&{integer}>>`
34+
| |
35+
| expected integer, found `&_`
36+
|
37+
= note: expected type `{integer}`
38+
found reference `&_`
39+
help: consider removing `&` from the pattern
40+
|
41+
LL - if let Some(Some(&&x)) = &Some(Some(&0)) {
42+
LL + if let Some(Some(&x)) = &Some(Some(&0)) {
43+
|
44+
45+
error[E0308]: mismatched types
46+
--> $DIR/and_eat_one_layer_2021.rs:17:17
47+
|
48+
LL | if let Some(&Some(x)) = &Some(Some(0)) {
49+
| ^^^^^^^^ -------------- this expression has type `&Option<Option<{integer}>>`
50+
| |
51+
| expected `Option<{integer}>`, found `&_`
52+
|
53+
= note: expected enum `Option<{integer}>`
54+
found reference `&_`
55+
56+
error[E0308]: mismatched types
57+
--> $DIR/and_eat_one_layer_2021.rs:21:22
58+
|
59+
LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
60+
| ^^^^^^ ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>`
61+
| |
62+
| expected integer, found `&mut _`
63+
|
64+
= note: expected type `{integer}`
65+
found mutable reference `&mut _`
66+
note: to declare a mutable binding use: `mut x`
67+
--> $DIR/and_eat_one_layer_2021.rs:21:22
68+
|
69+
LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
70+
| ^^^^^^
71+
help: consider removing `&mut` from the pattern
72+
|
73+
LL | if let Some(Some(x)) = &mut Some(&mut Some(0)) {
74+
| ~
75+
76+
error[E0308]: mismatched types
77+
--> $DIR/and_eat_one_layer_2021.rs:25:22
78+
|
79+
LL | if let Some(Some(&x)) = &Some(&Some(0)) {
80+
| ^^ --------------- this expression has type `&Option<&Option<{integer}>>`
81+
| |
82+
| expected integer, found `&_`
83+
|
84+
= note: expected type `{integer}`
85+
found reference `&_`
86+
help: consider removing `&` from the pattern
87+
|
88+
LL | if let Some(Some(x)) = &Some(&Some(0)) {
89+
| ~
90+
91+
error[E0308]: mismatched types
92+
--> $DIR/and_eat_one_layer_2021.rs:29:27
93+
|
94+
LL | if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
95+
| ^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>`
96+
| |
97+
| expected integer, found `&_`
98+
|
99+
= note: expected type `{integer}`
100+
found reference `&_`
101+
help: consider removing `&` from the pattern
102+
|
103+
LL | if let Some(&mut Some(x)) = &Some(&mut Some(0)) {
104+
| ~
105+
106+
error[E0308]: mismatched types
107+
--> $DIR/and_eat_one_layer_2021.rs:33:23
108+
|
109+
LL | if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
110+
| ^^^^^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>`
111+
| |
112+
| expected integer, found `&mut _`
113+
|
114+
= note: expected type `{integer}`
115+
found mutable reference `&mut _`
116+
note: to declare a mutable binding use: `mut x`
117+
--> $DIR/and_eat_one_layer_2021.rs:33:23
118+
|
119+
LL | if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
120+
| ^^^^^^
121+
help: consider removing `&mut` from the pattern
122+
|
123+
LL | if let Some(&Some(x)) = &mut Some(&Some(0)) {
124+
| ~
125+
126+
error: aborting due to 8 previous errors
127+
128+
For more information about this error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//@ run-pass
2+
//@ edition: 2024
3+
//@ compile-flags: -Zunstable-options
4+
#![allow(incomplete_features)]
5+
#![feature(and_eat_one_layer_2024)]
6+
7+
pub fn main() {
8+
if let Some(Some(&x)) = &Some(&Some(0)) {
9+
let _: u32 = x;
10+
}
11+
if let Some(Some(&x)) = &Some(Some(&0)) {
12+
let _: &u32 = x;
13+
}
14+
if let Some(Some(&&x)) = &Some(Some(&0)) {
15+
let _: u32 = x;
16+
}
17+
if let Some(&Some(x)) = &Some(Some(0)) {
18+
let _: u32 = x;
19+
}
20+
if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
21+
let _: u32 = x;
22+
}
23+
if let Some(Some(&x)) = &Some(&Some(0)) {
24+
let _: u32 = x;
25+
}
26+
if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
27+
let _: u32 = x;
28+
}
29+
if let Some(&Some(&mut x)) = &mut Some(& Some(0)) {
30+
let _: u32 = x;
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//@ edition: 2024
2+
//@ compile-flags: -Zunstable-options
3+
#![allow(incomplete_features)]
4+
#![feature(and_eat_one_layer_2024)]
5+
6+
pub fn main() {
7+
if let Some(&mut Some(&_)) = &Some(&Some(0)) {
8+
//~^ ERROR: mismatched types
9+
}
10+
if let Some(&Some(&_)) = &Some(&mut Some(0)) {
11+
//~^ ERROR: mismatched types
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/and_eat_one_layer_2024_fail.rs:7:17
3+
|
4+
LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) {
5+
| ^^^^^^^^^^^^^ --------------- this expression has type `&Option<&Option<{integer}>>`
6+
| |
7+
| types differ in mutability
8+
|
9+
= note: expected reference `&Option<{integer}>`
10+
found mutable reference `&mut _`
11+
12+
error[E0308]: mismatched types
13+
--> $DIR/and_eat_one_layer_2024_fail.rs:10:23
14+
|
15+
LL | if let Some(&Some(&_)) = &Some(&mut Some(0)) {
16+
| ^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>`
17+
| |
18+
| expected integer, found `&_`
19+
|
20+
= note: expected type `{integer}`
21+
found reference `&_`
22+
23+
error: aborting due to 2 previous errors
24+
25+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)