Skip to content

Commit

Permalink
Unrolled build for rust-lang#135434
Browse files Browse the repository at this point in the history
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````
  • Loading branch information
rust-timer authored Jan 30, 2025
2 parents a6434ef + be7d6e3 commit 924dc7e
Show file tree
Hide file tree
Showing 34 changed files with 1,923 additions and 336 deletions.
86 changes: 53 additions & 33 deletions compiler/rustc_hir_typeck/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn downgrade_mut_inside_shared(&self) -> bool {
// NB: RFC 3627 proposes stabilizing Rule 3 in all editions. If we adopt the same behavior
// across all editions, this may be removed.
self.tcx.features().ref_pat_eat_one_layer_2024()
|| self.tcx.features().ref_pat_eat_one_layer_2024_structural()
self.tcx.features().ref_pat_eat_one_layer_2024_structural()
}

/// Experimental pattern feature: when do reference patterns match against inherited references?
Expand Down Expand Up @@ -435,7 +434,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
max_ref_mutbl: MutblCap,
) -> (Ty<'tcx>, ByRef, MutblCap) {
#[cfg(debug_assertions)]
if def_br == ByRef::Yes(Mutability::Mut) && max_ref_mutbl != MutblCap::Mut {
if def_br == ByRef::Yes(Mutability::Mut)
&& max_ref_mutbl != MutblCap::Mut
&& self.downgrade_mut_inside_shared()
{
span_bug!(pat.span, "Pattern mutability cap violated!");
}
match adjust_mode {
Expand Down Expand Up @@ -2328,22 +2330,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// (RFC 3627, Rule 5). If we implement a pattern typing ruleset with Rule 4E
// but not Rule 5, we'll need to check that here.
debug_assert!(ref_pat_matches_mut_ref);
let err_msg = "mismatched types";
let err = if let Some(span) = pat_prefix_span {
let mut err = self.dcx().struct_span_err(span, err_msg);
err.code(E0308);
err.note("cannot match inherited `&` with `&mut` pattern");
err.span_suggestion_verbose(
span,
"replace this `&mut` pattern with `&`",
"&",
Applicability::MachineApplicable,
);
err
} else {
self.dcx().struct_span_err(pat.span, err_msg)
};
err.emit();
self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
}

pat_info.binding_mode = ByRef::No;
Expand All @@ -2352,28 +2339,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return expected;
}
InheritedRefMatchRule::EatInner => {
if let ty::Ref(_, _, r_mutbl) = *expected.kind() {
if let ty::Ref(_, _, r_mutbl) = *expected.kind()
&& pat_mutbl <= r_mutbl
{
// Match against the reference type; don't consume the inherited ref.
pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(r_mutbl);
// NB: The check for compatible pattern and ref type mutability assumes that
// `&` patterns can match against mutable references (RFC 3627, Rule 5). If
// we implement a pattern typing ruleset with Rule 4 (including the fallback
// to matching the inherited ref when the inner ref can't match) but not
// Rule 5, we'll need to check that here.
debug_assert!(ref_pat_matches_mut_ref);
// NB: For RFC 3627's Rule 3, we limit the default binding mode's ref
// mutability to `pat_info.max_ref_mutbl`. If we implement a pattern typing
// ruleset with Rule 4 but not Rule 3, we'll need to check that here.
debug_assert!(self.downgrade_mut_inside_shared());
let mutbl_cap = cmp::min(r_mutbl, pat_info.max_ref_mutbl.as_mutbl());
pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(mutbl_cap);
} else {
// The expected type isn't a reference, so match against the inherited ref.
// The reference pattern can't match against the expected type, so try
// matching against the inherited ref instead.
if pat_mutbl > inh_mut {
// We can't match an inherited shared reference with `&mut`. This will
// be a type error later, since we're matching a reference pattern
// against a non-reference type.
// We can't match an inherited shared reference with `&mut`.
// NB: This assumes that `&` patterns can match against mutable
// references (RFC 3627, Rule 5). If we implement a pattern typing
// ruleset with Rule 4 but not Rule 5, we'll need to check that here.
debug_assert!(ref_pat_matches_mut_ref);
} else {
pat_info.binding_mode = ByRef::No;
self.typeck_results
.borrow_mut()
.skipped_ref_pats_mut()
.insert(pat.hir_id);
self.check_pat(inner, expected, pat_info);
return expected;
self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
}

pat_info.binding_mode = ByRef::No;
self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
self.check_pat(inner, expected, pat_info);
return expected;
}
}
InheritedRefMatchRule::EatBoth => {
Expand Down Expand Up @@ -2447,6 +2444,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Ty::new_ref(self.tcx, region, ty, mutbl)
}

fn error_inherited_ref_mutability_mismatch(
&self,
pat: &'tcx Pat<'tcx>,
pat_prefix_span: Option<Span>,
) -> ErrorGuaranteed {
let err_msg = "mismatched types";
let err = if let Some(span) = pat_prefix_span {
let mut err = self.dcx().struct_span_err(span, err_msg);
err.code(E0308);
err.note("cannot match inherited `&` with `&mut` pattern");
err.span_suggestion_verbose(
span,
"replace this `&mut` pattern with `&`",
"&",
Applicability::MachineApplicable,
);
err
} else {
self.dcx().struct_span_err(pat.span, err_msg)
};
err.emit()
}

fn try_resolve_slice_ty_to_array_ty(
&self,
before: &'tcx [Pat<'tcx>],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# `ref_pat_eat_one_layer_2024_structural`

The tracking issue for this feature is: [#123076]

[#123076]: https://github.com/rust-lang/rust/issues/123076

---

This feature is incomplete and not yet intended for general use.

This implements experimental, Edition-dependent match ergonomics under consideration for inclusion
in Rust.
For more information, see the corresponding typing rules for [Editions 2024 and later].
On earlier Editions, the current behavior is unspecified.

For alternative experimental match ergonomics, see the feature
[`ref_pat_eat_one_layer_2024`](./ref-pat-eat-one-layer-2024.md).

[Editions 2024 and later]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAgEBAQEBAgIAAAAAAAAAAAAAAAA%3D&mode=rules&do_cmp=false
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# `ref_pat_eat_one_layer_2024`

The tracking issue for this feature is: [#123076]

[#123076]: https://github.com/rust-lang/rust/issues/123076

---

This feature is incomplete and not yet intended for general use.

This implements experimental, Edition-dependent match ergonomics under consideration for inclusion
in Rust.
For more information, see the corresponding typing rules for [Editions 2024 and later].
On earlier Editions, the current behavior is unspecified.

For alternative experimental match ergonomics, see the feature
[`ref_pat_eat_one_layer_2024_structural`](./ref-pat-eat-one-layer-2024-structural.md).

[Editions 2024 and later]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAAABAQABAgIAAQEBAAEBAAABAAA%3D&mode=rules&do_cmp=false
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
error[E0508]: cannot move out of type `[&mut u32; 1]`, a non-copy array
--> $DIR/borrowck-errors.rs:13:16
|
LL | let [&x] = &[&mut 0];
| - ^^^^^^^^^ cannot move out of here
| |
| data moved here
| move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait
|
help: consider borrowing the pattern binding
|
LL | let [&ref x] = &[&mut 0];
| +++

error[E0508]: cannot move out of type `[&mut u32; 1]`, a non-copy array
--> $DIR/borrowck-errors.rs:19:16
|
LL | let [&x] = &mut [&mut 0];
| - ^^^^^^^^^^^^^ cannot move out of here
| |
| data moved here
| move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait
|
help: consider borrowing the pattern binding
|
LL | let [&ref x] = &mut [&mut 0];
| +++

error[E0507]: cannot move out of a shared reference
--> $DIR/borrowck-errors.rs:27:29
|
LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) {
| - ^^^^^^^^^^^^^^^^^^^
| |
| data moved here
| move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait
|
help: consider removing the borrow
|
LL - if let Some(&Some(x)) = Some(&Some(&mut 0)) {
LL + if let Some(Some(x)) = Some(&Some(&mut 0)) {
|

error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/borrowck-errors.rs:32:10
|
LL | let &ref mut x = &0;
| ^^^^^^^^^ cannot borrow as mutable

error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/borrowck-errors.rs:35:23
|
LL | if let &Some(Some(x)) = &Some(&mut Some(0)) {
| ^ cannot borrow as mutable

error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/borrowck-errors.rs:40:11
|
LL | let &[x] = &&mut [0];
| ^ cannot borrow as mutable

error[E0508]: cannot move out of type `[&mut i32; 1]`, a non-copy array
--> $DIR/borrowck-errors.rs:44:20
|
LL | let [&mut x] = &mut [&mut 0];
| - ^^^^^^^^^^^^^ cannot move out of here
| |
| data moved here
| move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait
|
help: consider borrowing the pattern binding
|
LL | let [&mut ref x] = &mut [&mut 0];
| +++

error: aborting due to 7 previous errors

Some errors have detailed explanations: E0507, E0508, E0596.
For more information about an error, try `rustc --explain E0507`.
Original file line number Diff line number Diff line change
@@ -1,9 +1,27 @@
//@ edition: 2024
//@ revisions: classic structural
//@ revisions: stable2021 classic2024 structural2024
//@[stable2021] edition: 2021
//@[classic2024] edition: 2024
//@[structural2024] edition: 2024
//! Tests for pattern errors not handled by the pattern typing rules, but by borrowck.
#![allow(incomplete_features)]
#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))]
#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))]
#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))]

/// These patterns additionally use `&` to match a `&mut` reference type, which causes compilation
/// to fail in HIR typeck on stable. As such, they need to be separate from the other tests.
fn errors_caught_in_hir_typeck_on_stable() {
let [&x] = &[&mut 0];
//[stable2021]~^ mismatched types
//[stable2021]~| types differ in mutability
//[classic2024]~^^^ ERROR: cannot move out of type
let _: &u32 = x;

let [&x] = &mut [&mut 0];
//[stable2021]~^ mismatched types
//[stable2021]~| types differ in mutability
//[classic2024]~^^^ ERROR: cannot move out of type
let _: &u32 = x;
}

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

let &ref mut x = &0;
//~^ cannot borrow data in a `&` reference as mutable [E0596]

if let &Some(Some(x)) = &Some(&mut Some(0)) {
//[stable2021,classic2024]~^ ERROR: cannot borrow data in a `&` reference as mutable
let _: &u32 = x;
}

let &[x] = &&mut [0];
//[stable2021,classic2024]~^ ERROR: cannot borrow data in a `&` reference as mutable
let _: &u32 = x;

let [&mut x] = &mut [&mut 0];
//[classic2024]~^ ERROR: cannot move out of type
#[cfg(stable2021)] let _: u32 = x;
#[cfg(structural2024)] let _: &mut u32 = x;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
error[E0308]: mismatched types
--> $DIR/borrowck-errors.rs:13:10
|
LL | let [&x] = &[&mut 0];
| ^^ --------- this expression has type `&[&mut {integer}; 1]`
| |
| types differ in mutability
|
= note: expected mutable reference `&mut {integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - let [&x] = &[&mut 0];
LL + let [x] = &[&mut 0];
|

error[E0308]: mismatched types
--> $DIR/borrowck-errors.rs:19:10
|
LL | let [&x] = &mut [&mut 0];
| ^^ ------------- this expression has type `&mut [&mut {integer}; 1]`
| |
| types differ in mutability
|
= note: expected mutable reference `&mut {integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - let [&x] = &mut [&mut 0];
LL + let [x] = &mut [&mut 0];
|

error[E0507]: cannot move out of a shared reference
--> $DIR/borrowck-errors.rs:27:29
|
LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) {
| - ^^^^^^^^^^^^^^^^^^^
| |
| data moved here
| move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait
|
help: consider removing the borrow
|
LL - if let Some(&Some(x)) = Some(&Some(&mut 0)) {
LL + if let Some(Some(x)) = Some(&Some(&mut 0)) {
|

error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/borrowck-errors.rs:32:10
|
LL | let &ref mut x = &0;
| ^^^^^^^^^ cannot borrow as mutable

error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/borrowck-errors.rs:35:23
|
LL | if let &Some(Some(x)) = &Some(&mut Some(0)) {
| ^ cannot borrow as mutable

error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/borrowck-errors.rs:40:11
|
LL | let &[x] = &&mut [0];
| ^ cannot borrow as mutable

error: aborting due to 6 previous errors

Some errors have detailed explanations: E0308, E0507, E0596.
For more information about an error, try `rustc --explain E0308`.

This file was deleted.

Loading

0 comments on commit 924dc7e

Please sign in to comment.