@@ -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 ;
@@ -17,6 +18,7 @@ use rustc_ast::{
1718} ;
1819use rustc_ast_pretty:: pprust:: where_bound_predicate_to_string;
1920use rustc_data_structures:: fx:: FxHashSet ;
21+ use rustc_data_structures:: fx:: FxIndexSet ;
2022use rustc_errors:: {
2123 codes:: * , pluralize, struct_span_code_err, Applicability , Diag , ErrorGuaranteed , MultiSpan ,
2224 SuggestionStyle ,
@@ -31,7 +33,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
3133use rustc_span:: edition:: Edition ;
3234use rustc_span:: hygiene:: MacroKind ;
3335use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
34- use rustc_span:: Span ;
36+ use rustc_span:: { Span , DUMMY_SP } ;
3537
3638use rustc_middle:: ty;
3739
@@ -2711,8 +2713,12 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
27112713 self . suggest_introducing_lifetime (
27122714 & mut err,
27132715 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+ ) ;
27162722 true
27172723 } ,
27182724 ) ;
@@ -2723,13 +2729,20 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
27232729 & self ,
27242730 err : & mut Diag < ' _ > ,
27252731 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 ,
27272740 ) {
27282741 let mut suggest_note = true ;
27292742 for rib in self . lifetime_ribs . iter ( ) . rev ( ) {
27302743 let mut should_continue = true ;
27312744 match rib. kind {
2732- LifetimeRibKind :: Generics { binder : _ , span, kind } => {
2745+ LifetimeRibKind :: Generics { binder : node_id , span, kind } => {
27332746 // Avoid suggesting placing lifetime parameters on constant items unless the relevant
27342747 // feature is enabled. Suggest the parent item as a possible location if applicable.
27352748 if let LifetimeBinderKind :: ConstItem = kind
@@ -2758,11 +2771,58 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
27582771 | LifetimeBinderKind :: PolyTrait
27592772 | LifetimeBinderKind :: WhereBound
27602773 ) ;
2774+
2775+ let mut rm_inner_binders: FxIndexSet < Span > = Default :: default ( ) ;
27612776 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+ let ast:: GenericBound :: Trait ( poly_trait_ref, _) = bound else {
2798+ continue ;
2799+ } ;
2800+ rm_inner_binders. insert (
2801+ poly_trait_ref
2802+ . span
2803+ . with_hi ( poly_trait_ref. trait_ref . path . span . lo ( ) ) ,
2804+ ) ;
2805+ poly_trait_ref. bound_generic_params . iter ( ) . for_each ( |v| {
2806+ binder_idents. insert ( v. ident ) ;
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+ ) ;
27622822 let sugg = format ! (
27632823 "{}<{}>{}" ,
27642824 if higher_ranked { "for" } else { "" } ,
2765- name . unwrap_or ( "'a" ) ,
2825+ format! ( "{}" , binders_sugg ) ,
27662826 if higher_ranked { " " } else { "" } ,
27672827 ) ;
27682828 ( span, sugg)
@@ -2777,24 +2837,39 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
27772837 let sugg = format ! ( "{}, " , name. unwrap_or( "'a" ) ) ;
27782838 ( span, sugg)
27792839 } ;
2840+
27802841 if higher_ranked {
27812842 let message = Cow :: from ( format ! (
27822843 "consider making the {} lifetime-generic with a new `{}` lifetime" ,
27832844 kind. descr( ) ,
27842845 name. unwrap_or( "'a" ) ,
27852846 ) ) ;
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+ ) ;
27872862 err. note_once (
27882863 "for more information on higher-ranked polymorphism, visit \
27892864 https://doc.rust-lang.org/nomicon/hrtb.html",
27902865 ) ;
27912866 } else if let Some ( name) = name {
27922867 let message =
27932868 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 ! [ ] ) ;
27952870 } else {
27962871 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 ! [ ] ) ;
27982873 }
27992874 }
28002875 LifetimeRibKind :: Item | LifetimeRibKind :: ConstParamTy => break ,
@@ -3030,7 +3105,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
30303105 self . suggest_introducing_lifetime (
30313106 err,
30323107 None ,
3033- |err, higher_ranked, span, message, intro_sugg| {
3108+ |err, higher_ranked, span, message, intro_sugg, _ | {
30343109 err. multipart_suggestion_verbose (
30353110 message,
30363111 std:: iter:: once ( ( span, intro_sugg) )
@@ -3158,7 +3233,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
31583233 self . suggest_introducing_lifetime (
31593234 err,
31603235 None ,
3161- |err, higher_ranked, span, message, intro_sugg| {
3236+ |err, higher_ranked, span, message, intro_sugg, _ | {
31623237 err. multipart_suggestion_verbose (
31633238 message,
31643239 std:: iter:: once ( ( span, intro_sugg) )
@@ -3306,7 +3381,6 @@ fn mk_where_bound_predicate(
33063381 poly_trait_ref : & ast:: PolyTraitRef ,
33073382 ty : & Ty ,
33083383) -> Option < ast:: WhereBoundPredicate > {
3309- use rustc_span:: DUMMY_SP ;
33103384 let modified_segments = {
33113385 let mut segments = path. segments . clone ( ) ;
33123386 let [ preceding @ .., second_last, last] = segments. as_mut_slice ( ) else {
0 commit comments