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