diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 8e3b19f79a5..617c08181fb 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -406,7 +406,7 @@ fn peel_off_references( pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, mut def_br: ByRef, - mut max_ref_mutability: MutblCap, + mut max_ref_mutbl: MutblCap, ) -> (Ty<'tcx>, ByRef, MutblCap) { 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, @@ -438,10 +438,10 @@ fn peel_off_references( }); } - if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 { - def_br = def_br.cap_ref_mutability(max_ref_mutability.as_mutbl()); + if self.tcx.features().ref_pat_eat_one_layer_2024 { + def_br = def_br.cap_ref_mutability(max_ref_mutbl.as_mutbl()); if def_br == ByRef::Yes(Mutability::Not) { - max_ref_mutability = MutblCap::Not; + max_ref_mutbl = MutblCap::Not; } } @@ -453,7 +453,7 @@ fn peel_off_references( .insert(pat.hir_id, pat_adjustments); } - (expected, def_br, max_ref_mutability) + (expected, def_br, max_ref_mutbl) } fn check_pat_lit( @@ -2130,18 +2130,22 @@ fn check_pat_ref( mut expected: Ty<'tcx>, mut pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { - let new_match_ergonomics = - pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024; + let no_ref_mut_behind_and = self.tcx.features().ref_pat_eat_one_layer_2024; + let new_match_ergonomics = pat.span.at_least_rust_2024() && no_ref_mut_behind_and; - if new_match_ergonomics { - let pat_prefix_span = - inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end)); + let pat_prefix_span = + inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end)); + if no_ref_mut_behind_and { if pat_mutbl == Mutability::Not { // Prevent the inner pattern from binding with `ref mut`. pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(pat_prefix_span); } + } else { + pat_info.max_ref_mutbl = MutblCap::Mut; + } + if new_match_ergonomics { if let ByRef::Yes(inh_mut) = pat_info.binding_mode { // ref pattern consumes inherited reference @@ -2179,8 +2183,6 @@ fn check_pat_ref( .rust_2024_migration_desugared_pats_mut() .insert(pat_info.top_info.hir_id); } - - pat_info.max_ref_mutbl = MutblCap::Mut; } let tcx = self.tcx; @@ -2195,16 +2197,17 @@ fn check_pat_ref( // 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 >= pat_mutbl && new_match_ergonomics => { - if r_mutbl == Mutability::Not { + ty::Ref(_, r_ty, r_mutbl) + if (new_match_ergonomics && r_mutbl >= pat_mutbl) + || r_mutbl == pat_mutbl => + { + if no_ref_mut_behind_and && r_mutbl == Mutability::Not { pat_info.max_ref_mutbl = MutblCap::Not; } (expected, r_ty) } - ty::Ref(_, r_ty, r_mutbl) if r_mutbl == pat_mutbl => (expected, r_ty), - _ => { let inner_ty = self.next_ty_var(inner.span); let ref_ty = self.new_ref_ty(pat.span, pat_mutbl, inner_ty); diff --git a/tests/ui/pattern/no_ref_mut_behind_and.rs b/tests/ui/pattern/no_ref_mut_behind_and.rs new file mode 100644 index 00000000000..c18d64904d0 --- /dev/null +++ b/tests/ui/pattern/no_ref_mut_behind_and.rs @@ -0,0 +1,9 @@ +//@ edition: 2021 +//@ run-pass +#![allow(incomplete_features)] +#![feature(ref_pat_eat_one_layer_2024)] + +fn main() { + let &[[x]] = &[&mut [42]]; + let _: &i32 = x; +}