1
Fork 0

Match ergonomics 2024: Implement eat-one-layer

This commit is contained in:
Jules Bertholet 2024-03-31 22:27:19 -05:00
parent 63f70b3d10
commit 93544d5db3
No known key found for this signature in database
GPG key ID: 32034DAFC38C1BFC
10 changed files with 471 additions and 50 deletions

View file

@ -571,6 +571,8 @@ declare_features! (
(unstable, proc_macro_hygiene, "1.30.0", Some(54727)), (unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
/// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions. /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.
(unstable, raw_ref_op, "1.41.0", Some(64490)), (unstable, raw_ref_op, "1.41.0", Some(64490)),
/// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024.
(incomplete, ref_pat_eat_one_layer_2024, "CURRENT_RUSTC_VERSION", Some(123076)),
/// Allows `&` and `&mut` patterns to consume match-ergonomics-inserted references. /// Allows `&` and `&mut` patterns to consume match-ergonomics-inserted references.
(incomplete, ref_pat_everywhere, "CURRENT_RUSTC_VERSION", Some(123076)), (incomplete, ref_pat_everywhere, "CURRENT_RUSTC_VERSION", Some(123076)),
/// Allows using the `#[register_tool]` attribute. /// Allows using the `#[register_tool]` attribute.

View file

@ -294,7 +294,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
AdjustMode::Pass => (expected, def_bm, false), AdjustMode::Pass => (expected, def_bm, false),
AdjustMode::Reset => (expected, INITIAL_BM, false), AdjustMode::Reset => (expected, INITIAL_BM, false),
AdjustMode::ResetAndConsumeRef(mutbl) => { AdjustMode::ResetAndConsumeRef(mutbl) => {
(expected, INITIAL_BM, def_bm.0 == ByRef::Yes(mutbl)) let mutbls_match = def_bm.0 == ByRef::Yes(mutbl);
if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 {
if mutbls_match {
(expected, INITIAL_BM, true)
} else {
(expected, def_bm, false)
}
} else {
(expected, INITIAL_BM, mutbls_match)
}
} }
AdjustMode::Peel => { AdjustMode::Peel => {
let peeled = self.peel_off_references(pat, expected, def_bm); let peeled = self.peel_off_references(pat, expected, def_bm);
@ -2056,61 +2065,70 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pat_info: PatInfo<'tcx, '_>, pat_info: PatInfo<'tcx, '_>,
consumed_inherited_ref: bool, consumed_inherited_ref: bool,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
let tcx = self.tcx; if consumed_inherited_ref
let expected = self.shallow_resolve(expected); && pat.span.at_least_rust_2024()
let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) { && self.tcx.features().ref_pat_eat_one_layer_2024
Ok(()) => { {
// `demand::subtype` would be good enough, but using `eqtype` turns self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
// out to be equally general. See (note_1) for details. self.check_pat(inner, expected, pat_info);
expected
} else {
let tcx = self.tcx;
let expected = self.shallow_resolve(expected);
let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
Ok(()) => {
// `demand::subtype` would be good enough, but using `eqtype` turns
// out to be equally general. See (note_1) for details.
// Take region, inner-type from expected type if we can, // Take region, inner-type from expected type if we can,
// to avoid creating needless variables. This also helps with // to avoid creating needless variables. This also helps with
// the bad interactions of the given hack detailed in (note_1). // the bad interactions of the given hack detailed in (note_1).
debug!("check_pat_ref: expected={:?}", expected); debug!("check_pat_ref: expected={:?}", expected);
match *expected.kind() { match *expected.kind() {
ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty), ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
_ => { _ => {
if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere { if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere {
// We already matched against a match-ergonmics inserted reference, // We already matched against a match-ergonmics inserted reference,
// so we don't need to match against a reference from the original type. // so we don't need to match against a reference from the original type.
// Save this infor for use in lowering later // Save this infor for use in lowering later
self.typeck_results self.typeck_results
.borrow_mut() .borrow_mut()
.skipped_ref_pats_mut() .skipped_ref_pats_mut()
.insert(pat.hir_id); .insert(pat.hir_id);
(expected, expected) (expected, expected)
} else { } else {
let inner_ty = self.next_ty_var(TypeVariableOrigin { let inner_ty = self.next_ty_var(TypeVariableOrigin {
param_def_id: None, param_def_id: None,
span: inner.span, span: inner.span,
}); });
let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty); let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty); debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
let err = self.demand_eqtype_pat_diag( let err = self.demand_eqtype_pat_diag(
pat.span, pat.span,
expected, expected,
ref_ty, ref_ty,
pat_info.top_info, pat_info.top_info,
); );
// Look for a case like `fn foo(&foo: u32)` and suggest // Look for a case like `fn foo(&foo: u32)` and suggest
// `fn foo(foo: &u32)` // `fn foo(foo: &u32)`
if let Some(mut err) = err { if let Some(mut err) = err {
self.borrow_pat_suggestion(&mut err, pat); self.borrow_pat_suggestion(&mut err, pat);
err.emit(); err.emit();
}
(ref_ty, inner_ty)
} }
(ref_ty, inner_ty)
} }
} }
} }
} Err(guar) => {
Err(guar) => { let err = Ty::new_error(tcx, guar);
let err = Ty::new_error(tcx, guar); (err, err)
(err, err) }
} };
}; self.check_pat(inner, inner_ty, pat_info);
self.check_pat(inner, inner_ty, pat_info); ref_ty
ref_ty }
} }
/// Create a reference type with a fresh region variable. /// Create a reference type with a fresh region variable.

