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