@@ -243,8 +243,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
243243 fn downgrade_mut_inside_shared(&self) -> bool {
244244 // NB: RFC 3627 proposes stabilizing Rule 3 in all editions. If we adopt the same behavior
245245 // across all editions, this may be removed.
246- self.tcx.features().ref_pat_eat_one_layer_2024()
247- || self.tcx.features().ref_pat_eat_one_layer_2024_structural()
246+ self.tcx.features().ref_pat_eat_one_layer_2024_structural()
248247 }
249248
250249 /// Experimental pattern feature: when do reference patterns match against inherited references?
@@ -435,7 +434,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
435434 max_ref_mutbl: MutblCap,
436435 ) -> (Ty<'tcx>, ByRef, MutblCap) {
437436 #[cfg(debug_assertions)]
438- if def_br == ByRef::Yes(Mutability::Mut) && max_ref_mutbl != MutblCap::Mut {
437+ if def_br == ByRef::Yes(Mutability::Mut)
438+ && max_ref_mutbl != MutblCap::Mut
439+ && self.downgrade_mut_inside_shared()
440+ {
439441 span_bug!(pat.span, "Pattern mutability cap violated!");
440442 }
441443 match adjust_mode {
@@ -2328,22 +2330,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23282330 // (RFC 3627, Rule 5). If we implement a pattern typing ruleset with Rule 4E
23292331 // but not Rule 5, we'll need to check that here.
23302332 debug_assert!(ref_pat_matches_mut_ref);
2331- let err_msg = "mismatched types";
2332- let err = if let Some(span) = pat_prefix_span {
2333- let mut err = self.dcx().struct_span_err(span, err_msg);
2334- err.code(E0308);
2335- err.note("cannot match inherited `&` with `&mut` pattern");
2336- err.span_suggestion_verbose(
2337- span,
2338- "replace this `&mut` pattern with `&`",
2339- "&",
2340- Applicability::MachineApplicable,
2341- );
2342- err
2343- } else {
2344- self.dcx().struct_span_err(pat.span, err_msg)
2345- };
2346- err.emit();
2333+ self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
23472334 }
23482335
23492336 pat_info.binding_mode = ByRef::No;
@@ -2352,28 +2339,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23522339 return expected;
23532340 }
23542341 InheritedRefMatchRule::EatInner => {
2355- if let ty::Ref(_, _, r_mutbl) = *expected.kind() {
2342+ if let ty::Ref(_, _, r_mutbl) = *expected.kind()
2343+ && pat_mutbl <= r_mutbl
2344+ {
23562345 // Match against the reference type; don't consume the inherited ref.
2357- pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(r_mutbl);
2346+ // NB: The check for compatible pattern and ref type mutability assumes that
2347+ // `&` patterns can match against mutable references (RFC 3627, Rule 5). If
2348+ // we implement a pattern typing ruleset with Rule 4 (including the fallback
2349+ // to matching the inherited ref when the inner ref can't match) but not
2350+ // Rule 5, we'll need to check that here.
2351+ debug_assert!(ref_pat_matches_mut_ref);
2352+ // NB: For RFC 3627's Rule 3, we limit the default binding mode's ref
2353+ // mutability to `pat_info.max_ref_mutbl`. If we implement a pattern typing
2354+ // ruleset with Rule 4 but not Rule 3, we'll need to check that here.
2355+ debug_assert!(self.downgrade_mut_inside_shared());
2356+ let mutbl_cap = cmp::min(r_mutbl, pat_info.max_ref_mutbl.as_mutbl());
2357+ pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(mutbl_cap);
23582358 } else {
2359- // The expected type isn't a reference, so match against the inherited ref.
2359+ // The reference pattern can't match against the expected type, so try
2360+ // matching against the inherited ref instead.
23602361 if pat_mutbl > inh_mut {
2361- // We can't match an inherited shared reference with `&mut`. This will
2362- // be a type error later, since we're matching a reference pattern
2363- // against a non-reference type.
2362+ // We can't match an inherited shared reference with `&mut`.
23642363 // NB: This assumes that `&` patterns can match against mutable
23652364 // references (RFC 3627, Rule 5). If we implement a pattern typing
23662365 // ruleset with Rule 4 but not Rule 5, we'll need to check that here.
23672366 debug_assert!(ref_pat_matches_mut_ref);
2368- } else {
2369- pat_info.binding_mode = ByRef::No;
2370- self.typeck_results
2371- .borrow_mut()
2372- .skipped_ref_pats_mut()
2373- .insert(pat.hir_id);
2374- self.check_pat(inner, expected, pat_info);
2375- return expected;
2367+ self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
23762368 }
2369+
2370+ pat_info.binding_mode = ByRef::No;
2371+ self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2372+ self.check_pat(inner, expected, pat_info);
2373+ return expected;
23772374 }
23782375 }
23792376 InheritedRefMatchRule::EatBoth => {
@@ -2447,6 +2444,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24472444 Ty::new_ref(self.tcx, region, ty, mutbl)
24482445 }
24492446
2447+ fn error_inherited_ref_mutability_mismatch(
2448+ &self,
2449+ pat: &'tcx Pat<'tcx>,
2450+ pat_prefix_span: Option<Span>,
2451+ ) -> ErrorGuaranteed {
2452+ let err_msg = "mismatched types";
2453+ let err = if let Some(span) = pat_prefix_span {
2454+ let mut err = self.dcx().struct_span_err(span, err_msg);
2455+ err.code(E0308);
2456+ err.note("cannot match inherited `&` with `&mut` pattern");
2457+ err.span_suggestion_verbose(
2458+ span,
2459+ "replace this `&mut` pattern with `&`",
2460+ "&",
2461+ Applicability::MachineApplicable,
2462+ );
2463+ err
2464+ } else {
2465+ self.dcx().struct_span_err(pat.span, err_msg)
2466+ };
2467+ err.emit()
2468+ }
2469+
24502470 fn try_resolve_slice_ty_to_array_ty(
24512471 &self,
24522472 before: &'tcx [Pat<'tcx>],
0 commit comments