View file

@ -1460,6 +1460,7 @@ symbols! {
receiver, receiver,
recursion_limit, recursion_limit,
reexport_test_harness_main, reexport_test_harness_main,
ref_pat_eat_one_layer_2024,
ref_pat_everywhere, ref_pat_everywhere,
ref_unwind_safe_trait, ref_unwind_safe_trait,
reference, reference,

View file

@ -0,0 +1,37 @@
//@ edition: 2024
//@ compile-flags: -Zunstable-options
pub fn main() {
if let Some(Some(&x)) = &Some(&Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(Some(&x)) = &Some(Some(&0)) {
let _: &u32 = x;
//~^ ERROR: mismatched types
}
if let Some(Some(&&x)) = &Some(Some(&0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(&Some(x)) = &Some(Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(Some(&x)) = &Some(&Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
}

View file

@ -0,0 +1,128 @@
error[E0308]: mismatched types
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:5:22
|
LL | if let Some(Some(&x)) = &Some(&Some(0)) {
| ^^ --------------- this expression has type `&Option<&Option<{integer}>>`
| |
| expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL | if let Some(Some(x)) = &Some(&Some(0)) {
| ~
error[E0308]: mismatched types
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:10:23
|
LL | let _: &u32 = x;
| ---- ^ expected `&u32`, found integer
| |
| expected due to this
|
help: consider borrowing here
|
LL | let _: &u32 = &x;
| +
error[E0308]: mismatched types
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:13:23
|
LL | if let Some(Some(&&x)) = &Some(Some(&0)) {
| ^^ --------------- this expression has type `&Option<Option<&{integer}>>`
| |
| expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - if let Some(Some(&&x)) = &Some(Some(&0)) {
LL + if let Some(Some(&x)) = &Some(Some(&0)) {
|
error[E0308]: mismatched types
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:17:17
|
LL | if let Some(&Some(x)) = &Some(Some(0)) {
| ^^^^^^^^ -------------- this expression has type `&Option<Option<{integer}>>`
| |
| expected `Option<{integer}>`, found `&_`
|
= note: expected enum `Option<{integer}>`
found reference `&_`
error[E0308]: mismatched types
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:21:22
|
LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
| ^^^^^^ ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>`
| |
| expected integer, found `&mut _`
|
= note: expected type `{integer}`
found mutable reference `&mut _`
note: to declare a mutable binding use: `mut x`
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:21:22
|
LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
| ^^^^^^
help: consider removing `&mut` from the pattern
|
LL | if let Some(Some(x)) = &mut Some(&mut Some(0)) {
| ~
error[E0308]: mismatched types
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:25:22
|
LL | if let Some(Some(&x)) = &Some(&Some(0)) {
| ^^ --------------- this expression has type `&Option<&Option<{integer}>>`
| |
| expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL | if let Some(Some(x)) = &Some(&Some(0)) {
| ~
error[E0308]: mismatched types
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:29:27
|
LL | if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
| ^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>`
| |
| expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL | if let Some(&mut Some(x)) = &Some(&mut Some(0)) {
| ~
error[E0308]: mismatched types
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:33:23
|
LL | if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
| ^^^^^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>`
| |
| expected integer, found `&mut _`
|
= note: expected type `{integer}`
found mutable reference `&mut _`
note: to declare a mutable binding use: `mut x`
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:33:23
|
LL | if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
| ^^^^^^
help: consider removing `&mut` from the pattern
|
LL | if let Some(&Some(x)) = &mut Some(&Some(0)) {
| ~
error: aborting due to 8 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -0,0 +1,37 @@
//@ edition: 2021
#![allow(incomplete_features)]
#![feature(ref_pat_eat_one_layer_2024)]
pub fn main() {
if let Some(Some(&x)) = &Some(&Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(Some(&x)) = &Some(Some(&0)) {
let _: &u32 = x;
//~^ ERROR: mismatched types
}
if let Some(Some(&&x)) = &Some(Some(&0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(&Some(x)) = &Some(Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(Some(&x)) = &Some(&Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
}

View file

@ -0,0 +1,128 @@
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2021.rs:5:22
|
LL | if let Some(Some(&x)) = &Some(&Some(0)) {
| ^^ --------------- this expression has type `&Option<&Option<{integer}>>`
| |
| expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL | if let Some(Some(x)) = &Some(&Some(0)) {
| ~
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2021.rs:10:23
|
LL | let _: &u32 = x;
| ---- ^ expected `&u32`, found integer
| |
| expected due to this
|
help: consider borrowing here
|
LL | let _: &u32 = &x;
| +
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2021.rs:13:23
|
LL | if let Some(Some(&&x)) = &Some(Some(&0)) {
| ^^ --------------- this expression has type `&Option<Option<&{integer}>>`
| |
| expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - if let Some(Some(&&x)) = &Some(Some(&0)) {
LL + if let Some(Some(&x)) = &Some(Some(&0)) {
|
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2021.rs:17:17
|
LL | if let Some(&Some(x)) = &Some(Some(0)) {
| ^^^^^^^^ -------------- this expression has type `&Option<Option<{integer}>>`
| |
| expected `Option<{integer}>`, found `&_`
|
= note: expected enum `Option<{integer}>`
found reference `&_`
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2021.rs:21:22
|
LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
| ^^^^^^ ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>`
| |
| expected integer, found `&mut _`
|
= note: expected type `{integer}`
found mutable reference `&mut _`
note: to declare a mutable binding use: `mut x`
--> $DIR/ref_pat_eat_one_layer_2021.rs:21:22
|
LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
| ^^^^^^
help: consider removing `&mut` from the pattern
|
LL | if let Some(Some(x)) = &mut Some(&mut Some(0)) {
| ~
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2021.rs:25:22
|
LL | if let Some(Some(&x)) = &Some(&Some(0)) {
| ^^ --------------- this expression has type `&Option<&Option<{integer}>>`
| |
| expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL | if let Some(Some(x)) = &Some(&Some(0)) {
| ~
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2021.rs:29:27
|
LL | if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
| ^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>`
| |
| expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL | if let Some(&mut Some(x)) = &Some(&mut Some(0)) {
| ~
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2021.rs:33:23
|
LL | if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
| ^^^^^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>`
| |
| expected integer, found `&mut _`
|
= note: expected type `{integer}`
found mutable reference `&mut _`
note: to declare a mutable binding use: `mut x`
--> $DIR/ref_pat_eat_one_layer_2021.rs:33:23
|
LL | if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
| ^^^^^^
help: consider removing `&mut` from the pattern
|
LL | if let Some(&Some(x)) = &mut Some(&Some(0)) {
| ~
error: aborting due to 8 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -0,0 +1,32 @@
//@ run-pass
//@ edition: 2024
//@ compile-flags: -Zunstable-options
#![allow(incomplete_features)]
#![feature(ref_pat_eat_one_layer_2024)]
pub fn main() {
if let Some(Some(&x)) = &Some(&Some(0)) {
let _: u32 = x;
}
if let Some(Some(&x)) = &Some(Some(&0)) {
let _: &u32 = x;
}
if let Some(Some(&&x)) = &Some(Some(&0)) {
let _: u32 = x;
}
if let Some(&Some(x)) = &Some(Some(0)) {
let _: u32 = x;
}
if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
let _: u32 = x;
}
if let Some(Some(&x)) = &Some(&Some(0)) {
let _: u32 = x;
}
if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
let _: u32 = x;
}
if let Some(&Some(&mut x)) = &mut Some(& Some(0)) {
let _: u32 = x;
}
}

View file

@ -0,0 +1,13 @@
//@ edition: 2024
//@ compile-flags: -Zunstable-options
#![allow(incomplete_features)]
#![feature(ref_pat_eat_one_layer_2024)]
pub fn main() {
if let Some(&mut Some(&_)) = &Some(&Some(0)) {
//~^ ERROR: mismatched types
}
if let Some(&Some(&_)) = &Some(&mut Some(0)) {
//~^ ERROR: mismatched types
}
}

View file

@ -0,0 +1,25 @@
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:7:17
|
LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) {
| ^^^^^^^^^^^^^ --------------- this expression has type `&Option<&Option<{integer}>>`
| |
| types differ in mutability
|
= note: expected reference `&Option<{integer}>`
found mutable reference `&mut _`
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:10:23
|
LL | if let Some(&Some(&_)) = &Some(&mut Some(0)) {
| ^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>`
| |
| expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.