@@ -7,6 +7,7 @@ use crate::ty::fast_reject::SimplifiedType;
7
7
use crate :: { errors, path_names_to_string} ;
8
8
use crate :: { Module , ModuleKind , ModuleOrUniformRoot } ;
9
9
use crate :: { PathResult , PathSource , Segment } ;
10
+ use ast:: HasNodeId ;
10
11
use rustc_hir:: def:: Namespace :: { self , * } ;
11
12
12
13
use rustc_ast:: ptr:: P ;
@@ -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
@@ -2711,8 +2712,12 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
2711
2712
self . suggest_introducing_lifetime (
2712
2713
& mut err,
2713
2714
Some ( lifetime_ref. ident . name . as_str ( ) ) ,
2714
- |err, _, span, message, suggestion| {
2715
- err. span_suggestion ( span, message, suggestion, Applicability :: MaybeIncorrect ) ;
2715
+ |err, _, span, message, suggestion, span_suggs| {
2716
+ err. multipart_suggestion_verbose (
2717
+ message,
2718
+ std:: iter:: once ( ( span, suggestion) ) . chain ( span_suggs. iter ( ) . cloned ( ) ) . collect ( ) ,
2719
+ Applicability :: MaybeIncorrect ,
2720
+ ) ;
2716
2721
true
2717
2722
} ,
2718
2723
) ;
@@ -2723,13 +2728,20 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
2723
2728
& self ,
2724
2729
err : & mut Diag < ' _ > ,
2725
2730
name : Option < & str > ,
2726
- suggest : impl Fn ( & mut Diag < ' _ > , bool , Span , Cow < ' static , str > , String ) -> bool ,
2731
+ suggest : impl Fn (
2732
+ & mut Diag < ' _ > ,
2733
+ bool ,
2734
+ Span ,
2735
+ Cow < ' static , str > ,
2736
+ String ,
2737
+ & Vec < ( Span , String ) > ,
2738
+ ) -> bool ,
2727
2739
) {
2728
2740
let mut suggest_note = true ;
2729
2741
for rib in self . lifetime_ribs . iter ( ) . rev ( ) {
2730
2742
let mut should_continue = true ;
2731
2743
match rib. kind {
2732
- LifetimeRibKind :: Generics { binder : _ , span, kind } => {
2744
+ LifetimeRibKind :: Generics { binder : node_id , span, kind } => {
2733
2745
// Avoid suggesting placing lifetime parameters on constant items unless the relevant
2734
2746
// feature is enabled. Suggest the parent item as a possible location if applicable.
2735
2747
if let LifetimeBinderKind :: ConstItem = kind
@@ -2758,11 +2770,58 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
2758
2770
| LifetimeBinderKind :: PolyTrait
2759
2771
| LifetimeBinderKind :: WhereBound
2760
2772
) ;
2773
+
2774
+ let mut rm_inner_binders: FxHashSet < Span > = Default :: default ( ) ;
2761
2775
let ( span, sugg) = if span. is_empty ( ) {
2776
+ let mut binder_idents: FxHashSet < Ident > = Default :: default ( ) ;
2777
+ binder_idents. insert ( if let Some ( name) = name {
2778
+ Ident :: from_str ( name)
2779
+ } else {
2780
+ Ident :: from_str ( "'a" )
2781
+ } ) ;
2782
+
2783
+ // We need special treat binders in following situation:
2784
+ // Change `T: for<'a> Trait<T> + 'b` to `for<'a, 'b> T: Trait<T> + 'b`
2785
+ // T: for<'a> Trait<T> + 'b
2786
+ // ^^^^^^^ remove existing inner binder `for<'a>`
2787
+ // for<'a, 'b> T: Trait<T> + 'b
2788
+ // ^^^^^^^^^^^ suggest outer binder `for<'a, 'b>`
2789
+ if let LifetimeBinderKind :: WhereBound = kind
2790
+ && let Some ( ast:: WherePredicate :: BoundPredicate (
2791
+ ast:: WhereBoundPredicate { bounded_ty, bounds, .. } ,
2792
+ ) ) = self . diag_metadata . current_where_predicate
2793
+ && bounded_ty. node_id ( ) == node_id
2794
+ {
2795
+ for bound in bounds {
2796
+ let ast:: GenericBound :: Trait ( poly_trait_ref, _) = bound else {
2797
+ continue ;
2798
+ } ;
2799
+ rm_inner_binders. insert (
2800
+ poly_trait_ref
2801
+ . span
2802
+ . with_hi ( poly_trait_ref. trait_ref . path . span . lo ( ) ) ,
2803
+ ) ;
2804
+ poly_trait_ref. bound_generic_params . iter ( ) . for_each ( |v| {
2805
+ binder_idents. insert ( v. ident ) ;
2806
+ } ) ;
2807
+ }
2808
+ }
2809
+
2810
+ let len = binder_idents. len ( ) ;
2811
+ let binders_sugg = binder_idents. into_iter ( ) . enumerate ( ) . fold (
2812
+ "" . to_string ( ) ,
2813
+ |mut binders, ( i, x) | {
2814
+ binders += x. as_str ( ) ;
2815
+ if i != len - 1 {
2816
+ binders += ", " ;
2817
+ }
2818
+ binders
2819
+ } ,
2820
+ ) ;
2762
2821
let sugg = format ! (
2763
2822
"{}<{}>{}" ,
2764
2823
if higher_ranked { "for" } else { "" } ,
2765
- name . unwrap_or ( "'a" ) ,
2824
+ format! ( "{}" , binders_sugg ) ,
2766
2825
if higher_ranked { " " } else { "" } ,
2767
2826
) ;
2768
2827
( span, sugg)
@@ -2777,24 +2836,41 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
2777
2836
let sugg = format ! ( "{}, " , name. unwrap_or( "'a" ) ) ;
2778
2837
( span, sugg)
2779
2838
} ;
2839
+
2780
2840
if higher_ranked {
2781
2841
let message = Cow :: from ( format ! (
2782
2842
"consider making the {} lifetime-generic with a new `{}` lifetime" ,
2783
2843
kind. descr( ) ,
2784
2844
name. unwrap_or( "'a" ) ,
2785
2845
) ) ;
2786
- should_continue = suggest ( err, true , span, message, sugg) ;
2846
+ should_continue = suggest (
2847
+ err,
2848
+ true ,
2849
+ span,
2850
+ message,
2851
+ sugg,
2852
+ & if rm_inner_binders. len ( ) > 0 {
2853
+ let mut rm_inner_binders = rm_inner_binders
2854
+ . into_iter ( )
2855
+ . map ( |v| ( v, "" . to_string ( ) ) )
2856
+ . collect :: < Vec < _ > > ( ) ;
2857
+ rm_inner_binders. sort_by ( |a, b| a. 0 . partial_cmp ( & b. 0 ) . unwrap ( ) ) ;
2858
+ rm_inner_binders
2859
+ } else {
2860
+ vec ! [ ]
2861
+ } ,
2862
+ ) ;
2787
2863
err. note_once (
2788
2864
"for more information on higher-ranked polymorphism, visit \
2789
2865
https://doc.rust-lang.org/nomicon/hrtb.html",
2790
2866
) ;
2791
2867
} else if let Some ( name) = name {
2792
2868
let message =
2793
2869
Cow :: from ( format ! ( "consider introducing lifetime `{name}` here" ) ) ;
2794
- should_continue = suggest ( err, false , span, message, sugg) ;
2870
+ should_continue = suggest ( err, false , span, message, sugg, & vec ! [ ] ) ;
2795
2871
} else {
2796
2872
let message = Cow :: from ( "consider introducing a named lifetime parameter" ) ;
2797
- should_continue = suggest ( err, false , span, message, sugg) ;
2873
+ should_continue = suggest ( err, false , span, message, sugg, & vec ! [ ] ) ;
2798
2874
}
2799
2875
}
2800
2876
LifetimeRibKind :: Item | LifetimeRibKind :: ConstParamTy => break ,
@@ -3030,7 +3106,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
3030
3106
self . suggest_introducing_lifetime (
3031
3107
err,
3032
3108
None ,
3033
- |err, higher_ranked, span, message, intro_sugg| {
3109
+ |err, higher_ranked, span, message, intro_sugg, _ | {
3034
3110
err. multipart_suggestion_verbose (
3035
3111
message,
3036
3112
std:: iter:: once ( ( span, intro_sugg) )
@@ -3158,7 +3234,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
3158
3234
self . suggest_introducing_lifetime (
3159
3235
err,
3160
3236
None ,
3161
- |err, higher_ranked, span, message, intro_sugg| {
3237
+ |err, higher_ranked, span, message, intro_sugg, _ | {
3162
3238
err. multipart_suggestion_verbose (
3163
3239
message,
3164
3240
std:: iter:: once ( ( span, intro_sugg) )
@@ -3306,7 +3382,6 @@ fn mk_where_bound_predicate(
3306
3382
poly_trait_ref : & ast:: PolyTraitRef ,
3307
3383
ty : & Ty ,
3308
3384
) -> Option < ast:: WhereBoundPredicate > {
3309
- use rustc_span:: DUMMY_SP ;
3310
3385
let modified_segments = {
3311
3386
let mut segments = path. segments . clone ( ) ;
3312
3387
let [ preceding @ .., second_last, last] = segments. as_mut_slice ( ) else {
0 commit comments