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