@@ -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