@@ -12,7 +12,7 @@ use rustc_infer::infer;
12
12
use rustc_middle:: mir:: interpret:: ErrorHandled ;
13
13
use rustc_middle:: ty:: { self , Ty , TypeVisitableExt } ;
14
14
use rustc_middle:: { bug, span_bug} ;
15
- use rustc_session:: lint:: builtin:: NON_EXHAUSTIVE_OMITTED_PATTERNS ;
15
+ use rustc_session:: { lint:: builtin:: NON_EXHAUSTIVE_OMITTED_PATTERNS , parse :: feature_err } ;
16
16
use rustc_span:: edit_distance:: find_best_match_for_name;
17
17
use rustc_span:: hygiene:: DesugaringKind ;
18
18
use rustc_span:: source_map:: Spanned ;
@@ -335,9 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
335
335
match adjust_mode {
336
336
AdjustMode :: Pass => ( expected, def_br, max_ref_mutbl) ,
337
337
AdjustMode :: Reset => ( expected, ByRef :: No , MutblCap :: Mut ) ,
338
- AdjustMode :: Peel => {
339
- self . peel_off_references ( pat, expected, def_br, Mutability :: Mut , max_ref_mutbl)
340
- }
338
+ AdjustMode :: Peel => self . peel_off_references ( pat, expected, def_br, max_ref_mutbl) ,
341
339
}
342
340
}
343
341
@@ -408,8 +406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
408
406
pat : & ' tcx Pat < ' tcx > ,
409
407
expected : Ty < ' tcx > ,
410
408
mut def_br : ByRef ,
411
- max_peelable_mutability : Mutability ,
412
- mut max_ref_mutability : MutblCap ,
409
+ mut max_ref_mutbl : MutblCap ,
413
410
) -> ( Ty < ' tcx > , ByRef , MutblCap ) {
414
411
let mut expected = self . try_structurally_resolve_type ( pat. span , expected) ;
415
412
// Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
@@ -421,9 +418,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
421
418
//
422
419
// See the examples in `ui/match-defbm*.rs`.
423
420
let mut pat_adjustments = vec ! [ ] ;
424
- while let ty:: Ref ( _, inner_ty, inner_mutability) = * expected. kind ( )
425
- && inner_mutability <= max_peelable_mutability
426
- {
421
+ while let ty:: Ref ( _, inner_ty, inner_mutability) = * expected. kind ( ) {
427
422
debug ! ( "inspecting {:?}" , expected) ;
428
423
429
424
debug ! ( "current discriminant is Ref, inserting implicit deref" ) ;
@@ -443,10 +438,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
443
438
} ) ;
444
439
}
445
440
446
- if pat . span . at_least_rust_2024 ( ) && self . tcx . features ( ) . ref_pat_eat_one_layer_2024 {
447
- def_br = def_br. cap_ref_mutability ( max_ref_mutability . as_mutbl ( ) ) ;
441
+ if self . tcx . features ( ) . ref_pat_eat_one_layer_2024 {
442
+ def_br = def_br. cap_ref_mutability ( max_ref_mutbl . as_mutbl ( ) ) ;
448
443
if def_br == ByRef :: Yes ( Mutability :: Not ) {
449
- max_ref_mutability = MutblCap :: Not ;
444
+ max_ref_mutbl = MutblCap :: Not ;
450
445
}
451
446
}
452
447
@@ -458,7 +453,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
458
453
. insert ( pat. hir_id , pat_adjustments) ;
459
454
}
460
455
461
- ( expected, def_br, max_ref_mutability )
456
+ ( expected, def_br, max_ref_mutbl )
462
457
}
463
458
464
459
fn check_pat_lit (
@@ -674,17 +669,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
674
669
675
670
// Determine the binding mode...
676
671
let bm = match user_bind_annot {
677
- // `mut` resets binding mode on edition <= 2021
678
- BindingMode ( ByRef :: No , Mutability :: Mut )
679
- if !( pat. span . at_least_rust_2024 ( )
680
- && self . tcx . features ( ) . mut_preserve_binding_mode_2024 )
681
- && matches ! ( def_br, ByRef :: Yes ( _) ) =>
682
- {
683
- self . typeck_results
684
- . borrow_mut ( )
685
- . rust_2024_migration_desugared_pats_mut ( )
686
- . insert ( pat_info. top_info . hir_id ) ;
687
- BindingMode ( ByRef :: No , Mutability :: Mut )
672
+ BindingMode ( ByRef :: No , Mutability :: Mut ) if matches ! ( def_br, ByRef :: Yes ( _) ) => {
673
+ if pat. span . at_least_rust_2024 ( ) && self . tcx . features ( ) . ref_pat_eat_one_layer_2024 {
674
+ if !self . tcx . features ( ) . mut_ref {
675
+ feature_err (
676
+ & self . tcx . sess ,
677
+ sym:: mut_ref,
678
+ pat. span . until ( ident. span ) ,
679
+ "binding cannot be both mutable and by-reference" ,
680
+ )
681
+ . emit ( ) ;
682
+ }
683
+
684
+ BindingMode ( def_br, Mutability :: Mut )
685
+ } else {
686
+ // `mut` resets binding mode on edition <= 2021
687
+ self . typeck_results
688
+ . borrow_mut ( )
689
+ . rust_2024_migration_desugared_pats_mut ( )
690
+ . insert ( pat_info. top_info . hir_id ) ;
691
+ BindingMode ( ByRef :: No , Mutability :: Mut )
692
+ }
688
693
}
689
694
BindingMode ( ByRef :: No , mutbl) => BindingMode ( def_br, mutbl) ,
690
695
BindingMode ( ByRef :: Yes ( _) , _) => user_bind_annot,
@@ -2126,57 +2131,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2126
2131
mut expected : Ty < ' tcx > ,
2127
2132
mut pat_info : PatInfo < ' tcx , ' _ > ,
2128
2133
) -> Ty < ' tcx > {
2129
- // FIXME: repace with `bool` once final decision on 1 vs 2 layers is made
2130
- #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
2131
- enum MatchErgonomicsMode {
2132
- EatOneLayer ,
2133
- EatTwoLayers ,
2134
- Legacy ,
2135
- }
2134
+ let no_ref_mut_behind_and = self . tcx . features ( ) . ref_pat_eat_one_layer_2024 ;
2135
+ let new_match_ergonomics = pat. span . at_least_rust_2024 ( ) && no_ref_mut_behind_and;
2136
2136
2137
- let match_ergonomics_mode =
2138
- if pat. span . at_least_rust_2024 ( ) && self . tcx . features ( ) . ref_pat_eat_one_layer_2024 {
2139
- MatchErgonomicsMode :: EatOneLayer
2140
- } else if self . tcx . features ( ) . ref_pat_everywhere {
2141
- MatchErgonomicsMode :: EatTwoLayers
2142
- } else {
2143
- MatchErgonomicsMode :: Legacy
2144
- } ;
2137
+ let pat_prefix_span =
2138
+ inner. span . find_ancestor_inside ( pat. span ) . map ( |end| pat. span . until ( end) ) ;
2145
2139
2146
- let mut inherited_ref_mutbl_match = false ;
2147
- if match_ergonomics_mode != MatchErgonomicsMode :: Legacy {
2140
+ if no_ref_mut_behind_and {
2148
2141
if pat_mutbl == Mutability :: Not {
2149
2142
// Prevent the inner pattern from binding with `ref mut`.
2150
- pat_info. max_ref_mutbl = pat_info. max_ref_mutbl . cap_to_weakly_not (
2151
- inner. span . find_ancestor_inside ( pat. span ) . map ( |end| pat. span . until ( end) ) ,
2152
- ) ;
2143
+ pat_info. max_ref_mutbl = pat_info. max_ref_mutbl . cap_to_weakly_not ( pat_prefix_span) ;
2153
2144
}
2145
+ } else {
2146
+ pat_info. max_ref_mutbl = MutblCap :: Mut ;
2147
+ }
2154
2148
2149
+ if new_match_ergonomics {
2155
2150
if let ByRef :: Yes ( inh_mut) = pat_info. binding_mode {
2156
- inherited_ref_mutbl_match = pat_mutbl <= inh_mut;
2157
- }
2151
+ // ref pattern consumes inherited reference
2152
+
2153
+ if pat_mutbl > inh_mut {
2154
+ // Tried to match inherited `ref` with `&mut`, which is an error
2155
+ let err_msg = "cannot match inherited `&` with `&mut` pattern" ;
2156
+ let err = if let Some ( span) = pat_prefix_span {
2157
+ let mut err = self . dcx ( ) . struct_span_err ( span, err_msg) ;
2158
+ err. span_suggestion_verbose (
2159
+ span,
2160
+ "replace this `&mut` pattern with `&`" ,
2161
+ "&" ,
2162
+ Applicability :: MachineApplicable ,
2163
+ ) ;
2164
+ err
2165
+ } else {
2166
+ self . dcx ( ) . struct_span_err ( pat. span , err_msg)
2167
+ } ;
2168
+ err. emit ( ) ;
2169
+ }
2158
2170
2159
- if inherited_ref_mutbl_match {
2160
2171
pat_info. binding_mode = ByRef :: No ;
2161
- if match_ergonomics_mode == MatchErgonomicsMode :: EatOneLayer {
2162
- self . typeck_results . borrow_mut ( ) . skipped_ref_pats_mut ( ) . insert ( pat. hir_id ) ;
2163
- self . check_pat ( inner, expected, pat_info) ;
2164
- return expected;
2165
- }
2166
- } else if match_ergonomics_mode == MatchErgonomicsMode :: EatOneLayer
2167
- && pat_mutbl == Mutability :: Mut
2168
- {
2169
- // `&mut` patterns pell off `&` references
2170
- let ( new_expected, new_bm, max_ref_mutbl) = self . peel_off_references (
2171
- pat,
2172
- expected,
2173
- pat_info. binding_mode ,
2174
- Mutability :: Not ,
2175
- pat_info. max_ref_mutbl ,
2176
- ) ;
2177
- expected = new_expected;
2178
- pat_info. binding_mode = new_bm;
2179
- pat_info. max_ref_mutbl = max_ref_mutbl;
2172
+ self . typeck_results . borrow_mut ( ) . skipped_ref_pats_mut ( ) . insert ( pat. hir_id ) ;
2173
+ self . check_pat ( inner, expected, pat_info) ;
2174
+ return expected;
2180
2175
}
2181
2176
} else {
2182
2177
// Reset binding mode on old editions
@@ -2189,8 +2184,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2189
2184
. rust_2024_migration_desugared_pats_mut ( )
2190
2185
. insert ( pat_info. top_info . hir_id ) ;
2191
2186
}
2192
-
2193
- pat_info. max_ref_mutbl = MutblCap :: Mut ;
2194
2187
}
2195
2188
2196
2189
let tcx = self . tcx ;
@@ -2205,34 +2198,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2205
2198
// the bad interactions of the given hack detailed in (note_1).
2206
2199
debug ! ( "check_pat_ref: expected={:?}" , expected) ;
2207
2200
match * expected. kind ( ) {
2208
- ty:: Ref ( _, r_ty, r_mutbl) if r_mutbl == pat_mutbl => {
2209
- if r_mutbl == Mutability :: Not
2210
- && match_ergonomics_mode != MatchErgonomicsMode :: Legacy
2211
- {
2201
+ ty:: Ref ( _, r_ty, r_mutbl)
2202
+ if ( new_match_ergonomics && r_mutbl >= pat_mutbl)
2203
+ || r_mutbl == pat_mutbl =>
2204
+ {
2205
+ if no_ref_mut_behind_and && r_mutbl == Mutability :: Not {
2212
2206
pat_info. max_ref_mutbl = MutblCap :: Not ;
2213
2207
}
2214
2208
2215
2209
( expected, r_ty)
2216
2210
}
2217
2211
2218
- // `&` pattern eats `&mut` reference
2219
- ty:: Ref ( _, r_ty, Mutability :: Mut )
2220
- if pat_mutbl == Mutability :: Not
2221
- && match_ergonomics_mode != MatchErgonomicsMode :: Legacy =>
2222
- {
2223
- ( expected, r_ty)
2224
- }
2225
-
2226
- _ if inherited_ref_mutbl_match
2227
- && match_ergonomics_mode == MatchErgonomicsMode :: EatTwoLayers =>
2228
- {
2229
- // We already matched against a match-ergonmics inserted reference,
2230
- // so we don't need to match against a reference from the original type.
2231
- // Save this info for use in lowering later
2232
- self . typeck_results . borrow_mut ( ) . skipped_ref_pats_mut ( ) . insert ( pat. hir_id ) ;
2233
- ( expected, expected)
2234
- }
2235
-
2236
2212
_ => {
2237
2213
let inner_ty = self . next_ty_var ( inner. span ) ;
2238
2214
let ref_ty = self . new_ref_ty ( pat. span , pat_mutbl, inner_ty) ;
0 commit comments