diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index e6b19817de3..5d17675a532 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -571,6 +571,8 @@ declare_features! (
(unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
/// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.
(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.
(incomplete, ref_pat_everywhere, "CURRENT_RUSTC_VERSION", Some(123076)),
/// Allows using the `#[register_tool]` attribute.
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index db4bd132b7e..ff7716ce7ea 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -294,7 +294,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
AdjustMode::Pass => (expected, def_bm, false),
AdjustMode::Reset => (expected, INITIAL_BM, false),
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 => {
let peeled = self.peel_off_references(pat, expected, def_bm);
@@ -2056,61 +2065,70 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pat_info: PatInfo<'tcx, '_>,
consumed_inherited_ref: bool,
) -> Ty<'tcx> {
- 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.
+ if consumed_inherited_ref
+ && pat.span.at_least_rust_2024()
+ && self.tcx.features().ref_pat_eat_one_layer_2024
+ {
+ self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
+ 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,
- // to avoid creating needless variables. This also helps with
- // the bad interactions of the given hack detailed in (note_1).
- debug!("check_pat_ref: expected={:?}", expected);
- match *expected.kind() {
- ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
- _ => {
- if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere {
- // We already matched against a match-ergonmics inserted reference,
- // so we don't need to match against a reference from the original type.
- // Save this infor for use in lowering later
- self.typeck_results
- .borrow_mut()
- .skipped_ref_pats_mut()
- .insert(pat.hir_id);
- (expected, expected)
- } else {
- let inner_ty = self.next_ty_var(TypeVariableOrigin {
- param_def_id: None,
- span: inner.span,
- });
- let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
- debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
- let err = self.demand_eqtype_pat_diag(
- pat.span,
- expected,
- ref_ty,
- pat_info.top_info,
- );
+ // Take region, inner-type from expected type if we can,
+ // to avoid creating needless variables. This also helps with
+ // the bad interactions of the given hack detailed in (note_1).
+ debug!("check_pat_ref: expected={:?}", expected);
+ match *expected.kind() {
+ ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
+ _ => {
+ if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere {
+ // We already matched against a match-ergonmics inserted reference,
+ // so we don't need to match against a reference from the original type.
+ // Save this infor for use in lowering later
+ self.typeck_results
+ .borrow_mut()
+ .skipped_ref_pats_mut()
+ .insert(pat.hir_id);
+ (expected, expected)
+ } else {
+ let inner_ty = self.next_ty_var(TypeVariableOrigin {
+ param_def_id: None,
+ span: inner.span,
+ });
+ let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
+ debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
+ let err = self.demand_eqtype_pat_diag(
+ pat.span,
+ expected,
+ ref_ty,
+ pat_info.top_info,
+ );
- // Look for a case like `fn foo(&foo: u32)` and suggest
- // `fn foo(foo: &u32)`
- if let Some(mut err) = err {
- self.borrow_pat_suggestion(&mut err, pat);
- err.emit();
+ // Look for a case like `fn foo(&foo: u32)` and suggest
+ // `fn foo(foo: &u32)`
+ if let Some(mut err) = err {
+ self.borrow_pat_suggestion(&mut err, pat);
+ err.emit();
+ }
+ (ref_ty, inner_ty)
}
- (ref_ty, inner_ty)
}
}
}
- }
- Err(guar) => {
- let err = Ty::new_error(tcx, guar);
- (err, err)
- }
- };
- self.check_pat(inner, inner_ty, pat_info);
- ref_ty
+ Err(guar) => {
+ let err = Ty::new_error(tcx, guar);
+ (err, err)
+ }
+ };
+ self.check_pat(inner, inner_ty, pat_info);
+ ref_ty
+ }
}
/// Create a reference type with a fresh region variable.
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index bfd0f77c237..baf7fab3ad8 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1460,6 +1460,7 @@ symbols! {
receiver,
recursion_limit,
reexport_test_harness_main,
+ ref_pat_eat_one_layer_2024,
ref_pat_everywhere,
ref_unwind_safe_trait,
reference,
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs
new file mode 100644
index 00000000000..83f1ee6a77e
--- /dev/null
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs
@@ -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;
+ }
+}
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr
new file mode 100644
index 00000000000..132fe421a18
--- /dev/null
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr
@@ -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