@@ -131,14 +131,6 @@ enum AdjustMode {
131
131
/// Reset binding mode to the initial mode.
132
132
/// Used for destructuring assignment, where we don't want any match ergonomics.
133
133
Reset ,
134
- /// Produced by ref patterns.
135
- /// Reset the binding mode to the initial mode,
136
- /// and if the old biding mode was by-reference
137
- /// with mutability matching the pattern,
138
- /// mark the pattern as having consumed this reference.
139
- ///
140
- /// `Span` is that of the `&` or `&mut` itself.
141
- ResetAndConsumeRef ( Mutability , Option < Span > ) ,
142
134
/// Pass on the input binding mode and expected type.
143
135
Pass ,
144
136
}
@@ -170,13 +162,15 @@ enum MutblCap {
170
162
}
171
163
172
164
impl MutblCap {
165
+ #[ must_use]
173
166
fn cap_to_weakly_not ( self , span : Option < Span > ) -> Self {
174
167
match self {
175
168
MutblCap :: Not => MutblCap :: Not ,
176
169
_ => MutblCap :: WeaklyNot ( span) ,
177
170
}
178
171
}
179
172
173
+ #[ must_use]
180
174
fn as_mutbl ( self ) -> Mutability {
181
175
match self {
182
176
MutblCap :: Not | MutblCap :: WeaklyNot ( _) => Mutability :: Not ,
@@ -214,14 +208,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
214
208
}
215
209
216
210
/// Type check the given `pat` against the `expected` type
217
- /// with the provided `def_bm ` (default binding mode).
211
+ /// with the provided `binding_mode ` (default binding mode).
218
212
///
219
213
/// Outside of this module, `check_pat_top` should always be used.
220
214
/// Conversely, inside this module, `check_pat_top` should never be used.
221
215
#[ instrument( level = "debug" , skip( self , pat_info) ) ]
222
216
fn check_pat ( & self , pat : & ' tcx Pat < ' tcx > , expected : Ty < ' tcx > , pat_info : PatInfo < ' tcx , ' _ > ) {
223
- let PatInfo { binding_mode : def_bm, max_ref_mutbl, top_info : ti, current_depth, .. } =
224
- pat_info;
217
+ let PatInfo { binding_mode, max_ref_mutbl, top_info : ti, current_depth, .. } = pat_info;
225
218
226
219
let path_res = match & pat. kind {
227
220
PatKind :: Path ( qpath) => Some (
@@ -230,10 +223,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
230
223
_ => None ,
231
224
} ;
232
225
let adjust_mode = self . calc_adjust_mode ( pat, path_res. map ( |( res, ..) | res) ) ;
233
- let ( expected, def_bm , max_ref_mutbl, ref_pattern_already_consumed ) =
234
- self . calc_default_binding_mode ( pat, expected, def_bm , adjust_mode, max_ref_mutbl) ;
226
+ let ( expected, binding_mode , max_ref_mutbl) =
227
+ self . calc_default_binding_mode ( pat, expected, binding_mode , adjust_mode, max_ref_mutbl) ;
235
228
let pat_info = PatInfo {
236
- binding_mode : def_bm ,
229
+ binding_mode,
237
230
max_ref_mutbl,
238
231
top_info : ti,
239
232
decl_origin : pat_info. decl_origin ,
@@ -269,14 +262,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
269
262
}
270
263
PatKind :: Box ( inner) => self . check_pat_box ( pat. span , inner, expected, pat_info) ,
271
264
PatKind :: Deref ( inner) => self . check_pat_deref ( pat. span , inner, expected, pat_info) ,
272
- PatKind :: Ref ( inner, mutbl) => self . check_pat_ref (
273
- pat,
274
- inner,
275
- mutbl,
276
- expected,
277
- pat_info,
278
- ref_pattern_already_consumed,
279
- ) ,
265
+ PatKind :: Ref ( inner, mutbl) => self . check_pat_ref ( pat, inner, mutbl, expected, pat_info) ,
280
266
PatKind :: Slice ( before, slice, after) => {
281
267
self . check_pat_slice ( pat. span , before, slice, after, expected, pat_info)
282
268
}
@@ -329,61 +315,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
329
315
330
316
/// Compute the new expected type and default binding mode from the old ones
331
317
/// as well as the pattern form we are currently checking.
332
- ///
333
- /// Last entry is only relevant for ref patterns (`&` and `&mut`);
334
- /// if `true`, then the ref pattern consumed a match ergonomics inserted reference
335
- /// and so does no need to match against a reference in the scrutinee type.
336
318
fn calc_default_binding_mode (
337
319
& self ,
338
320
pat : & ' tcx Pat < ' tcx > ,
339
321
expected : Ty < ' tcx > ,
340
322
def_br : ByRef ,
341
323
adjust_mode : AdjustMode ,
342
324
max_ref_mutbl : MutblCap ,
343
- ) -> ( Ty < ' tcx > , ByRef , MutblCap , bool ) {
325
+ ) -> ( Ty < ' tcx > , ByRef , MutblCap ) {
344
326
if let ByRef :: Yes ( Mutability :: Mut ) = def_br {
345
327
debug_assert ! ( max_ref_mutbl == MutblCap :: Mut ) ;
346
328
}
347
329
match adjust_mode {
348
- AdjustMode :: Pass => ( expected, def_br, max_ref_mutbl, false ) ,
349
- AdjustMode :: Reset => ( expected, ByRef :: No , MutblCap :: Mut , false ) ,
350
- AdjustMode :: ResetAndConsumeRef ( ref_pat_mutbl, ref_span) => {
351
- // `&` pattern eats `&mut`
352
- let mutbls_match =
353
- if let ByRef :: Yes ( def_mut) = def_br { ref_pat_mutbl <= def_mut } else { false } ;
354
-
355
- if pat. span . at_least_rust_2024 ( ) && self . tcx . features ( ) . ref_pat_eat_one_layer_2024 {
356
- let max_ref_mutbl = if ref_pat_mutbl == Mutability :: Not {
357
- max_ref_mutbl. cap_to_weakly_not ( ref_span)
358
- } else {
359
- max_ref_mutbl
360
- } ;
361
-
362
- if mutbls_match {
363
- debug ! ( "consuming inherited reference" ) ;
364
- ( expected, ByRef :: No , max_ref_mutbl, true )
365
- } else {
366
- let ( new_ty, new_bm, max_ref_mutbl) = if ref_pat_mutbl == Mutability :: Mut {
367
- self . peel_off_references (
368
- pat,
369
- expected,
370
- def_br,
371
- Mutability :: Not ,
372
- max_ref_mutbl,
373
- )
374
- } else {
375
- ( expected, def_br. cap_ref_mutability ( Mutability :: Not ) , max_ref_mutbl)
376
- } ;
377
- ( new_ty, new_bm, max_ref_mutbl, false )
378
- }
379
- } else {
380
- ( expected, ByRef :: No , max_ref_mutbl, mutbls_match)
381
- }
382
- }
330
+ AdjustMode :: Pass => ( expected, def_br, max_ref_mutbl) ,
331
+ AdjustMode :: Reset => ( expected, ByRef :: No , MutblCap :: Mut ) ,
383
332
AdjustMode :: Peel => {
384
- let peeled =
385
- self . peel_off_references ( pat, expected, def_br, Mutability :: Mut , max_ref_mutbl) ;
386
- ( peeled. 0 , peeled. 1 , peeled. 2 , false )
333
+ self . peel_off_references ( pat, expected, def_br, Mutability :: Mut , max_ref_mutbl)
387
334
}
388
335
}
389
336
}
@@ -429,17 +376,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
429
376
// a reference type wherefore peeling doesn't give up any expressiveness.
430
377
_ => AdjustMode :: Peel ,
431
378
} ,
432
- // When encountering a `& mut? pat` pattern, reset to "by value".
433
- // This is so that `x` and `y` here are by value, as they appear to be:
434
- //
435
- // ```
436
- // match &(&22, &44) {
437
- // (&x, &y) => ...
438
- // }
439
- // ```
440
- //
441
- // See issue #46688.
442
- PatKind :: Ref ( inner, mutbl) => AdjustMode :: ResetAndConsumeRef ( * mutbl, inner. span . find_ancestor_inside ( pat. span ) . map ( |end| pat. span . until ( end) ) ) ,
379
+ // Ref patterns are complicated, we handle them in `check_pat_ref`.
380
+ PatKind :: Ref ( ..) => AdjustMode :: Pass ,
443
381
// A `_` pattern works with any expected type, so there's no need to do anything.
444
382
PatKind :: Wild
445
383
// A malformed pattern doesn't have an expected type, so let's just accept any type.
@@ -2179,96 +2117,135 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2179
2117
& self ,
2180
2118
pat : & ' tcx Pat < ' tcx > ,
2181
2119
inner : & ' tcx Pat < ' tcx > ,
2182
- mutbl : Mutability ,
2183
- expected : Ty < ' tcx > ,
2184
- pat_info : PatInfo < ' tcx , ' _ > ,
2185
- consumed_inherited_ref : bool ,
2120
+ pat_mutbl : Mutability ,
2121
+ mut expected : Ty < ' tcx > ,
2122
+ mut pat_info : PatInfo < ' tcx , ' _ > ,
2186
2123
) -> Ty < ' tcx > {
2187
- if consumed_inherited_ref
2188
- && pat. span . at_least_rust_2024 ( )
2189
- && self . tcx . features ( ) . ref_pat_eat_one_layer_2024
2190
- {
2191
- self . typeck_results . borrow_mut ( ) . skipped_ref_pats_mut ( ) . insert ( pat. hir_id ) ;
2192
- self . check_pat ( inner, expected, pat_info) ;
2193
- expected
2194
- } else {
2195
- let tcx = self . tcx ;
2196
- let expected = self . shallow_resolve ( expected) ;
2197
- let ( ref_ty, inner_ty, pat_info) = match self
2198
- . 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
2199
2162
{
2200
- Ok ( ( ) ) => {
2201
- // `demand::subtype` would be good enough, but using `eqtype` turns
2202
- // out to be equally general. See (note_1) for details.
2203
-
2204
- // Take region, inner-type from expected type if we can,
2205
- // to avoid creating needless variables. This also helps with
2206
- // the bad interactions of the given hack detailed in (note_1).
2207
- debug ! ( "check_pat_ref: expected={:?}" , expected) ;
2208
- match * expected. kind ( ) {
2209
- ty:: Ref ( _, r_ty, r_mutbl) if r_mutbl == mutbl => {
2210
- let pat_info = if r_mutbl == Mutability :: Not
2211
- && ( ( pat. span . at_least_rust_2024 ( )
2212
- && self . tcx . features ( ) . ref_pat_eat_one_layer_2024 )
2213
- || self . tcx . features ( ) . ref_pat_everywhere )
2214
- {
2215
- PatInfo { max_ref_mutbl : MutblCap :: Not , ..pat_info }
2216
- } else {
2217
- pat_info
2218
- } ;
2219
- ( expected, r_ty, pat_info)
2220
- }
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
+ }
2221
2180
2222
- // `&` pattern eats `&mut` reference
2223
- ty:: Ref ( _, r_ty, Mutability :: Mut )
2224
- if mutbl == Mutability :: Not
2225
- && ( ( pat. span . at_least_rust_2024 ( )
2226
- && self . tcx . features ( ) . ref_pat_eat_one_layer_2024 )
2227
- || 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
2228
2196
{
2229
- ( expected , r_ty , pat_info )
2197
+ pat_info . max_ref_mutbl = MutblCap :: Not ;
2230
2198
}
2231
2199
2232
- _ if consumed_inherited_ref && self . tcx . features ( ) . ref_pat_everywhere => {
2233
- // We already matched against a match-ergonmics inserted reference,
2234
- // so we don't need to match against a reference from the original type.
2235
- // Save this infor for use in lowering later
2236
- self . typeck_results
2237
- . borrow_mut ( )
2238
- . skipped_ref_pats_mut ( )
2239
- . insert ( pat. hir_id ) ;
2240
- ( expected, expected, pat_info)
2241
- }
2200
+ ( expected, r_ty)
2201
+ }
2242
2202
2243
- _ => {
2244
- let inner_ty = self . next_ty_var ( inner. span ) ;
2245
- let ref_ty = self . new_ref_ty ( pat. span , mutbl, inner_ty) ;
2246
- debug ! ( "check_pat_ref: demanding {:?} = {:?}" , expected, ref_ty) ;
2247
- let err = self . demand_eqtype_pat_diag (
2248
- pat. span ,
2249
- expected,
2250
- ref_ty,
2251
- pat_info. top_info ,
2252
- ) ;
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
+ }
2253
2210
2254
- // Look for a case like `fn foo(&foo: u32)` and suggest
2255
- // `fn foo(foo: &u32)`
2256
- if let Some ( mut err) = err {
2257
- self . borrow_pat_suggestion ( & mut err, pat) ;
2258
- err. emit ( ) ;
2259
- }
2260
- ( 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 ( inner. span ) ;
2223
+ let ref_ty = self . new_ref_ty ( pat. span , pat_mutbl, inner_ty) ;
2224
+ debug ! ( "check_pat_ref: demanding {:?} = {:?}" , expected, ref_ty) ;
2225
+ let err = self . demand_eqtype_pat_diag (
2226
+ pat. span ,
2227
+ expected,
2228
+ ref_ty,
2229
+ pat_info. top_info ,
2230
+ ) ;
2231
+
2232
+ // Look for a case like `fn foo(&foo: u32)` and suggest
2233
+ // `fn foo(foo: &u32)`
2234
+ if let Some ( mut err) = err {
2235
+ self . borrow_pat_suggestion ( & mut err, pat) ;
2236
+ err. emit ( ) ;
2261
2237
}
2238
+ ( ref_ty, inner_ty)
2262
2239
}
2263
2240
}
2264
- Err ( guar ) => {
2265
- let err = Ty :: new_error ( tcx , guar) ;
2266
- ( err , err , pat_info )
2267
- }
2268
- } ;
2269
- self . check_pat ( inner , inner_ty , pat_info ) ;
2270
- ref_ty
2271
- }
2241
+ }
2242
+ Err ( guar) => {
2243
+ let err = Ty :: new_error ( tcx , guar ) ;
2244
+ ( err , err )
2245
+ }
2246
+ } ;
2247
+ self . check_pat ( inner , inner_ty , pat_info ) ;
2248
+ ref_ty
2272
2249
}
2273
2250
2274
2251
/// Create a reference type with a fresh region variable.
0 commit comments