@@ -80,6 +80,7 @@ struct TopInfo<'tcx> {
8080#[ derive( Copy ,  Clone ) ]  
8181struct  PatInfo < ' tcx ,  ' a >  { 
8282    binding_mode :  BindingAnnotation , 
83+     max_ref_mutbl :  Mutability , 
8384    top_info :  TopInfo < ' tcx > , 
8485    decl_origin :  Option < DeclOrigin < ' a > > , 
8586
@@ -161,8 +162,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
161162        decl_origin :  Option < DeclOrigin < ' tcx > > , 
162163    )  { 
163164        let  info = TopInfo  {  expected,  origin_expr,  span } ; 
164-         let  pat_info =
165-             PatInfo  {  binding_mode :  INITIAL_BM ,  top_info :  info,  decl_origin,  current_depth :  0  } ; 
165+         let  pat_info = PatInfo  { 
166+             binding_mode :  INITIAL_BM , 
167+             max_ref_mutbl :  Mutability :: Mut , 
168+             top_info :  info, 
169+             decl_origin, 
170+             current_depth :  0 , 
171+         } ; 
166172        self . check_pat ( pat,  expected,  pat_info) ; 
167173    } 
168174
@@ -173,7 +179,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
173179     /// Conversely, inside this module, `check_pat_top` should never be used. 
174180     #[ instrument( level = "debug" ,  skip( self ,  pat_info) ) ]  
175181    fn  check_pat ( & self ,  pat :  & ' tcx  Pat < ' tcx > ,  expected :  Ty < ' tcx > ,  pat_info :  PatInfo < ' tcx ,  ' _ > )  { 
176-         let  PatInfo  {  binding_mode :  def_bm,  top_info :  ti,  current_depth,  .. }  = pat_info; 
182+         let  PatInfo  {  binding_mode :  def_bm,  max_ref_mutbl,  top_info :  ti,  current_depth,  .. }  =
183+             pat_info; 
177184
178185        let  path_res = match  & pat. kind  { 
179186            PatKind :: Path ( qpath)  => Some ( 
@@ -182,10 +189,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
182189            _ => None , 
183190        } ; 
184191        let  adjust_mode = self . calc_adjust_mode ( pat,  path_res. map ( |( res,  ..) | res) ) ; 
185-         let  ( expected,  def_bm,  ref_pattern_already_consumed)  =
186-             self . calc_default_binding_mode ( pat,  expected,  def_bm,  adjust_mode) ; 
192+         let  ( expected,  def_bm,  max_ref_mutbl ,   ref_pattern_already_consumed)  =
193+             self . calc_default_binding_mode ( pat,  expected,  def_bm,  adjust_mode,  max_ref_mutbl ) ; 
187194        let  pat_info = PatInfo  { 
188195            binding_mode :  def_bm, 
196+             max_ref_mutbl, 
189197            top_info :  ti, 
190198            decl_origin :  pat_info. decl_origin , 
191199            current_depth :  current_depth + 1 , 
@@ -290,16 +298,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
290298        expected :  Ty < ' tcx > , 
291299        def_bm :  BindingAnnotation , 
292300        adjust_mode :  AdjustMode , 
293-     )  -> ( Ty < ' tcx > ,  BindingAnnotation ,  bool )  { 
301+         max_ref_mutbl :  Mutability , 
302+     )  -> ( Ty < ' tcx > ,  BindingAnnotation ,  Mutability ,  bool )  { 
303+         if  let  ByRef :: Yes ( mutbl)  = def_bm. 0  { 
304+             debug_assert ! ( mutbl <= max_ref_mutbl) ; 
305+         } 
294306        match  adjust_mode { 
295-             AdjustMode :: Pass  => ( expected,  def_bm,  false ) , 
296-             AdjustMode :: Reset  => ( expected,  INITIAL_BM ,  false ) , 
297-             AdjustMode :: ResetAndConsumeRef ( mutbl)  => { 
298-                 ( expected,  INITIAL_BM ,  def_bm. 0  == ByRef :: Yes ( mutbl) ) 
307+             AdjustMode :: Pass  => ( expected,  def_bm,  max_ref_mutbl,  false ) , 
308+             AdjustMode :: Reset  => ( expected,  INITIAL_BM ,  Mutability :: Mut ,  false ) , 
309+             AdjustMode :: ResetAndConsumeRef ( ref_pat_mutbl)  => { 
310+                 let  mutbls_match = def_bm. 0  == ByRef :: Yes ( ref_pat_mutbl) ; 
311+                 if  pat. span . at_least_rust_2024 ( )  && self . tcx . features ( ) . ref_pat_eat_one_layer_2024  { 
312+                     if  mutbls_match { 
313+                         debug ! ( "consuming inherited reference" ) ; 
314+                         ( expected,  INITIAL_BM ,  cmp:: min ( max_ref_mutbl,  ref_pat_mutbl) ,  true ) 
315+                     }  else  { 
316+                         let  ( new_ty,  new_bm,  max_ref_mutbl)  = if  ref_pat_mutbl == Mutability :: Mut  { 
317+                             self . peel_off_references ( 
318+                                 pat, 
319+                                 expected, 
320+                                 def_bm, 
321+                                 Mutability :: Not , 
322+                                 max_ref_mutbl, 
323+                             ) 
324+                         }  else  { 
325+                             ( expected,  def_bm. cap_ref_mutability ( Mutability :: Not ) ,  Mutability :: Not ) 
326+                         } ; 
327+                         ( new_ty,  new_bm,  max_ref_mutbl,  false ) 
328+                     } 
329+                 }  else  { 
330+                     ( expected,  INITIAL_BM ,  max_ref_mutbl,  mutbls_match) 
331+                 } 
299332            } 
300333            AdjustMode :: Peel  => { 
301-                 let  peeled = self . peel_off_references ( pat,  expected,  def_bm) ; 
302-                 ( peeled. 0 ,  peeled. 1 ,  false ) 
334+                 let  peeled =
335+                     self . peel_off_references ( pat,  expected,  def_bm,  Mutability :: Mut ,  max_ref_mutbl) ; 
336+                 ( peeled. 0 ,  peeled. 1 ,  peeled. 2 ,  false ) 
303337            } 
304338        } 
305339    } 
@@ -380,7 +414,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
380414        pat :  & ' tcx  Pat < ' tcx > , 
381415        expected :  Ty < ' tcx > , 
382416        mut  def_bm :  BindingAnnotation , 
383-     )  -> ( Ty < ' tcx > ,  BindingAnnotation )  { 
417+         max_peelable_mutability :  Mutability , 
418+         mut  max_ref_mutability :  Mutability , 
419+     )  -> ( Ty < ' tcx > ,  BindingAnnotation ,  Mutability )  { 
384420        let  mut  expected = self . try_structurally_resolve_type ( pat. span ,  expected) ; 
385421        // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example, 
386422        // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches 
@@ -391,7 +427,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
391427        // 
392428        // See the examples in `ui/match-defbm*.rs`. 
393429        let  mut  pat_adjustments = vec ! [ ] ; 
394-         while  let  ty:: Ref ( _,  inner_ty,  inner_mutability)  = * expected. kind ( )  { 
430+         while  let  ty:: Ref ( _,  inner_ty,  inner_mutability)  = * expected. kind ( ) 
431+             && inner_mutability <= max_peelable_mutability
432+         { 
395433            debug ! ( "inspecting {:?}" ,  expected) ; 
396434
397435            debug ! ( "current discriminant is Ref, inserting implicit deref" ) ; 
@@ -411,6 +449,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
411449            } ) ; 
412450        } 
413451
452+         if  pat. span . at_least_rust_2024 ( )  && self . tcx . features ( ) . ref_pat_eat_one_layer_2024  { 
453+             def_bm = def_bm. cap_ref_mutability ( max_ref_mutability) ; 
454+             if  def_bm. 0  == ByRef :: Yes ( Mutability :: Not )  { 
455+                 max_ref_mutability = Mutability :: Not ; 
456+             } 
457+         } 
458+ 
414459        if  !pat_adjustments. is_empty ( )  { 
415460            debug ! ( "default binding mode is now {:?}" ,  def_bm) ; 
416461            self . typeck_results 
@@ -419,7 +464,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
419464                . insert ( pat. hir_id ,  pat_adjustments) ; 
420465        } 
421466
422-         ( expected,  def_bm) 
467+         ( expected,  def_bm,  max_ref_mutability ) 
423468    } 
424469
425470    fn  check_pat_lit ( 
@@ -1109,15 +1154,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11091154        expected :  Ty < ' tcx > , 
11101155        pat_info :  PatInfo < ' tcx ,  ' _ > , 
11111156    )  -> Ty < ' tcx >  { 
1112-         let  PatInfo  {  binding_mode :  def_bm,  top_info :  ti,  decl_origin,  current_depth }  = pat_info; 
11131157        let  tcx = self . tcx ; 
11141158        let  on_error = |e| { 
11151159            for  pat in  subpats { 
1116-                 self . check_pat ( 
1117-                     pat, 
1118-                     Ty :: new_error ( tcx,  e) , 
1119-                     PatInfo  {  binding_mode :  def_bm,  top_info :  ti,  decl_origin,  current_depth } , 
1120-                 ) ; 
1160+                 self . check_pat ( pat,  Ty :: new_error ( tcx,  e) ,  pat_info) ; 
11211161            } 
11221162        } ; 
11231163        let  report_unexpected_res = |res :  Res | { 
@@ -1162,7 +1202,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11621202        let  pat_ty = pat_ty. no_bound_vars ( ) . expect ( "expected fn type" ) ; 
11631203
11641204        // Type-check the tuple struct pattern against the expected type. 
1165-         let  diag = self . demand_eqtype_pat_diag ( pat. span ,  expected,  pat_ty,  ti ) ; 
1205+         let  diag = self . demand_eqtype_pat_diag ( pat. span ,  expected,  pat_ty,  pat_info . top_info ) ; 
11661206        let  had_err = if  let  Some ( err)  = diag { 
11671207            err. emit ( ) ; 
11681208            true 
@@ -1180,11 +1220,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11801220            for  ( i,  subpat)  in  subpats. iter ( ) . enumerate_and_adjust ( variant. fields . len ( ) ,  ddpos)  { 
11811221                let  field = & variant. fields [ FieldIdx :: from_usize ( i) ] ; 
11821222                let  field_ty = self . field_ty ( subpat. span ,  field,  args) ; 
1183-                 self . check_pat ( 
1184-                     subpat, 
1185-                     field_ty, 
1186-                     PatInfo  {  binding_mode :  def_bm,  top_info :  ti,  decl_origin,  current_depth } , 
1187-                 ) ; 
1223+                 self . check_pat ( subpat,  field_ty,  pat_info) ; 
11881224
11891225                self . tcx . check_stability ( 
11901226                    variant. fields [ FieldIdx :: from_usize ( i) ] . did , 
@@ -2071,61 +2107,70 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20712107        pat_info :  PatInfo < ' tcx ,  ' _ > , 
20722108        consumed_inherited_ref :  bool , 
20732109    )  -> Ty < ' tcx >  { 
2074-         let  tcx = self . tcx ; 
2075-         let  expected = self . shallow_resolve ( expected) ; 
2076-         let  ( ref_ty,  inner_ty)  = match  self . check_dereferenceable ( pat. span ,  expected,  inner)  { 
2077-             Ok ( ( ) )  => { 
2078-                 // `demand::subtype` would be good enough, but using `eqtype` turns 
2079-                 // out to be equally general. See (note_1) for details. 
2080- 
2081-                 // Take region, inner-type from expected type if we can, 
2082-                 // to avoid creating needless variables. This also helps with 
2083-                 // the bad interactions of the given hack detailed in (note_1). 
2084-                 debug ! ( "check_pat_ref: expected={:?}" ,  expected) ; 
2085-                 match  * expected. kind ( )  { 
2086-                     ty:: Ref ( _,  r_ty,  r_mutbl)  if  r_mutbl == mutbl => ( expected,  r_ty) , 
2087-                     _ => { 
2088-                         if  consumed_inherited_ref && self . tcx . features ( ) . ref_pat_everywhere  { 
2089-                             // We already matched against a match-ergonmics inserted reference, 
2090-                             // so we don't need to match against a reference from the original type. 
2091-                             // Save this infor for use in lowering later 
2092-                             self . typeck_results 
2093-                                 . borrow_mut ( ) 
2094-                                 . skipped_ref_pats_mut ( ) 
2095-                                 . insert ( pat. hir_id ) ; 
2096-                             ( expected,  expected) 
2097-                         }  else  { 
2098-                             let  inner_ty = self . next_ty_var ( TypeVariableOrigin  { 
2099-                                 param_def_id :  None , 
2100-                                 span :  inner. span , 
2101-                             } ) ; 
2102-                             let  ref_ty = self . new_ref_ty ( pat. span ,  mutbl,  inner_ty) ; 
2103-                             debug ! ( "check_pat_ref: demanding {:?} = {:?}" ,  expected,  ref_ty) ; 
2104-                             let  err = self . demand_eqtype_pat_diag ( 
2105-                                 pat. span , 
2106-                                 expected, 
2107-                                 ref_ty, 
2108-                                 pat_info. top_info , 
2109-                             ) ; 
2110+         if  consumed_inherited_ref
2111+             && pat. span . at_least_rust_2024 ( ) 
2112+             && self . tcx . features ( ) . ref_pat_eat_one_layer_2024 
2113+         { 
2114+             self . typeck_results . borrow_mut ( ) . skipped_ref_pats_mut ( ) . insert ( pat. hir_id ) ; 
2115+             self . check_pat ( inner,  expected,  pat_info) ; 
2116+             expected
2117+         }  else  { 
2118+             let  tcx = self . tcx ; 
2119+             let  expected = self . shallow_resolve ( expected) ; 
2120+             let  ( ref_ty,  inner_ty)  = match  self . check_dereferenceable ( pat. span ,  expected,  inner)  { 
2121+                 Ok ( ( ) )  => { 
2122+                     // `demand::subtype` would be good enough, but using `eqtype` turns 
2123+                     // out to be equally general. See (note_1) for details. 
2124+ 
2125+                     // Take region, inner-type from expected type if we can, 
2126+                     // to avoid creating needless variables. This also helps with 
2127+                     // the bad interactions of the given hack detailed in (note_1). 
2128+                     debug ! ( "check_pat_ref: expected={:?}" ,  expected) ; 
2129+                     match  * expected. kind ( )  { 
2130+                         ty:: Ref ( _,  r_ty,  r_mutbl)  if  r_mutbl == mutbl => ( expected,  r_ty) , 
2131+                         _ => { 
2132+                             if  consumed_inherited_ref && self . tcx . features ( ) . ref_pat_everywhere  { 
2133+                                 // We already matched against a match-ergonmics inserted reference, 
2134+                                 // so we don't need to match against a reference from the original type. 
2135+                                 // Save this infor for use in lowering later 
2136+                                 self . typeck_results 
2137+                                     . borrow_mut ( ) 
2138+                                     . skipped_ref_pats_mut ( ) 
2139+                                     . insert ( pat. hir_id ) ; 
2140+                                 ( expected,  expected) 
2141+                             }  else  { 
2142+                                 let  inner_ty = self . next_ty_var ( TypeVariableOrigin  { 
2143+                                     param_def_id :  None , 
2144+                                     span :  inner. span , 
2145+                                 } ) ; 
2146+                                 let  ref_ty = self . new_ref_ty ( pat. span ,  mutbl,  inner_ty) ; 
2147+                                 debug ! ( "check_pat_ref: demanding {:?} = {:?}" ,  expected,  ref_ty) ; 
2148+                                 let  err = self . demand_eqtype_pat_diag ( 
2149+                                     pat. span , 
2150+                                     expected, 
2151+                                     ref_ty, 
2152+                                     pat_info. top_info , 
2153+                                 ) ; 
21102154
2111-                             // Look for a case like `fn foo(&foo: u32)` and suggest 
2112-                             // `fn foo(foo: &u32)` 
2113-                             if  let  Some ( mut  err)  = err { 
2114-                                 self . borrow_pat_suggestion ( & mut  err,  pat) ; 
2115-                                 err. emit ( ) ; 
2155+                                 // Look for a case like `fn foo(&foo: u32)` and suggest 
2156+                                 // `fn foo(foo: &u32)` 
2157+                                 if  let  Some ( mut  err)  = err { 
2158+                                     self . borrow_pat_suggestion ( & mut  err,  pat) ; 
2159+                                     err. emit ( ) ; 
2160+                                 } 
2161+                                 ( ref_ty,  inner_ty) 
21162162                            } 
2117-                             ( ref_ty,  inner_ty) 
21182163                        } 
21192164                    } 
21202165                } 
2121-             } 
2122-             Err ( guar )  =>  { 
2123-                 let  err =  Ty :: new_error ( tcx ,  guar ) ; 
2124-                 ( err ,  err ) 
2125-             } 
2126-         } ; 
2127-         self . check_pat ( inner ,  inner_ty ,  pat_info ) ; 
2128-         ref_ty 
2166+                  Err ( guar )  =>  { 
2167+                      let  err =  Ty :: new_error ( tcx ,  guar ) ; 
2168+                      ( err ,  err ) 
2169+                 } 
2170+             } ; 
2171+              self . check_pat ( inner ,  inner_ty ,  pat_info ) ; 
2172+             ref_ty 
2173+         } 
21292174    } 
21302175
21312176    /// Create a reference type with a fresh region variable. 
0 commit comments