@@ -133,14 +133,6 @@ enum AdjustMode {
133133 /// Reset binding mode to the initial mode.
134134 /// Used for destructuring assignment, where we don't want any match ergonomics.
135135 Reset ,
136- /// Produced by ref patterns.
137- /// Reset the binding mode to the initial mode,
138- /// and if the old biding mode was by-reference
139- /// with mutability matching the pattern,
140- /// mark the pattern as having consumed this reference.
141- ///
142- /// `Span` is that of the `&` or `&mut` itself.
143- ResetAndConsumeRef ( Mutability , Option < Span > ) ,
144136 /// Pass on the input binding mode and expected type.
145137 Pass ,
146138}
@@ -172,13 +164,15 @@ enum MutblCap {
172164}
173165
174166impl MutblCap {
167+ #[ must_use]
175168 fn cap_to_weakly_not ( self , span : Option < Span > ) -> Self {
176169 match self {
177170 MutblCap :: Not => MutblCap :: Not ,
178171 _ => MutblCap :: WeaklyNot ( span) ,
179172 }
180173 }
181174
175+ #[ must_use]
182176 fn as_mutbl ( self ) -> Mutability {
183177 match self {
184178 MutblCap :: Not | MutblCap :: WeaklyNot ( _) => Mutability :: Not ,
@@ -216,14 +210,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
216210 }
217211
218212 /// Type check the given `pat` against the `expected` type
219- /// with the provided `def_bm ` (default binding mode).
213+ /// with the provided `binding_mode ` (default binding mode).
220214 ///
221215 /// Outside of this module, `check_pat_top` should always be used.
222216 /// Conversely, inside this module, `check_pat_top` should never be used.
223217 #[ instrument( level = "debug" , skip( self , pat_info) ) ]
224218 fn check_pat ( & self , pat : & ' tcx Pat < ' tcx > , expected : Ty < ' tcx > , pat_info : PatInfo < ' tcx , ' _ > ) {
225- let PatInfo { binding_mode : def_bm, max_ref_mutbl, top_info : ti, current_depth, .. } =
226- pat_info;
219+ let PatInfo { binding_mode, max_ref_mutbl, top_info : ti, current_depth, .. } = pat_info;
227220
228221 let path_res = match & pat. kind {
229222 PatKind :: Path ( qpath) => Some (
@@ -232,10 +225,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
232225 _ => None ,
233226 } ;
234227 let adjust_mode = self . calc_adjust_mode ( pat, path_res. map ( |( res, ..) | res) ) ;
235- let ( expected, def_bm , max_ref_mutbl, ref_pattern_already_consumed ) =
236- self . calc_default_binding_mode ( pat, expected, def_bm , adjust_mode, max_ref_mutbl) ;
228+ let ( expected, binding_mode , max_ref_mutbl) =
229+ self . calc_default_binding_mode ( pat, expected, binding_mode , adjust_mode, max_ref_mutbl) ;
237230 let pat_info = PatInfo {
238- binding_mode : def_bm ,
231+ binding_mode,
239232 max_ref_mutbl,
240233 top_info : ti,
241234 decl_origin : pat_info. decl_origin ,
@@ -271,14 +264,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
271264 }
272265 PatKind :: Box ( inner) => self . check_pat_box ( pat. span , inner, expected, pat_info) ,
273266 PatKind :: Deref ( inner) => self . check_pat_deref ( pat. span , inner, expected, pat_info) ,
274- PatKind :: Ref ( inner, mutbl) => self . check_pat_ref (
275- pat,
276- inner,
277- mutbl,
278- expected,
279- pat_info,
280- ref_pattern_already_consumed,
281- ) ,
267+ PatKind :: Ref ( inner, mutbl) => self . check_pat_ref ( pat, inner, mutbl, expected, pat_info) ,
282268 PatKind :: Slice ( before, slice, after) => {
283269 self . check_pat_slice ( pat. span , before, slice, after, expected, pat_info)
284270 }
@@ -331,61 +317,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
331317
332318 /// Compute the new expected type and default binding mode from the old ones
333319 /// as well as the pattern form we are currently checking.
334- ///
335- /// Last entry is only relevant for ref patterns (`&` and `&mut`);
336- /// if `true`, then the ref pattern consumed a match ergonomics inserted reference
337- /// and so does no need to match against a reference in the scrutinee type.
338320 fn calc_default_binding_mode (
339321 & self ,
340322 pat : & ' tcx Pat < ' tcx > ,
341323 expected : Ty < ' tcx > ,
342324 def_br : ByRef ,
343325 adjust_mode : AdjustMode ,
344326 max_ref_mutbl : MutblCap ,
345- ) -> ( Ty < ' tcx > , ByRef , MutblCap , bool ) {
327+ ) -> ( Ty < ' tcx > , ByRef , MutblCap ) {
346328 if let ByRef :: Yes ( Mutability :: Mut ) = def_br {
347329 debug_assert ! ( max_ref_mutbl == MutblCap :: Mut ) ;
348330 }
349331 match adjust_mode {
350- AdjustMode :: Pass => ( expected, def_br, max_ref_mutbl, false ) ,
351- AdjustMode :: Reset => ( expected, ByRef :: No , MutblCap :: Mut , false ) ,
352- AdjustMode :: ResetAndConsumeRef ( ref_pat_mutbl, ref_span) => {
353- // `&` pattern eats `&mut`
354- let mutbls_match =
355- if let ByRef :: Yes ( def_mut) = def_br { ref_pat_mutbl <= def_mut } else { false } ;
356-
357- if pat. span . at_least_rust_2024 ( ) && self . tcx . features ( ) . ref_pat_eat_one_layer_2024 {
358- let max_ref_mutbl = if ref_pat_mutbl == Mutability :: Not {
359- max_ref_mutbl. cap_to_weakly_not ( ref_span)
360- } else {
361- max_ref_mutbl
362- } ;
363-
364- if mutbls_match {
365- debug ! ( "consuming inherited reference" ) ;
366- ( expected, ByRef :: No , max_ref_mutbl, true )
367- } else {
368- let ( new_ty, new_bm, max_ref_mutbl) = if ref_pat_mutbl == Mutability :: Mut {
369- self . peel_off_references (
370- pat,
371- expected,
372- def_br,
373- Mutability :: Not ,
374- max_ref_mutbl,
375- )
376- } else {
377- ( expected, def_br. cap_ref_mutability ( Mutability :: Not ) , max_ref_mutbl)
378- } ;
379- ( new_ty, new_bm, max_ref_mutbl, false )
380- }
381- } else {
382- ( expected, ByRef :: No , max_ref_mutbl, mutbls_match)
383- }
384- }
332+ AdjustMode :: Pass => ( expected, def_br, max_ref_mutbl) ,
333+ AdjustMode :: Reset => ( expected, ByRef :: No , MutblCap :: Mut ) ,
385334 AdjustMode :: Peel => {
386335 let peeled =
387336 self . peel_off_references ( pat, expected, def_br, Mutability :: Mut , max_ref_mutbl) ;
388- ( peeled. 0 , peeled. 1 , peeled. 2 , false )
337+ ( peeled. 0 , peeled. 1 , peeled. 2 )
389338 }
390339 }
391340 }
@@ -431,17 +380,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
431380 // a reference type wherefore peeling doesn't give up any expressiveness.
432381 _ => AdjustMode :: Peel ,
433382 } ,
434- // When encountering a `& mut? pat` pattern, reset to "by value".
435- // This is so that `x` and `y` here are by value, as they appear to be:
436- //
437- // ```
438- // match &(&22, &44) {
439- // (&x, &y) => ...
440- // }
441- // ```
442- //
443- // See issue #46688.
444- PatKind :: Ref ( inner, mutbl) => AdjustMode :: ResetAndConsumeRef ( * mutbl, inner. span . find_ancestor_inside ( pat. span ) . map ( |end| pat. span . until ( end) ) ) ,
383+ // Ref patterns are complicated, we handle them in `check_pat_ref`.
384+ PatKind :: Ref ( ..) => AdjustMode :: Pass ,
445385 // A `_` pattern works with any expected type, so there's no need to do anything.
446386 PatKind :: Wild
447387 // A malformed pattern doesn't have an expected type, so let's just accept any type.
@@ -2177,99 +2117,138 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
21772117 & self ,
21782118 pat : & ' tcx Pat < ' tcx > ,
21792119 inner : & ' tcx Pat < ' tcx > ,
2180- mutbl : Mutability ,
2181- expected : Ty < ' tcx > ,
2182- pat_info : PatInfo < ' tcx , ' _ > ,
2183- consumed_inherited_ref : bool ,
2120+ pat_mutbl : Mutability ,
2121+ mut expected : Ty < ' tcx > ,
2122+ mut pat_info : PatInfo < ' tcx , ' _ > ,
21842123 ) -> Ty < ' tcx > {
2185- if consumed_inherited_ref
2186- && pat. span . at_least_rust_2024 ( )
2187- && self . tcx . features ( ) . ref_pat_eat_one_layer_2024
2188- {
2189- self . typeck_results . borrow_mut ( ) . skipped_ref_pats_mut ( ) . insert ( pat. hir_id ) ;
2190- self . check_pat ( inner, expected, pat_info) ;
2191- expected
2192- } else {
2193- let tcx = self . tcx ;
2194- let expected = self . shallow_resolve ( expected) ;
2195- let ( ref_ty, inner_ty, pat_info) = match self
2196- . check_dereferenceable ( pat. span , expected, inner)
2124+ // FIXME: repace with `bool` once final decision on 1 vs 2 layers is made
2125+ #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
2126+ enum MatchErgonomicsMode {
2127+ EatOneLayer ,
2128+ EatTwoLayers ,
2129+ Legacy ,
2130+ }
2131+
2132+ let match_ergonomics_mode =
2133+ if pat. span . at_least_rust_2024 ( ) && self . tcx . features ( ) . ref_pat_eat_one_layer_2024 {
2134+ MatchErgonomicsMode :: EatOneLayer
2135+ } else if self . tcx . features ( ) . ref_pat_everywhere {
2136+ MatchErgonomicsMode :: EatTwoLayers
2137+ } else {
2138+ MatchErgonomicsMode :: Legacy
2139+ } ;
2140+
2141+ let mut inherited_ref_mutbl_match = false ;
2142+ if match_ergonomics_mode != MatchErgonomicsMode :: Legacy {
2143+ if pat_mutbl == Mutability :: Not {
2144+ pat_info. max_ref_mutbl = pat_info. max_ref_mutbl . cap_to_weakly_not (
2145+ inner. span . find_ancestor_inside ( pat. span ) . map ( |end| pat. span . until ( end) ) ,
2146+ ) ;
2147+ }
2148+
2149+ if let ByRef :: Yes ( inh_mut) = pat_info. binding_mode {
2150+ inherited_ref_mutbl_match = pat_mutbl <= inh_mut;
2151+ }
2152+
2153+ if inherited_ref_mutbl_match {
2154+ pat_info. binding_mode = ByRef :: No ;
2155+ if match_ergonomics_mode == MatchErgonomicsMode :: EatOneLayer {
2156+ self . typeck_results . borrow_mut ( ) . skipped_ref_pats_mut ( ) . insert ( pat. hir_id ) ;
2157+ self . check_pat ( inner, expected, pat_info) ;
2158+ return expected;
2159+ }
2160+ } else if match_ergonomics_mode == MatchErgonomicsMode :: EatOneLayer
2161+ && pat_mutbl == Mutability :: Mut
21972162 {
2198- Ok ( ( ) ) => {
2199- // `demand::subtype` would be good enough, but using `eqtype` turns
2200- // out to be equally general. See (note_1) for details.
2201-
2202- // Take region, inner-type from expected type if we can,
2203- // to avoid creating needless variables. This also helps with
2204- // the bad interactions of the given hack detailed in (note_1).
2205- debug ! ( "check_pat_ref: expected={:?}" , expected) ;
2206- match * expected. kind ( ) {
2207- ty:: Ref ( _, r_ty, r_mutbl) if r_mutbl == mutbl => {
2208- let pat_info = if r_mutbl == Mutability :: Not
2209- && ( ( pat. span . at_least_rust_2024 ( )
2210- && self . tcx . features ( ) . ref_pat_eat_one_layer_2024 )
2211- || self . tcx . features ( ) . ref_pat_everywhere )
2212- {
2213- PatInfo { max_ref_mutbl : MutblCap :: Not , ..pat_info }
2214- } else {
2215- pat_info
2216- } ;
2217- ( expected, r_ty, pat_info)
2218- }
2163+ // `&mut` patterns pell off `&` references
2164+ let ( new_expected, new_bm, max_ref_mutbl) = self . peel_off_references (
2165+ pat,
2166+ expected,
2167+ pat_info. binding_mode ,
2168+ Mutability :: Not ,
2169+ pat_info. max_ref_mutbl ,
2170+ ) ;
2171+ expected = new_expected;
2172+ pat_info. binding_mode = new_bm;
2173+ pat_info. max_ref_mutbl = max_ref_mutbl;
2174+ }
2175+ } else {
2176+ // Reset binding mode on old editions
2177+ pat_info. binding_mode = ByRef :: No ;
2178+ pat_info. max_ref_mutbl = MutblCap :: Mut
2179+ }
22192180
2220- // `&` pattern eats `&mut` reference
2221- ty:: Ref ( _, r_ty, Mutability :: Mut )
2222- if mutbl == Mutability :: Not
2223- && ( ( pat. span . at_least_rust_2024 ( )
2224- && self . tcx . features ( ) . ref_pat_eat_one_layer_2024 )
2225- || self . tcx . features ( ) . ref_pat_everywhere ) =>
2181+ let tcx = self . tcx ;
2182+ expected = self . try_structurally_resolve_type ( pat. span , expected) ;
2183+ let ( ref_ty, inner_ty) = match self . check_dereferenceable ( pat. span , expected, inner) {
2184+ Ok ( ( ) ) => {
2185+ // `demand::subtype` would be good enough, but using `eqtype` turns
2186+ // out to be equally general. See (note_1) for details.
2187+
2188+ // Take region, inner-type from expected type if we can,
2189+ // to avoid creating needless variables. This also helps with
2190+ // the bad interactions of the given hack detailed in (note_1).
2191+ debug ! ( "check_pat_ref: expected={:?}" , expected) ;
2192+ match * expected. kind ( ) {
2193+ ty:: Ref ( _, r_ty, r_mutbl) if r_mutbl == pat_mutbl => {
2194+ if r_mutbl == Mutability :: Not
2195+ && match_ergonomics_mode != MatchErgonomicsMode :: Legacy
22262196 {
2227- ( expected , r_ty , pat_info )
2197+ pat_info . max_ref_mutbl = MutblCap :: Not ;
22282198 }
22292199
2230- _ if consumed_inherited_ref && self . tcx . features ( ) . ref_pat_everywhere => {
2231- // We already matched against a match-ergonmics inserted reference,
2232- // so we don't need to match against a reference from the original type.
2233- // Save this infor for use in lowering later
2234- self . typeck_results
2235- . borrow_mut ( )
2236- . skipped_ref_pats_mut ( )
2237- . insert ( pat. hir_id ) ;
2238- ( expected, expected, pat_info)
2239- }
2200+ ( expected, r_ty)
2201+ }
22402202
2241- _ => {
2242- let inner_ty = self . next_ty_var ( TypeVariableOrigin {
2243- param_def_id : None ,
2244- span : inner. span ,
2245- } ) ;
2246- let ref_ty = self . new_ref_ty ( pat. span , mutbl, inner_ty) ;
2247- debug ! ( "check_pat_ref: demanding {:?} = {:?}" , expected, ref_ty) ;
2248- let err = self . demand_eqtype_pat_diag (
2249- pat. span ,
2250- expected,
2251- ref_ty,
2252- pat_info. top_info ,
2253- ) ;
2203+ // `&` pattern eats `&mut` reference
2204+ ty:: Ref ( _, r_ty, Mutability :: Mut )
2205+ if pat_mutbl == Mutability :: Not
2206+ && match_ergonomics_mode != MatchErgonomicsMode :: Legacy =>
2207+ {
2208+ ( expected, r_ty)
2209+ }
22542210
2255- // Look for a case like `fn foo(&foo: u32)` and suggest
2256- // `fn foo(foo: &u32)`
2257- if let Some ( mut err) = err {
2258- self . borrow_pat_suggestion ( & mut err, pat) ;
2259- err. emit ( ) ;
2260- }
2261- ( ref_ty, inner_ty, pat_info)
2211+ _ if inherited_ref_mutbl_match
2212+ && match_ergonomics_mode == MatchErgonomicsMode :: EatTwoLayers =>
2213+ {
2214+ // We already matched against a match-ergonmics inserted reference,
2215+ // so we don't need to match against a reference from the original type.
2216+ // Save this info for use in lowering later
2217+ self . typeck_results . borrow_mut ( ) . skipped_ref_pats_mut ( ) . insert ( pat. hir_id ) ;
2218+ ( expected, expected)
2219+ }
2220+
2221+ _ => {
2222+ let inner_ty = self . next_ty_var ( TypeVariableOrigin {
2223+ param_def_id : None ,
2224+ span : inner. span ,
2225+ } ) ;
2226+ let ref_ty = self . new_ref_ty ( pat. span , pat_mutbl, inner_ty) ;
2227+ debug ! ( "check_pat_ref: demanding {:?} = {:?}" , expected, ref_ty) ;
2228+ let err = self . demand_eqtype_pat_diag (
2229+ pat. span ,
2230+ expected,
2231+ ref_ty,
2232+ pat_info. top_info ,
2233+ ) ;
2234+
2235+ // Look for a case like `fn foo(&foo: u32)` and suggest
2236+ // `fn foo(foo: &u32)`
2237+ if let Some ( mut err) = err {
2238+ self . borrow_pat_suggestion ( & mut err, pat) ;
2239+ err. emit ( ) ;
22622240 }
2241+ ( ref_ty, inner_ty)
22632242 }
22642243 }
2265- Err ( guar ) => {
2266- let err = Ty :: new_error ( tcx , guar) ;
2267- ( err , err , pat_info )
2268- }
2269- } ;
2270- self . check_pat ( inner , inner_ty , pat_info ) ;
2271- ref_ty
2272- }
2244+ }
2245+ Err ( guar) => {
2246+ let err = Ty :: new_error ( tcx , guar ) ;
2247+ ( err , err )
2248+ }
2249+ } ;
2250+ self . check_pat ( inner , inner_ty , pat_info ) ;
2251+ ref_ty
22732252 }
22742253
22752254 /// Create a reference type with a fresh region variable.
0 commit comments