@@ -699,7 +699,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
699
699
700
700
// Determine the binding mode...
701
701
let bm = match user_bind_annot {
702
- BindingMode ( ByRef :: No , Mutability :: Mut ) if matches ! ( def_br , ByRef :: Yes ( _ ) ) => {
702
+ BindingMode ( ByRef :: No , Mutability :: Mut ) if let ByRef :: Yes ( def_br_mutbl ) = def_br => {
703
703
if pat. span . at_least_rust_2024 ( )
704
704
&& ( self . tcx . features ( ) . ref_pat_eat_one_layer_2024 ( )
705
705
|| self . tcx . features ( ) . ref_pat_eat_one_layer_2024_structural ( ) )
@@ -719,22 +719,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
719
719
// `mut` resets the binding mode on edition <= 2021
720
720
self . add_rust_2024_migration_desugared_pat (
721
721
pat_info. top_info . hir_id ,
722
- pat. span ,
722
+ pat,
723
723
ident. span ,
724
- "requires binding by-value, but the implicit default is by-reference" ,
724
+ def_br_mutbl ,
725
725
) ;
726
726
BindingMode ( ByRef :: No , Mutability :: Mut )
727
727
}
728
728
}
729
729
BindingMode ( ByRef :: No , mutbl) => BindingMode ( def_br, mutbl) ,
730
730
BindingMode ( ByRef :: Yes ( _) , _) => {
731
- if matches ! ( def_br , ByRef :: Yes ( _ ) ) {
731
+ if let ByRef :: Yes ( def_br_mutbl ) = def_br {
732
732
// `ref`/`ref mut` overrides the binding mode on edition <= 2021
733
733
self . add_rust_2024_migration_desugared_pat (
734
734
pat_info. top_info . hir_id ,
735
- pat. span ,
735
+ pat,
736
736
ident. span ,
737
- "cannot override to bind by-reference when that is the implicit default" ,
737
+ def_br_mutbl ,
738
738
) ;
739
739
}
740
740
user_bind_annot
@@ -2263,13 +2263,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2263
2263
}
2264
2264
} else {
2265
2265
// Reset binding mode on old editions
2266
- if pat_info . binding_mode != ByRef :: No {
2266
+ if let ByRef :: Yes ( inh_mut ) = pat_info . binding_mode {
2267
2267
pat_info. binding_mode = ByRef :: No ;
2268
2268
self . add_rust_2024_migration_desugared_pat (
2269
2269
pat_info. top_info . hir_id ,
2270
- pat. span ,
2270
+ pat,
2271
2271
inner. span ,
2272
- "cannot implicitly match against multiple layers of reference" ,
2272
+ inh_mut ,
2273
2273
)
2274
2274
}
2275
2275
}
@@ -2635,33 +2635,65 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2635
2635
fn add_rust_2024_migration_desugared_pat (
2636
2636
& self ,
2637
2637
pat_id : HirId ,
2638
- subpat_span : Span ,
2638
+ subpat : & ' tcx Pat < ' tcx > ,
2639
2639
cutoff_span : Span ,
2640
- detailed_label : & str ,
2640
+ def_br_mutbl : Mutability ,
2641
2641
) {
2642
2642
// Try to trim the span we're labeling to just the `&` or binding mode that's an issue.
2643
2643
// If the subpattern's span is is from an expansion, the emitted label will not be trimmed.
2644
2644
let source_map = self . tcx . sess . source_map ( ) ;
2645
2645
let cutoff_span = source_map
2646
- . span_extend_prev_while ( cutoff_span, char :: is_whitespace)
2646
+ . span_extend_prev_while ( cutoff_span, |c| c . is_whitespace ( ) || c == '(' )
2647
2647
. unwrap_or ( cutoff_span) ;
2648
- // Ensure we use the syntax context and thus edition of `subpat_span `; this will be a hard
2648
+ // Ensure we use the syntax context and thus edition of `subpat.span `; this will be a hard
2649
2649
// error if the subpattern is of edition >= 2024.
2650
- let trimmed_span = subpat_span. until ( cutoff_span) . with_ctxt ( subpat_span. ctxt ( ) ) ;
2650
+ let trimmed_span = subpat. span . until ( cutoff_span) . with_ctxt ( subpat. span . ctxt ( ) ) ;
2651
+
2652
+ let mut typeck_results = self . typeck_results . borrow_mut ( ) ;
2653
+ let mut table = typeck_results. rust_2024_migration_desugared_pats_mut ( ) ;
2654
+ // FIXME(ref_pat_eat_one_layer_2024): The migration diagnostic doesn't know how to track the
2655
+ // default binding mode in the presence of Rule 3 or Rule 5. As a consequence, the labels it
2656
+ // gives for default binding modes are wrong, as well as suggestions based on the default
2657
+ // binding mode. This keeps it from making those suggestions, as doing so could panic.
2658
+ let info = table. entry ( pat_id) . or_insert_with ( || ty:: Rust2024IncompatiblePatInfo {
2659
+ primary_labels : Vec :: new ( ) ,
2660
+ bad_modifiers : false ,
2661
+ bad_ref_pats : false ,
2662
+ suggest_eliding_modes : !self . tcx . features ( ) . ref_pat_eat_one_layer_2024 ( )
2663
+ && !self . tcx . features ( ) . ref_pat_eat_one_layer_2024_structural ( ) ,
2664
+ } ) ;
2651
2665
2652
2666
// Only provide a detailed label if the problematic subpattern isn't from an expansion.
2653
2667
// In the case that it's from a macro, we'll add a more detailed note in the emitter.
2654
- let desc = if subpat_span. from_expansion ( ) {
2655
- "default binding mode is reset within expansion"
2668
+ let from_expansion = subpat. span . from_expansion ( ) ;
2669
+ let primary_label = if from_expansion {
2670
+ // NB: This wording assumes the only expansions that can produce problematic reference
2671
+ // patterns and bindings are macros. If a desugaring or AST pass is added that can do
2672
+ // so, we may want to inspect the span's source callee or macro backtrace.
2673
+ "occurs within macro expansion" . to_owned ( )
2656
2674
} else {
2657
- detailed_label
2675
+ let pat_kind = if let PatKind :: Binding ( user_bind_annot, _, _, _) = subpat. kind {
2676
+ info. bad_modifiers |= true ;
2677
+ // If the user-provided binding modifier doesn't match the default binding mode, we'll
2678
+ // need to suggest reference patterns, which can affect other bindings.
2679
+ // For simplicity, we opt to suggest making the pattern fully explicit.
2680
+ info. suggest_eliding_modes &=
2681
+ user_bind_annot == BindingMode ( ByRef :: Yes ( def_br_mutbl) , Mutability :: Not ) ;
2682
+ "binding modifier"
2683
+ } else {
2684
+ info. bad_ref_pats |= true ;
2685
+ // For simplicity, we don't try to suggest eliding reference patterns. Thus, we'll
2686
+ // suggest adding them instead, which can affect the types assigned to bindings.
2687
+ // As such, we opt to suggest making the pattern fully explicit.
2688
+ info. suggest_eliding_modes = false ;
2689
+ "reference pattern"
2690
+ } ;
2691
+ let dbm_str = match def_br_mutbl {
2692
+ Mutability :: Not => "ref" ,
2693
+ Mutability :: Mut => "ref mut" ,
2694
+ } ;
2695
+ format ! ( "{pat_kind} not allowed under `{dbm_str}` default binding mode" )
2658
2696
} ;
2659
-
2660
- self . typeck_results
2661
- . borrow_mut ( )
2662
- . rust_2024_migration_desugared_pats_mut ( )
2663
- . entry ( pat_id)
2664
- . or_default ( )
2665
- . push ( ( trimmed_span, desc. to_owned ( ) ) ) ;
2697
+ info. primary_labels . push ( ( trimmed_span, primary_label) ) ;
2666
2698
}
2667
2699
}
0 commit comments