@@ -17,6 +17,7 @@ use rustc_ast::{
17
17
} ;
18
18
use rustc_ast_pretty:: pprust:: where_bound_predicate_to_string;
19
19
use rustc_data_structures:: fx:: FxHashSet ;
20
+ use rustc_data_structures:: fx:: FxIndexSet ;
20
21
use rustc_errors:: {
21
22
codes:: * , pluralize, struct_span_code_err, Applicability , Diag , ErrorGuaranteed , MultiSpan ,
22
23
SuggestionStyle ,
@@ -31,7 +32,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
31
32
use rustc_span:: edition:: Edition ;
32
33
use rustc_span:: hygiene:: MacroKind ;
33
34
use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
34
- use rustc_span:: Span ;
35
+ use rustc_span:: { Span , DUMMY_SP } ;
35
36
36
37
use rustc_middle:: ty;
37
38
@@ -2714,8 +2715,17 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
2714
2715
self . suggest_introducing_lifetime (
2715
2716
& mut err,
2716
2717
Some ( lifetime_ref. ident . name . as_str ( ) ) ,
2717
- |err, _, span, message, suggestion| {
2718
- err. span_suggestion ( span, message, suggestion, Applicability :: MaybeIncorrect ) ;
2718
+ |err, _, span, message, suggestion, span_suggs| {
2719
+ err. multipart_suggestion_with_style (
2720
+ message,
2721
+ std:: iter:: once ( ( span, suggestion) ) . chain ( span_suggs. clone ( ) ) . collect ( ) ,
2722
+ Applicability :: MaybeIncorrect ,
2723
+ if span_suggs. is_empty ( ) {
2724
+ SuggestionStyle :: ShowCode
2725
+ } else {
2726
+ SuggestionStyle :: ShowAlways
2727
+ } ,
2728
+ ) ;
2719
2729
true
2720
2730
} ,
2721
2731
) ;
@@ -2726,13 +2736,20 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
2726
2736
& self ,
2727
2737
err : & mut Diag < ' _ > ,
2728
2738
name : Option < & str > ,
2729
- suggest : impl Fn ( & mut Diag < ' _ > , bool , Span , Cow < ' static , str > , String ) -> bool ,
2739
+ suggest : impl Fn (
2740
+ & mut Diag < ' _ > ,
2741
+ bool ,
2742
+ Span ,
2743
+ Cow < ' static , str > ,
2744
+ String ,
2745
+ Vec < ( Span , String ) > ,
2746
+ ) -> bool ,
2730
2747
) {
2731
2748
let mut suggest_note = true ;
2732
2749
for rib in self . lifetime_ribs . iter ( ) . rev ( ) {
2733
2750
let mut should_continue = true ;
2734
2751
match rib. kind {
2735
- LifetimeRibKind :: Generics { binder : _ , span, kind } => {
2752
+ LifetimeRibKind :: Generics { binder, span, kind } => {
2736
2753
// Avoid suggesting placing lifetime parameters on constant items unless the relevant
2737
2754
// feature is enabled. Suggest the parent item as a possible location if applicable.
2738
2755
if let LifetimeBinderKind :: ConstItem = kind
@@ -2761,11 +2778,53 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
2761
2778
| LifetimeBinderKind :: PolyTrait
2762
2779
| LifetimeBinderKind :: WhereBound
2763
2780
) ;
2781
+
2782
+ let mut rm_inner_binders: FxIndexSet < Span > = Default :: default ( ) ;
2764
2783
let ( span, sugg) = if span. is_empty ( ) {
2784
+ let mut binder_idents: FxIndexSet < Ident > = Default :: default ( ) ;
2785
+ binder_idents. insert ( Ident :: from_str ( name. unwrap_or ( "'a" ) ) ) ;
2786
+
2787
+ // We need to special case binders in the following situation:
2788
+ // Change `T: for<'a> Trait<T> + 'b` to `for<'a, 'b> T: Trait<T> + 'b`
2789
+ // T: for<'a> Trait<T> + 'b
2790
+ // ^^^^^^^ remove existing inner binder `for<'a>`
2791
+ // for<'a, 'b> T: Trait<T> + 'b
2792
+ // ^^^^^^^^^^^ suggest outer binder `for<'a, 'b>`
2793
+ if let LifetimeBinderKind :: WhereBound = kind
2794
+ && let Some ( ast:: WherePredicate :: BoundPredicate (
2795
+ ast:: WhereBoundPredicate { bounded_ty, bounds, .. } ,
2796
+ ) ) = self . diag_metadata . current_where_predicate
2797
+ && bounded_ty. id == binder
2798
+ {
2799
+ for bound in bounds {
2800
+ if let ast:: GenericBound :: Trait ( poly_trait_ref, _) = bound
2801
+ && let span = poly_trait_ref
2802
+ . span
2803
+ . with_hi ( poly_trait_ref. trait_ref . path . span . lo ( ) )
2804
+ && !span. is_empty ( )
2805
+ {
2806
+ rm_inner_binders. insert ( span) ;
2807
+ poly_trait_ref. bound_generic_params . iter ( ) . for_each ( |v| {
2808
+ binder_idents. insert ( v. ident ) ;
2809
+ } ) ;
2810
+ }
2811
+ }
2812
+ }
2813
+
2814
+ let binders_sugg = binder_idents. into_iter ( ) . enumerate ( ) . fold (
2815
+ "" . to_string ( ) ,
2816
+ |mut binders, ( i, x) | {
2817
+ if i != 0 {
2818
+ binders += ", " ;
2819
+ }
2820
+ binders += x. as_str ( ) ;
2821
+ binders
2822
+ } ,
2823
+ ) ;
2765
2824
let sugg = format ! (
2766
2825
"{}<{}>{}" ,
2767
2826
if higher_ranked { "for" } else { "" } ,
2768
- name . unwrap_or ( "'a" ) ,
2827
+ binders_sugg ,
2769
2828
if higher_ranked { " " } else { "" } ,
2770
2829
) ;
2771
2830
( span, sugg)
@@ -2780,24 +2839,39 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
2780
2839
let sugg = format ! ( "{}, " , name. unwrap_or( "'a" ) ) ;
2781
2840
( span, sugg)
2782
2841
} ;
2842
+
2783
2843
if higher_ranked {
2784
2844
let message = Cow :: from ( format ! (
2785
2845
"consider making the {} lifetime-generic with a new `{}` lifetime" ,
2786
2846
kind. descr( ) ,
2787
2847
name. unwrap_or( "'a" ) ,
2788
2848
) ) ;
2789
- should_continue = suggest ( err, true , span, message, sugg) ;
2849
+ should_continue = suggest (
2850
+ err,
2851
+ true ,
2852
+ span,
2853
+ message,
2854
+ sugg,
2855
+ if !rm_inner_binders. is_empty ( ) {
2856
+ rm_inner_binders
2857
+ . into_iter ( )
2858
+ . map ( |v| ( v, "" . to_string ( ) ) )
2859
+ . collect :: < Vec < _ > > ( )
2860
+ } else {
2861
+ vec ! [ ]
2862
+ } ,
2863
+ ) ;
2790
2864
err. note_once (
2791
2865
"for more information on higher-ranked polymorphism, visit \
2792
2866
https://doc.rust-lang.org/nomicon/hrtb.html",
2793
2867
) ;
2794
2868
} else if let Some ( name) = name {
2795
2869
let message =
2796
2870
Cow :: from ( format ! ( "consider introducing lifetime `{name}` here" ) ) ;
2797
- should_continue = suggest ( err, false , span, message, sugg) ;
2871
+ should_continue = suggest ( err, false , span, message, sugg, vec ! [ ] ) ;
2798
2872
} else {
2799
2873
let message = Cow :: from ( "consider introducing a named lifetime parameter" ) ;
2800
- should_continue = suggest ( err, false , span, message, sugg) ;
2874
+ should_continue = suggest ( err, false , span, message, sugg, vec ! [ ] ) ;
2801
2875
}
2802
2876
}
2803
2877
LifetimeRibKind :: Item | LifetimeRibKind :: ConstParamTy => break ,
@@ -3033,11 +3107,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
3033
3107
self . suggest_introducing_lifetime (
3034
3108
err,
3035
3109
None ,
3036
- |err, higher_ranked, span, message, intro_sugg| {
3110
+ |err, higher_ranked, span, message, intro_sugg, _ | {
3037
3111
err. multipart_suggestion_verbose (
3038
3112
message,
3039
3113
std:: iter:: once ( ( span, intro_sugg) )
3040
- . chain ( spans_suggs. iter ( ) . cloned ( ) )
3114
+ . chain ( spans_suggs. clone ( ) )
3041
3115
. collect ( ) ,
3042
3116
Applicability :: MaybeIncorrect ,
3043
3117
) ;
@@ -3161,11 +3235,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
3161
3235
self . suggest_introducing_lifetime (
3162
3236
err,
3163
3237
None ,
3164
- |err, higher_ranked, span, message, intro_sugg| {
3238
+ |err, higher_ranked, span, message, intro_sugg, _ | {
3165
3239
err. multipart_suggestion_verbose (
3166
3240
message,
3167
3241
std:: iter:: once ( ( span, intro_sugg) )
3168
- . chain ( spans_suggs. iter ( ) . cloned ( ) )
3242
+ . chain ( spans_suggs. clone ( ) )
3169
3243
. collect ( ) ,
3170
3244
Applicability :: MaybeIncorrect ,
3171
3245
) ;
@@ -3309,7 +3383,6 @@ fn mk_where_bound_predicate(
3309
3383
poly_trait_ref : & ast:: PolyTraitRef ,
3310
3384
ty : & Ty ,
3311
3385
) -> Option < ast:: WhereBoundPredicate > {
3312
- use rustc_span:: DUMMY_SP ;
3313
3386
let modified_segments = {
3314
3387
let mut segments = path. segments . clone ( ) ;
3315
3388
let [ preceding @ .., second_last, last] = segments. as_mut_slice ( ) else {
0 commit comments