@@ -133,14 +133,6 @@ enum AdjustMode {
133
133
/// Reset binding mode to the initial mode.
134
134
/// Used for destructuring assignment, where we don't want any match ergonomics.
135
135
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 > ) ,
144
136
/// Pass on the input binding mode and expected type.
145
137
Pass ,
146
138
}
@@ -172,13 +164,15 @@ enum MutblCap {
172
164
}
173
165
174
166
impl MutblCap {
167
+ #[ must_use]
175
168
fn cap_to_weakly_not ( self , span : Option < Span > ) -> Self {
176
169
match self {
177
170
MutblCap :: Not => MutblCap :: Not ,
178
171
_ => MutblCap :: WeaklyNot ( span) ,
179
172
}
180
173
}
181
174
175
+ #[ must_use]
182
176
fn as_mutbl ( self ) -> Mutability {
183
177
match self {
184
178
MutblCap :: Not | MutblCap :: WeaklyNot ( _) => Mutability :: Not ,
@@ -216,14 +210,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
216
210
}
217
211
218
212
/// 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).
220
214
///
221
215
/// Outside of this module, `check_pat_top` should always be used.
222
216
/// Conversely, inside this module, `check_pat_top` should never be used.
223
217
#[ instrument( level = "debug" , skip( self , pat_info) ) ]
224
218
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;
227
220
228
221
let path_res = match & pat. kind {
229
222
PatKind :: Path ( qpath) => Some (
@@ -232,10 +225,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
232
225
_ => None ,
233
226
} ;
234
227
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) ;
237
230
let pat_info = PatInfo {
238
- binding_mode : def_bm ,
231
+ binding_mode,
239
232
max_ref_mutbl,
240
233
top_info : ti,
241
234
decl_origin : pat_info. decl_origin ,
@@ -271,14 +264,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
271
264
}
272
265
PatKind :: Box ( inner) => self . check_pat_box ( pat. span , inner, expected, pat_info) ,
273
266
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) ,
282
268
PatKind :: Slice ( before, slice, after) => {
283
269
self . check_pat_slice ( pat. span , before, slice, after, expected, pat_info)
284
270
}
@@ -331,61 +317,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
331
317
332
318
/// Compute the new expected type and default binding mode from the old ones
333
319
/// 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.
338
320
fn calc_default_binding_mode (
339
321
& self ,
340
322
pat : & ' tcx Pat < ' tcx > ,
341
323
expected : Ty < ' tcx > ,
342
324
def_br : ByRef ,
343
325
adjust_mode : AdjustMode ,
344
326
max_ref_mutbl : MutblCap ,
345
- ) -> ( Ty < ' tcx > , ByRef , MutblCap , bool ) {
327
+ ) -> ( Ty < ' tcx > , ByRef , MutblCap ) {
346
328
if let ByRef :: Yes ( Mutability :: Mut ) = def_br {
347
329
debug_assert ! ( max_ref_mutbl == MutblCap :: Mut ) ;
348
330
}
349
331
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 ) ,
385
334
AdjustMode :: Peel => {
386
335
let peeled =
387
336
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 )
389
338
}
390
339
}
391
340
}
@@ -431,17 +380,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
431
380
// a reference type wherefore peeling doesn't give up any expressiveness.
432
381
_ => AdjustMode :: Peel ,
433
382
} ,
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 ,
445
385
// A `_` pattern works with any expected type, so there's no need to do anything.
446
386
PatKind :: Wild
447
387
// 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> {
2177
2117
& self ,
2178
2118
pat : & ' tcx Pat < ' tcx > ,
2179
2119
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 , ' _ > ,
2184
2123
) -> 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
2197
2162
{
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
+ }
2219
2180
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
2226
2196
{
2227
- ( expected , r_ty , pat_info )
2197
+ pat_info . max_ref_mutbl = MutblCap :: Not ;
2228
2198
}
2229
2199
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
+ }
2240
2202
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
+ }
2254
2210
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 ( ) ;
2262
2240
}
2241
+ ( ref_ty, inner_ty)
2263
2242
}
2264
2243
}
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
2273
2252
}
2274
2253
2275
2254
/// Create a reference type with a fresh region variable.
0 commit comments