From b6c409723b6438a10db53f12ae6e79f530df8a1b Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Fri, 5 Apr 2024 22:07:57 -0400 Subject: [PATCH] Support `let &mut x = &&mut 0;` --- compiler/rustc_hir_typeck/src/pat.rs | 23 +++++++++----- .../ref_pat_eat_one_layer_2024.rs | 9 ++++++ .../ref_pat_eat_one_layer_2024_fail.rs | 8 +++++ .../ref_pat_eat_one_layer_2024_fail.stderr | 30 +++++++++++++++++-- 4 files changed, 60 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index bec177a2845..5930cc0698a 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -299,18 +299,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if mutbls_match { (expected, INITIAL_BM, true) } else { - let mut new_bm = def_bm; - if new_bm.0 == ByRef::Yes(Mutability::Mut) && mutbl == Mutability::Not { - new_bm.0 = ByRef::Yes(Mutability::Not); - } - (expected, new_bm, false) + let (new_ty, new_bm) = if mutbl == Mutability::Mut { + self.peel_off_references(pat, expected, def_bm, Mutability::Not) + } else { + let new_byref = if def_bm.0 == ByRef::Yes(Mutability::Mut) { + ByRef::Yes(Mutability::Not) + } else { + def_bm.0 + }; + (expected, BindingAnnotation(new_byref, def_bm.1)) + }; + (new_ty, new_bm, false) } } else { (expected, INITIAL_BM, mutbls_match) } } AdjustMode::Peel => { - let peeled = self.peel_off_references(pat, expected, def_bm); + let peeled = self.peel_off_references(pat, expected, def_bm, Mutability::Mut); (peeled.0, peeled.1, false) } } @@ -392,6 +398,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, mut def_bm: BindingAnnotation, + max_mutability: Mutability, ) -> (Ty<'tcx>, BindingAnnotation) { let mut expected = self.try_structurally_resolve_type(pat.span, expected); // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example, @@ -403,7 +410,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // See the examples in `ui/match-defbm*.rs`. let mut pat_adjustments = vec![]; - while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() { + while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() + && inner_mutability <= max_mutability + { debug!("inspecting {:?}", expected); debug!("current discriminant is Ref, inserting implicit deref"); diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs index 3cf6008609d..2c426f469d8 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs @@ -38,4 +38,13 @@ pub fn main() { if let Some(Some(&mut x)) = &Some(Some(&mut 0)) { let _: &u32 = x; } + + let &mut x = &&mut 0; + let _: &u32 = x; + + let &mut x = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0; + let _: &u32 = x; + + let &mut &mut &mut &mut x = &mut &&&&mut &&&mut &mut 0; + let _: &u32 = x; } diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs index f8385d2e049..9e14a524e2b 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs @@ -17,4 +17,12 @@ pub fn main() { if let Some(&Some(&x)) = Some(&Some(&mut 0)) { //~^ ERROR: mismatched types } + + let &mut x = &&0; + //~^ ERROR: mismatched types + let _: &u32 = x; + + let &mut x = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; + //~^ ERROR: mismatched types + let _: &u32 = x; } diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr index 8b714cfcc3e..074c5d298a5 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr @@ -4,9 +4,9 @@ error[E0308]: mismatched types LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) { | ^^^^^^^^^^^^^ --------------- this expression has type `&Option<&Option<{integer}>>` | | - | types differ in mutability + | expected `Option<{integer}>`, found `&mut _` | - = note: expected reference `&Option<{integer}>` + = note: expected enum `Option<{integer}>` found mutable reference `&mut _` error[E0308]: mismatched types @@ -46,6 +46,30 @@ help: consider removing `&` from the pattern LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) { | ~ -error: aborting due to 4 previous errors +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:21:9 + | +LL | let &mut x = &&0; + | ^^^^^^ --- this expression has type `&&{integer}` + | | + | expected integer, found `&mut _` + | help: to declare a mutable variable use: `mut x` + | + = note: expected type `{integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:25:9 + | +LL | let &mut x = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; + | ^^^^^^ ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}` + | | + | expected integer, found `&mut _` + | help: to declare a mutable variable use: `mut x` + | + = note: expected type `{integer}` + found mutable reference `&mut _` + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0308`.