@@ -12,7 +12,7 @@ use rustc_infer::infer;
1212use rustc_middle:: mir:: interpret:: ErrorHandled ;
1313use rustc_middle:: ty:: { self , Ty , TypeVisitableExt } ;
1414use 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 } ;
1616use rustc_span:: edit_distance:: find_best_match_for_name;
1717use rustc_span:: hygiene:: DesugaringKind ;
1818use rustc_span:: source_map:: Spanned ;
@@ -335,9 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
335335 match adjust_mode {
336336 AdjustMode :: Pass => ( expected, def_br, max_ref_mutbl) ,
337337 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) ,
341339 }
342340 }
343341
@@ -408,8 +406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
408406 pat : & ' tcx Pat < ' tcx > ,
409407 expected : Ty < ' tcx > ,
410408 mut def_br : ByRef ,
411- max_peelable_mutability : Mutability ,
412- mut max_ref_mutability : MutblCap ,
409+ mut max_ref_mutbl : MutblCap ,
413410 ) -> ( Ty < ' tcx > , ByRef , MutblCap ) {
414411 let mut expected = self . try_structurally_resolve_type ( pat. span , expected) ;
415412 // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
@@ -421,9 +418,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
421418 //
422419 // See the examples in `ui/match-defbm*.rs`.
423420 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 ( ) {
427422 debug ! ( "inspecting {:?}" , expected) ;
428423
429424 debug ! ( "current discriminant is Ref, inserting implicit deref" ) ;
@@ -443,10 +438,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
443438 } ) ;
444439 }
445440
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 ( ) ) ;
448443 if def_br == ByRef :: Yes ( Mutability :: Not ) {
449- max_ref_mutability = MutblCap :: Not ;
444+ max_ref_mutbl = MutblCap :: Not ;
450445 }
451446 }
452447
@@ -458,7 +453,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
458453 . insert ( pat. hir_id , pat_adjustments) ;
459454 }
460455
461- ( expected, def_br, max_ref_mutability )
456+ ( expected, def_br, max_ref_mutbl )
462457 }
463458
464459 fn check_pat_lit (
@@ -674,17 +669,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
674669
675670 // Determine the binding mode...
676671 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+ }
688693 }
689694 BindingMode ( ByRef :: No , mutbl) => BindingMode ( def_br, mutbl) ,
690695 BindingMode ( ByRef :: Yes ( _) , _) => user_bind_annot,
@@ -2126,57 +2131,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
21262131 mut expected : Ty < ' tcx > ,
21272132 mut pat_info : PatInfo < ' tcx , ' _ > ,
21282133 ) -> 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;
21362136
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) ) ;
21452139
2146- let mut inherited_ref_mutbl_match = false ;
2147- if match_ergonomics_mode != MatchErgonomicsMode :: Legacy {
2140+ if no_ref_mut_behind_and {
21482141 if pat_mutbl == Mutability :: Not {
21492142 // 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) ;
21532144 }
2145+ } else {
2146+ pat_info. max_ref_mutbl = MutblCap :: Mut ;
2147+ }
21542148
2149+ if new_match_ergonomics {
21552150 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+ }
21582170
2159- if inherited_ref_mutbl_match {
21602171 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;
21802175 }
21812176 } else {
21822177 // Reset binding mode on old editions
@@ -2189,8 +2184,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
21892184 . rust_2024_migration_desugared_pats_mut ( )
21902185 . insert ( pat_info. top_info . hir_id ) ;
21912186 }
2192-
2193- pat_info. max_ref_mutbl = MutblCap :: Mut ;
21942187 }
21952188
21962189 let tcx = self . tcx ;
@@ -2205,34 +2198,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22052198 // the bad interactions of the given hack detailed in (note_1).
22062199 debug ! ( "check_pat_ref: expected={:?}" , expected) ;
22072200 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 {
22122206 pat_info. max_ref_mutbl = MutblCap :: Not ;
22132207 }
22142208
22152209 ( expected, r_ty)
22162210 }
22172211
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-
22362212 _ => {
22372213 let inner_ty = self . next_ty_var ( inner. span ) ;
22382214 let ref_ty = self . new_ref_ty ( pat. span , pat_mutbl, inner_ty) ;
0 commit comments