@@ -7,6 +7,7 @@ use crate::ty::fast_reject::SimplifiedType;
77use crate :: { errors, path_names_to_string} ;
88use crate :: { Module , ModuleKind , ModuleOrUniformRoot } ;
99use crate :: { PathResult , PathSource , Segment } ;
10+ use ast:: HasNodeId ;
1011use rustc_hir:: def:: Namespace :: { self , * } ;
1112
1213use rustc_ast:: ptr:: P ;
@@ -31,7 +32,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
3132use rustc_span:: edition:: Edition ;
3233use rustc_span:: hygiene:: MacroKind ;
3334use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
34- use rustc_span:: Span ;
35+ use rustc_span:: { Span , DUMMY_SP } ;
3536
3637use rustc_middle:: ty;
3738
@@ -2711,8 +2712,12 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
27112712 self . suggest_introducing_lifetime (
27122713 & mut err,
27132714 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+ ) ;
27162721 true
27172722 } ,
27182723 ) ;
@@ -2723,13 +2728,20 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
27232728 & self ,
27242729 err : & mut Diag < ' _ > ,
27252730 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 ,
27272739 ) {
27282740 let mut suggest_note = true ;
27292741 for rib in self . lifetime_ribs . iter ( ) . rev ( ) {
27302742 let mut should_continue = true ;
27312743 match rib. kind {
2732- LifetimeRibKind :: Generics { binder : _ , span, kind } => {
2744+ LifetimeRibKind :: Generics { binder : node_id , span, kind } => {
27332745 // Avoid suggesting placing lifetime parameters on constant items unless the relevant
27342746 // feature is enabled. Suggest the parent item as a possible location if applicable.
27352747 if let LifetimeBinderKind :: ConstItem = kind
@@ -2758,11 +2770,58 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
27582770 | LifetimeBinderKind :: PolyTrait
27592771 | LifetimeBinderKind :: WhereBound
27602772 ) ;
2773+
2774+ let mut rm_inner_binders: FxHashSet < Span > = Default :: default ( ) ;
27612775 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+ ) ;
27622821 let sugg = format ! (
27632822 "{}<{}>{}" ,
27642823 if higher_ranked { "for" } else { "" } ,
2765- name . unwrap_or ( "'a" ) ,
2824+ format! ( "{}" , binders_sugg ) ,
27662825 if higher_ranked { " " } else { "" } ,
27672826 ) ;
27682827 ( span, sugg)
@@ -2777,24 +2836,41 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
27772836 let sugg = format ! ( "{}, " , name. unwrap_or( "'a" ) ) ;
27782837 ( span, sugg)
27792838 } ;
2839+
27802840 if higher_ranked {
27812841 let message = Cow :: from ( format ! (
27822842 "consider making the {} lifetime-generic with a new `{}` lifetime" ,
27832843 kind. descr( ) ,
27842844 name. unwrap_or( "'a" ) ,
27852845 ) ) ;
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+ ) ;
27872863 err. note_once (
27882864 "for more information on higher-ranked polymorphism, visit \
27892865 https://doc.rust-lang.org/nomicon/hrtb.html",
27902866 ) ;
27912867 } else if let Some ( name) = name {
27922868 let message =
27932869 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 ! [ ] ) ;
27952871 } else {
27962872 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 ! [ ] ) ;
27982874 }
27992875 }
28002876 LifetimeRibKind :: Item | LifetimeRibKind :: ConstParamTy => break ,
@@ -3030,7 +3106,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
30303106 self . suggest_introducing_lifetime (
30313107 err,
30323108 None ,
3033- |err, higher_ranked, span, message, intro_sugg| {
3109+ |err, higher_ranked, span, message, intro_sugg, _ | {
30343110 err. multipart_suggestion_verbose (
30353111 message,
30363112 std:: iter:: once ( ( span, intro_sugg) )
@@ -3158,7 +3234,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
31583234 self . suggest_introducing_lifetime (
31593235 err,
31603236 None ,
3161- |err, higher_ranked, span, message, intro_sugg| {
3237+ |err, higher_ranked, span, message, intro_sugg, _ | {
31623238 err. multipart_suggestion_verbose (
31633239 message,
31643240 std:: iter:: once ( ( span, intro_sugg) )
@@ -3306,7 +3382,6 @@ fn mk_where_bound_predicate(
33063382 poly_trait_ref : & ast:: PolyTraitRef ,
33073383 ty : & Ty ,
33083384) -> Option < ast:: WhereBoundPredicate > {
3309- use rustc_span:: DUMMY_SP ;
33103385 let modified_segments = {
33113386 let mut segments = path. segments . clone ( ) ;
33123387 let [ preceding @ .., second_last, last] = segments. as_mut_slice ( ) else {
0 commit comments