@@ -78,7 +78,7 @@ struct TopInfo<'tcx> {
78
78
#[ derive( Copy , Clone ) ]
79
79
struct PatInfo < ' tcx , ' a > {
80
80
binding_mode : ByRef ,
81
- max_ref_mutbl : Mutability ,
81
+ max_ref_mutbl : MutblCap ,
82
82
top_info : TopInfo < ' tcx > ,
83
83
decl_origin : Option < DeclOrigin < ' a > > ,
84
84
@@ -124,6 +124,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
124
124
}
125
125
126
126
/// Mode for adjusting the expected type and binding mode.
127
+ #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
127
128
enum AdjustMode {
128
129
/// Peel off all immediate reference types.
129
130
Peel ,
@@ -135,11 +136,44 @@ enum AdjustMode {
135
136
/// and if the old biding mode was by-reference
136
137
/// with mutability matching the pattern,
137
138
/// mark the pattern as having consumed this reference.
138
- ResetAndConsumeRef ( Mutability ) ,
139
+ ///
140
+ /// `Span` is that of the inside of the reference pattern
141
+ ResetAndConsumeRef ( Mutability , Span ) ,
139
142
/// Pass on the input binding mode and expected type.
140
143
Pass ,
141
144
}
142
145
146
+ /// `ref mut` patterns (explicit or match-ergonomics)
147
+ /// are not allowed behind an `&` reference.
148
+ ///
149
+ /// This includes explicit `ref mut` behind `&` patterns
150
+ /// that match against `&mut` references,
151
+ /// where the code would have compiled
152
+ /// had the pattern been written as `&mut`.
153
+ /// However, the borrow checker will not catch
154
+ /// this last case, so we need to throw an error ourselves.
155
+ #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
156
+ enum MutblCap {
157
+ /// Mutability restricted to immutable;
158
+ /// contained span, if present, should be shown in diagnostics as the reason.
159
+ Not ( Option < Span > ) ,
160
+ /// No restriction on mutability
161
+ Mut ,
162
+ }
163
+
164
+ impl MutblCap {
165
+ fn cap_mutbl_to_not ( self , span : Option < Span > ) -> Self {
166
+ if self == MutblCap :: Mut { MutblCap :: Not ( span) } else { self }
167
+ }
168
+
169
+ fn as_mutbl ( self ) -> Mutability {
170
+ match self {
171
+ MutblCap :: Not ( _) => Mutability :: Not ,
172
+ MutblCap :: Mut => Mutability :: Mut ,
173
+ }
174
+ }
175
+ }
176
+
143
177
impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
144
178
/// Type check the given top level pattern against the `expected` type.
145
179
///
@@ -160,7 +194,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
160
194
let info = TopInfo { expected, origin_expr, span } ;
161
195
let pat_info = PatInfo {
162
196
binding_mode : ByRef :: No ,
163
- max_ref_mutbl : Mutability :: Mut ,
197
+ max_ref_mutbl : MutblCap :: Mut ,
164
198
top_info : info,
165
199
decl_origin,
166
200
current_depth : 0 ,
@@ -201,8 +235,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
201
235
PatKind :: Never => expected,
202
236
PatKind :: Lit ( lt) => self . check_pat_lit ( pat. span , lt, expected, ti) ,
203
237
PatKind :: Range ( lhs, rhs, _) => self . check_pat_range ( pat. span , lhs, rhs, expected, ti) ,
204
- PatKind :: Binding ( ba, var_id, _ , sub) => {
205
- self . check_pat_ident ( pat, ba, var_id, sub, expected, pat_info)
238
+ PatKind :: Binding ( ba, var_id, ident , sub) => {
239
+ self . check_pat_ident ( pat, ba, var_id, ident , sub, expected, pat_info)
206
240
}
207
241
PatKind :: TupleStruct ( ref qpath, subpats, ddpos) => {
208
242
self . check_pat_tuple_struct ( pat, qpath, subpats, ddpos, expected, pat_info)
@@ -294,20 +328,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
294
328
expected : Ty < ' tcx > ,
295
329
def_br : ByRef ,
296
330
adjust_mode : AdjustMode ,
297
- max_ref_mutbl : Mutability ,
298
- ) -> ( Ty < ' tcx > , ByRef , Mutability , bool ) {
299
- if let ByRef :: Yes ( mutbl ) = def_br {
300
- debug_assert ! ( mutbl <= max_ref_mutbl ) ;
331
+ max_ref_mutbl : MutblCap ,
332
+ ) -> ( Ty < ' tcx > , ByRef , MutblCap , bool ) {
333
+ if let ByRef :: Yes ( Mutability :: Mut ) = def_br {
334
+ debug_assert ! ( max_ref_mutbl == MutblCap :: Mut ) ;
301
335
}
302
336
match adjust_mode {
303
337
AdjustMode :: Pass => ( expected, def_br, max_ref_mutbl, false ) ,
304
- AdjustMode :: Reset => ( expected, ByRef :: No , Mutability :: Mut , false ) ,
305
- AdjustMode :: ResetAndConsumeRef ( ref_pat_mutbl) => {
306
- let mutbls_match = def_br == ByRef :: Yes ( ref_pat_mutbl) ;
338
+ AdjustMode :: Reset => ( expected, ByRef :: No , MutblCap :: Mut , false ) ,
339
+ AdjustMode :: ResetAndConsumeRef ( ref_pat_mutbl, inner_span) => {
340
+ // `&` pattern eats `&mut`
341
+ let mutbls_match =
342
+ if let ByRef :: Yes ( def_mut) = def_br { ref_pat_mutbl <= def_mut } else { false } ;
343
+
307
344
if pat. span . at_least_rust_2024 ( ) && self . tcx . features ( ) . ref_pat_eat_one_layer_2024 {
345
+ let max_ref_mutbl = if ref_pat_mutbl == Mutability :: Not {
346
+ max_ref_mutbl. cap_mutbl_to_not ( Some ( pat. span . until ( inner_span) ) )
347
+ } else {
348
+ max_ref_mutbl
349
+ } ;
350
+
308
351
if mutbls_match {
309
352
debug ! ( "consuming inherited reference" ) ;
310
- ( expected, ByRef :: No , cmp :: min ( max_ref_mutbl, ref_pat_mutbl ) , true )
353
+ ( expected, ByRef :: No , max_ref_mutbl, true )
311
354
} else {
312
355
let ( new_ty, new_bm, max_ref_mutbl) = if ref_pat_mutbl == Mutability :: Mut {
313
356
self . peel_off_references (
@@ -318,7 +361,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
318
361
max_ref_mutbl,
319
362
)
320
363
} else {
321
- ( expected, def_br. cap_ref_mutability ( Mutability :: Not ) , Mutability :: Not )
364
+ ( expected, def_br. cap_ref_mutability ( Mutability :: Not ) , max_ref_mutbl )
322
365
} ;
323
366
( new_ty, new_bm, max_ref_mutbl, false )
324
367
}
@@ -385,7 +428,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
385
428
// ```
386
429
//
387
430
// See issue #46688.
388
- PatKind :: Ref ( _ , mutbl) => AdjustMode :: ResetAndConsumeRef ( * mutbl) ,
431
+ PatKind :: Ref ( inner , mutbl) => AdjustMode :: ResetAndConsumeRef ( * mutbl, inner . span ) ,
389
432
// A `_` pattern works with any expected type, so there's no need to do anything.
390
433
PatKind :: Wild
391
434
// A malformed pattern doesn't have an expected type, so let's just accept any type.
@@ -411,8 +454,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
411
454
expected : Ty < ' tcx > ,
412
455
mut def_br : ByRef ,
413
456
max_peelable_mutability : Mutability ,
414
- mut max_ref_mutability : Mutability ,
415
- ) -> ( Ty < ' tcx > , ByRef , Mutability ) {
457
+ mut max_ref_mutability : MutblCap ,
458
+ ) -> ( Ty < ' tcx > , ByRef , MutblCap ) {
416
459
let mut expected = self . try_structurally_resolve_type ( pat. span , expected) ;
417
460
// Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
418
461
// for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
@@ -446,9 +489,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
446
489
}
447
490
448
491
if pat. span . at_least_rust_2024 ( ) && self . tcx . features ( ) . ref_pat_eat_one_layer_2024 {
449
- def_br = def_br. cap_ref_mutability ( max_ref_mutability) ;
492
+ def_br = def_br. cap_ref_mutability ( max_ref_mutability. as_mutbl ( ) ) ;
450
493
if def_br == ByRef :: Yes ( Mutability :: Not ) {
451
- max_ref_mutability = Mutability :: Not ;
494
+ max_ref_mutability = max_ref_mutability . cap_mutbl_to_not ( None ) ;
452
495
}
453
496
}
454
497
@@ -665,16 +708,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
665
708
fn check_pat_ident (
666
709
& self ,
667
710
pat : & ' tcx Pat < ' tcx > ,
668
- ba : BindingMode ,
711
+ explicit_ba : BindingMode ,
669
712
var_id : HirId ,
713
+ ident : Ident ,
670
714
sub : Option < & ' tcx Pat < ' tcx > > ,
671
715
expected : Ty < ' tcx > ,
672
716
pat_info : PatInfo < ' tcx , ' _ > ,
673
717
) -> Ty < ' tcx > {
674
718
let PatInfo { binding_mode : def_br, top_info : ti, .. } = pat_info;
675
719
676
720
// Determine the binding mode...
677
- let bm = match ba {
721
+ let bm = match explicit_ba {
678
722
BindingMode ( ByRef :: No , Mutability :: Mut )
679
723
if !( pat. span . at_least_rust_2024 ( )
680
724
&& self . tcx . features ( ) . mut_preserve_binding_mode_2024 )
@@ -690,8 +734,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
690
734
BindingMode ( ByRef :: No , Mutability :: Mut )
691
735
}
692
736
BindingMode ( ByRef :: No , mutbl) => BindingMode ( def_br, mutbl) ,
693
- BindingMode ( ByRef :: Yes ( _) , _) => ba ,
737
+ BindingMode ( ByRef :: Yes ( _) , _) => explicit_ba ,
694
738
} ;
739
+
740
+ if bm. 0 == ByRef :: Yes ( Mutability :: Mut )
741
+ && let MutblCap :: Not ( Some ( and_pat_span) ) = pat_info. max_ref_mutbl
742
+ {
743
+ let mut err = struct_span_code_err ! (
744
+ self . tcx. dcx( ) ,
745
+ ident. span,
746
+ E0596 ,
747
+ "cannot bind with `ref mut` behind an `&` pattern"
748
+ ) ;
749
+ err. span_help ( and_pat_span, "change this `&` pattern to an `&mut`" ) ;
750
+ err. emit ( ) ;
751
+ }
752
+
695
753
// ...and store it in a side table:
696
754
self . typeck_results . borrow_mut ( ) . pat_binding_modes_mut ( ) . insert ( pat. hir_id , bm) ;
697
755
@@ -717,7 +775,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
717
775
// If there are multiple arms, make sure they all agree on
718
776
// what the type of the binding `x` ought to be.
719
777
if var_id != pat. hir_id {
720
- self . check_binding_alt_eq_ty ( ba , pat. span , var_id, local_ty, ti) ;
778
+ self . check_binding_alt_eq_ty ( explicit_ba , pat. span , var_id, local_ty, ti) ;
721
779
}
722
780
723
781
if let Some ( p) = sub {
@@ -2117,7 +2175,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2117
2175
} else {
2118
2176
let tcx = self . tcx ;
2119
2177
let expected = self . shallow_resolve ( expected) ;
2120
- let ( ref_ty, inner_ty) = match self . check_dereferenceable ( pat. span , expected, inner) {
2178
+ let ( ref_ty, inner_ty, pat_info) = match self
2179
+ . check_dereferenceable ( pat. span , expected, inner)
2180
+ {
2121
2181
Ok ( ( ) ) => {
2122
2182
// `demand::subtype` would be good enough, but using `eqtype` turns
2123
2183
// out to be equally general. See (note_1) for details.
@@ -2127,42 +2187,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2127
2187
// the bad interactions of the given hack detailed in (note_1).
2128
2188
debug ! ( "check_pat_ref: expected={:?}" , expected) ;
2129
2189
match * expected. kind ( ) {
2130
- ty:: Ref ( _, r_ty, r_mutbl) if r_mutbl == mutbl => ( expected, r_ty) ,
2190
+ ty:: Ref ( _, r_ty, r_mutbl) if r_mutbl == mutbl => ( expected, r_ty, pat_info) ,
2191
+
2192
+ // `&` pattern eats `&mut` reference
2193
+ ty:: Ref ( _, r_ty, Mutability :: Mut )
2194
+ if mutbl == Mutability :: Not
2195
+ && ( ( pat. span . at_least_rust_2024 ( )
2196
+ && self . tcx . features ( ) . ref_pat_eat_one_layer_2024 )
2197
+ || self . tcx . features ( ) . ref_pat_everywhere ) =>
2198
+ {
2199
+ (
2200
+ expected,
2201
+ r_ty,
2202
+ PatInfo {
2203
+ max_ref_mutbl : pat_info
2204
+ . max_ref_mutbl
2205
+ . cap_mutbl_to_not ( Some ( pat. span . until ( inner. span ) ) ) ,
2206
+ ..pat_info
2207
+ } ,
2208
+ )
2209
+ }
2210
+
2211
+ _ if consumed_inherited_ref && self . tcx . features ( ) . ref_pat_everywhere => {
2212
+ // We already matched against a match-ergonmics inserted reference,
2213
+ // so we don't need to match against a reference from the original type.
2214
+ // Save this infor for use in lowering later
2215
+ self . typeck_results
2216
+ . borrow_mut ( )
2217
+ . skipped_ref_pats_mut ( )
2218
+ . insert ( pat. hir_id ) ;
2219
+ ( expected, expected, pat_info)
2220
+ }
2221
+
2131
2222
_ => {
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 ( inner. span ) ;
2143
- let ref_ty = self . new_ref_ty ( pat. span , mutbl, inner_ty) ;
2144
- debug ! ( "check_pat_ref: demanding {:?} = {:?}" , expected, ref_ty) ;
2145
- let err = self . demand_eqtype_pat_diag (
2146
- pat. span ,
2147
- expected,
2148
- ref_ty,
2149
- pat_info. top_info ,
2150
- ) ;
2223
+ let inner_ty = self . next_ty_var ( inner. span ) ;
2224
+ let ref_ty = self . new_ref_ty ( pat. span , mutbl, inner_ty) ;
2225
+ debug ! ( "check_pat_ref: demanding {:?} = {:?}" , expected, ref_ty) ;
2226
+ let err = self . demand_eqtype_pat_diag (
2227
+ pat. span ,
2228
+ expected,
2229
+ ref_ty,
2230
+ pat_info. top_info ,
2231
+ ) ;
2151
2232
2152
- // Look for a case like `fn foo(&foo: u32)` and suggest
2153
- // `fn foo(foo: &u32)`
2154
- if let Some ( mut err) = err {
2155
- self . borrow_pat_suggestion ( & mut err, pat) ;
2156
- err. emit ( ) ;
2157
- }
2158
- ( ref_ty, inner_ty)
2233
+ // Look for a case like `fn foo(&foo: u32)` and suggest
2234
+ // `fn foo(foo: &u32)`
2235
+ if let Some ( mut err) = err {
2236
+ self . borrow_pat_suggestion ( & mut err, pat) ;
2237
+ err. emit ( ) ;
2159
2238
}
2239
+ ( ref_ty, inner_ty, pat_info)
2160
2240
}
2161
2241
}
2162
2242
}
2163
2243
Err ( guar) => {
2164
2244
let err = Ty :: new_error ( tcx, guar) ;
2165
- ( err, err)
2245
+ ( err, err, pat_info )
2166
2246
}
2167
2247
} ;
2168
2248
self . check_pat ( inner, inner_ty, pat_info) ;
0 commit comments