Skip to content

Commit 9b0274e

Browse files
authored
Rollup merge of rust-lang#135434 - dianne:match-2024-for-edition-2024, r=Nadrieril
Match Ergonomics 2024: update edition 2024 behavior of feature gates This updates the edition 2024 behavior of the feature gates `ref_pat_eat_one_layer_2024_structural` and `ref_pat_eat_one_layer_2024` to correspond to the left and right typing rules compared [here](https://nadrieril.github.io/typing-rust-patterns/?compare=true&opts2=AQEBAAABAQABAgIAAQEBAAEBAAABAAA%3D&opts1=AQEBAgEBAQEBAgIAAAAAAAAAAAAAAAA%3D&mode=rules&do_cmp=true&ty_d=3&style=SequentBindingMode), respectively. I'll implement the proposed new behavior for editions ≤ 2021 in another PR. The tests are split up a bit awkwardly for practical reasons, but I've added new tests from 3 places: - I got tests for where the typing rules differ from the "Compare" tab of the page linked above. These had to be split up based on where the errors are emitted and how rustfixable they are, so they've ended up in different files to keep tidy. Within each file, though, the order of the tests matches the order the typing differences appear in that comparison (as of when this was written). - I used [this other comparison](https://nadrieril.github.io/typing-rust-patterns/?q=%5B%26mut+%26%28mut+x%29%5D%3A+%26mut+%5B%26CT%5D&compare=true&opts2=AQEBAgABAQEBAgIAAQEBAAEBAAABAAA%3D&opts1=AQEBAgEBAQEBAgIAAAAAAAAAAAAAAAA%3D&mode=compare&do_cmp=true&ty_d=3&style=SequentBindingMode) to test the `Deref(EatInner, FallbackToOuter)` rule of the left/"structural"/eat-inner ruleset. These are all in `well-typed-edition-2024.rs`. - I added some select tests for cases where the new typing rules differ from current stable Rust. I had to be pickier about what I included here, but I tried to make sure each typing rule got some coverage. That said, my approach for these tests was a bit ad-hoc, so I may have missed something. Relevant tracking issue: rust-lang#123076 r? ```@ghost```
2 parents 60b08ac + be7d6e3 commit 9b0274e

34 files changed

+1923
-336
lines changed

compiler/rustc_hir_typeck/src/pat.rs

+53-33
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
243243
fn downgrade_mut_inside_shared(&self) -> bool {
244244
// NB: RFC 3627 proposes stabilizing Rule 3 in all editions. If we adopt the same behavior
245245
// across all editions, this may be removed.
246-
self.tcx.features().ref_pat_eat_one_layer_2024()
247-
|| self.tcx.features().ref_pat_eat_one_layer_2024_structural()
246+
self.tcx.features().ref_pat_eat_one_layer_2024_structural()
248247
}
249248

250249
/// Experimental pattern feature: when do reference patterns match against inherited references?
@@ -435,7 +434,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
435434
max_ref_mutbl: MutblCap,
436435
) -> (Ty<'tcx>, ByRef, MutblCap) {
437436
#[cfg(debug_assertions)]
438-
if def_br == ByRef::Yes(Mutability::Mut) && max_ref_mutbl != MutblCap::Mut {
437+
if def_br == ByRef::Yes(Mutability::Mut)
438+
&& max_ref_mutbl != MutblCap::Mut
439+
&& self.downgrade_mut_inside_shared()
440+
{
439441
span_bug!(pat.span, "Pattern mutability cap violated!");
440442
}
441443
match adjust_mode {
@@ -2328,22 +2330,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23282330
// (RFC 3627, Rule 5). If we implement a pattern typing ruleset with Rule 4E
23292331
// but not Rule 5, we'll need to check that here.
23302332
debug_assert!(ref_pat_matches_mut_ref);
2331-
let err_msg = "mismatched types";
2332-
let err = if let Some(span) = pat_prefix_span {
2333-
let mut err = self.dcx().struct_span_err(span, err_msg);
2334-
err.code(E0308);
2335-
err.note("cannot match inherited `&` with `&mut` pattern");
2336-
err.span_suggestion_verbose(
2337-
span,
2338-
"replace this `&mut` pattern with `&`",
2339-
"&",
2340-
Applicability::MachineApplicable,
2341-
);
2342-
err
2343-
} else {
2344-
self.dcx().struct_span_err(pat.span, err_msg)
2345-
};
2346-
err.emit();
2333+
self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
23472334
}
23482335

23492336
pat_info.binding_mode = ByRef::No;
@@ -2352,28 +2339,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23522339
return expected;
23532340
}
23542341
InheritedRefMatchRule::EatInner => {
2355-
if let ty::Ref(_, _, r_mutbl) = *expected.kind() {
2342+
if let ty::Ref(_, _, r_mutbl) = *expected.kind()
2343+
&& pat_mutbl <= r_mutbl
2344+
{
23562345
// Match against the reference type; don't consume the inherited ref.
2357-
pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(r_mutbl);
2346+
// NB: The check for compatible pattern and ref type mutability assumes that
2347+
// `&` patterns can match against mutable references (RFC 3627, Rule 5). If
2348+
// we implement a pattern typing ruleset with Rule 4 (including the fallback
2349+
// to matching the inherited ref when the inner ref can't match) but not
2350+
// Rule 5, we'll need to check that here.
2351+
debug_assert!(ref_pat_matches_mut_ref);
2352+
// NB: For RFC 3627's Rule 3, we limit the default binding mode's ref
2353+
// mutability to `pat_info.max_ref_mutbl`. If we implement a pattern typing
2354+
// ruleset with Rule 4 but not Rule 3, we'll need to check that here.
2355+
debug_assert!(self.downgrade_mut_inside_shared());
2356+
let mutbl_cap = cmp::min(r_mutbl, pat_info.max_ref_mutbl.as_mutbl());
2357+
pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(mutbl_cap);
23582358
} else {
2359-
// The expected type isn't a reference, so match against the inherited ref.
2359+
// The reference pattern can't match against the expected type, so try
2360+
// matching against the inherited ref instead.
23602361
if pat_mutbl > inh_mut {
2361-
// We can't match an inherited shared reference with `&mut`. This will
2362-
// be a type error later, since we're matching a reference pattern
2363-
// against a non-reference type.
2362+
// We can't match an inherited shared reference with `&mut`.
23642363
// NB: This assumes that `&` patterns can match against mutable
23652364
// references (RFC 3627, Rule 5). If we implement a pattern typing
23662365
// ruleset with Rule 4 but not Rule 5, we'll need to check that here.
23672366
debug_assert!(ref_pat_matches_mut_ref);
2368-
} else {
2369-
pat_info.binding_mode = ByRef::No;
2370-
self.typeck_results
2371-
.borrow_mut()
2372-
.skipped_ref_pats_mut()
2373-
.insert(pat.hir_id);
2374-
self.check_pat(inner, expected, pat_info);
2375-
return expected;
2367+
self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
23762368
}
2369+
2370+
pat_info.binding_mode = ByRef::No;
2371+
self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2372+
self.check_pat(inner, expected, pat_info);
2373+
return expected;
23772374
}
23782375
}
23792376
InheritedRefMatchRule::EatBoth => {
@@ -2447,6 +2444,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24472444
Ty::new_ref(self.tcx, region, ty, mutbl)
24482445
}
24492446

2447+
fn error_inherited_ref_mutability_mismatch(
2448+
&self,
2449+
pat: &'tcx Pat<'tcx>,
2450+
pat_prefix_span: Option<Span>,
2451+
) -> ErrorGuaranteed {
2452+
let err_msg = "mismatched types";
2453+
let err = if let Some(span) = pat_prefix_span {
2454+
let mut err = self.dcx().struct_span_err(span, err_msg);
2455+
err.code(E0308);
2456+
err.note("cannot match inherited `&` with `&mut` pattern");
2457+
err.span_suggestion_verbose(
2458+
span,
2459+
"replace this `&mut` pattern with `&`",
2460+
"&",
2461+
Applicability::MachineApplicable,
2462+
);
2463+
err
2464+
} else {
2465+
self.dcx().struct_span_err(pat.span, err_msg)
2466+
};
2467+
err.emit()
2468+
}
2469+
24502470
fn try_resolve_slice_ty_to_array_ty(
24512471
&self,
24522472
before: &'tcx [Pat<'tcx>],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# `ref_pat_eat_one_layer_2024_structural`
2+
3+
The tracking issue for this feature is: [#123076]
4+
5+
[#123076]: https://github.com/rust-lang/rust/issues/123076
6+
7+
---
8+
9+
This feature is incomplete and not yet intended for general use.
10+
11+
This implements experimental, Edition-dependent match ergonomics under consideration for inclusion
12+
in Rust.
13+
For more information, see the corresponding typing rules for [Editions 2024 and later].
14+
On earlier Editions, the current behavior is unspecified.
15+
16+
For alternative experimental match ergonomics, see the feature
17+
[`ref_pat_eat_one_layer_2024`](./ref-pat-eat-one-layer-2024.md).
18+
19+
[Editions 2024 and later]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAgEBAQEBAgIAAAAAAAAAAAAAAAA%3D&mode=rules&do_cmp=false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# `ref_pat_eat_one_layer_2024`
2+
3+
The tracking issue for this feature is: [#123076]
4+
5+
[#123076]: https://github.com/rust-lang/rust/issues/123076
6+
7+
---
8+
9+
This feature is incomplete and not yet intended for general use.
10+
11+
This implements experimental, Edition-dependent match ergonomics under consideration for inclusion
12+
in Rust.
13+
For more information, see the corresponding typing rules for [Editions 2024 and later].
14+
On earlier Editions, the current behavior is unspecified.
15+
16+
For alternative experimental match ergonomics, see the feature
17+
[`ref_pat_eat_one_layer_2024_structural`](./ref-pat-eat-one-layer-2024-structural.md).
18+
19+
[Editions 2024 and later]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAAABAQABAgIAAQEBAAEBAAABAAA%3D&mode=rules&do_cmp=false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
error[E0508]: cannot move out of type `[&mut u32; 1]`, a non-copy array
2+
--> $DIR/borrowck-errors.rs:13:16
3+
|
4+
LL | let [&x] = &[&mut 0];
5+
| - ^^^^^^^^^ cannot move out of here
6+
| |
7+
| data moved here
8+
| move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait
9+
|
10+
help: consider borrowing the pattern binding
11+
|
12+
LL | let [&ref x] = &[&mut 0];
13+
| +++
14+
15+
error[E0508]: cannot move out of type `[&mut u32; 1]`, a non-copy array
16+
--> $DIR/borrowck-errors.rs:19:16
17+
|
18+
LL | let [&x] = &mut [&mut 0];
19+
| - ^^^^^^^^^^^^^ cannot move out of here
20+
| |
21+
| data moved here
22+
| move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait
23+
|
24+
help: consider borrowing the pattern binding
25+
|
26+
LL | let [&ref x] = &mut [&mut 0];
27+
| +++
28+
29+
error[E0507]: cannot move out of a shared reference
30+
--> $DIR/borrowck-errors.rs:27:29
31+
|
32+
LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) {
33+
| - ^^^^^^^^^^^^^^^^^^^
34+
| |
35+
| data moved here
36+
| move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait
37+
|
38+
help: consider removing the borrow
39+
|
40+
LL - if let Some(&Some(x)) = Some(&Some(&mut 0)) {
41+
LL + if let Some(Some(x)) = Some(&Some(&mut 0)) {
42+
|
43+
44+
error[E0596]: cannot borrow data in a `&` reference as mutable
45+
--> $DIR/borrowck-errors.rs:32:10
46+
|
47+
LL | let &ref mut x = &0;
48+
| ^^^^^^^^^ cannot borrow as mutable
49+
50+
error[E0596]: cannot borrow data in a `&` reference as mutable
51+
--> $DIR/borrowck-errors.rs:35:23
52+
|
53+
LL | if let &Some(Some(x)) = &Some(&mut Some(0)) {
54+
| ^ cannot borrow as mutable
55+
56+
error[E0596]: cannot borrow data in a `&` reference as mutable
57+
--> $DIR/borrowck-errors.rs:40:11
58+
|
59+
LL | let &[x] = &&mut [0];
60+
| ^ cannot borrow as mutable
61+
62+
error[E0508]: cannot move out of type `[&mut i32; 1]`, a non-copy array
63+
--> $DIR/borrowck-errors.rs:44:20
64+
|
65+
LL | let [&mut x] = &mut [&mut 0];
66+
| - ^^^^^^^^^^^^^ cannot move out of here
67+
| |
68+
| data moved here
69+
| move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait
70+
|
71+
help: consider borrowing the pattern binding
72+
|
73+
LL | let [&mut ref x] = &mut [&mut 0];
74+
| +++
75+
76+
error: aborting due to 7 previous errors
77+
78+
Some errors have detailed explanations: E0507, E0508, E0596.
79+
For more information about an error, try `rustc --explain E0507`.
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,27 @@
1-
//@ edition: 2024
2-
//@ revisions: classic structural
1+
//@ revisions: stable2021 classic2024 structural2024
2+
//@[stable2021] edition: 2021
3+
//@[classic2024] edition: 2024
4+
//@[structural2024] edition: 2024
35
//! Tests for pattern errors not handled by the pattern typing rules, but by borrowck.
46
#![allow(incomplete_features)]
5-
#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))]
6-
#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
7+
#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))]
8+
#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))]
9+
10+
/// These patterns additionally use `&` to match a `&mut` reference type, which causes compilation
11+
/// to fail in HIR typeck on stable. As such, they need to be separate from the other tests.
12+
fn errors_caught_in_hir_typeck_on_stable() {
13+
let [&x] = &[&mut 0];
14+
//[stable2021]~^ mismatched types
15+
//[stable2021]~| types differ in mutability
16+
//[classic2024]~^^^ ERROR: cannot move out of type
17+
let _: &u32 = x;
18+
19+
let [&x] = &mut [&mut 0];
20+
//[stable2021]~^ mismatched types
21+
//[stable2021]~| types differ in mutability
22+
//[classic2024]~^^^ ERROR: cannot move out of type
23+
let _: &u32 = x;
24+
}
725

826
pub fn main() {
927
if let Some(&Some(x)) = Some(&Some(&mut 0)) {
@@ -13,4 +31,18 @@ pub fn main() {
1331

1432
let &ref mut x = &0;
1533
//~^ cannot borrow data in a `&` reference as mutable [E0596]
34+
35+
if let &Some(Some(x)) = &Some(&mut Some(0)) {
36+
//[stable2021,classic2024]~^ ERROR: cannot borrow data in a `&` reference as mutable
37+
let _: &u32 = x;
38+
}
39+
40+
let &[x] = &&mut [0];
41+
//[stable2021,classic2024]~^ ERROR: cannot borrow data in a `&` reference as mutable
42+
let _: &u32 = x;
43+
44+
let [&mut x] = &mut [&mut 0];
45+
//[classic2024]~^ ERROR: cannot move out of type
46+
#[cfg(stable2021)] let _: u32 = x;
47+
#[cfg(structural2024)] let _: &mut u32 = x;
1648
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/borrowck-errors.rs:13:10
3+
|
4+
LL | let [&x] = &[&mut 0];
5+
| ^^ --------- this expression has type `&[&mut {integer}; 1]`
6+
| |
7+
| types differ in mutability
8+
|
9+
= note: expected mutable reference `&mut {integer}`
10+
found reference `&_`
11+
help: consider removing `&` from the pattern
12+
|
13+
LL - let [&x] = &[&mut 0];
14+
LL + let [x] = &[&mut 0];
15+
|
16+
17+
error[E0308]: mismatched types
18+
--> $DIR/borrowck-errors.rs:19:10
19+
|
20+
LL | let [&x] = &mut [&mut 0];
21+
| ^^ ------------- this expression has type `&mut [&mut {integer}; 1]`
22+
| |
23+
| types differ in mutability
24+
|
25+
= note: expected mutable reference `&mut {integer}`
26+
found reference `&_`
27+
help: consider removing `&` from the pattern
28+
|
29+
LL - let [&x] = &mut [&mut 0];
30+
LL + let [x] = &mut [&mut 0];
31+
|
32+
33+
error[E0507]: cannot move out of a shared reference
34+
--> $DIR/borrowck-errors.rs:27:29
35+
|
36+
LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) {
37+
| - ^^^^^^^^^^^^^^^^^^^
38+
| |
39+
| data moved here
40+
| move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait
41+
|
42+
help: consider removing the borrow
43+
|
44+
LL - if let Some(&Some(x)) = Some(&Some(&mut 0)) {
45+
LL + if let Some(Some(x)) = Some(&Some(&mut 0)) {
46+
|
47+
48+
error[E0596]: cannot borrow data in a `&` reference as mutable
49+
--> $DIR/borrowck-errors.rs:32:10
50+
|
51+
LL | let &ref mut x = &0;
52+
| ^^^^^^^^^ cannot borrow as mutable
53+
54+
error[E0596]: cannot borrow data in a `&` reference as mutable
55+
--> $DIR/borrowck-errors.rs:35:23
56+
|
57+
LL | if let &Some(Some(x)) = &Some(&mut Some(0)) {
58+
| ^ cannot borrow as mutable
59+
60+
error[E0596]: cannot borrow data in a `&` reference as mutable
61+
--> $DIR/borrowck-errors.rs:40:11
62+
|
63+
LL | let &[x] = &&mut [0];
64+
| ^ cannot borrow as mutable
65+
66+
error: aborting due to 6 previous errors
67+
68+
Some errors have detailed explanations: E0308, E0507, E0596.
69+
For more information about an error, try `rustc --explain E0308`.

tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural.stderr

-25
This file was deleted.

0 commit comments

Comments
 (0)