@@ -8,7 +8,7 @@ use rustc_middle::traits::{
88 StatementAsExpression ,
99} ;
1010use rustc_middle:: ty:: print:: with_no_trimmed_paths;
11- use rustc_middle:: ty:: { self as ty, IsSuggestable , Ty , TypeVisitableExt } ;
11+ use rustc_middle:: ty:: { self as ty, GenericArgKind , IsSuggestable , Ty , TypeVisitableExt } ;
1212use rustc_span:: { sym, BytePos , Span } ;
1313
1414use crate :: errors:: {
@@ -553,6 +553,62 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
553553 }
554554 }
555555 }
556+
557+ /// For "one type is more general than the other" errors on closures, suggest changing the lifetime
558+ /// of the parameters to accept all lifetimes.
559+ pub ( super ) fn suggest_for_all_lifetime_closure (
560+ & self ,
561+ span : Span ,
562+ exp_found : & ty:: error:: ExpectedFound < ty:: PolyTraitRef < ' tcx > > ,
563+ diag : & mut Diagnostic ,
564+ ) {
565+ // 1. Get the substs of the closure.
566+ // 2. Assume exp_found is FnOnce / FnMut / Fn, we can extract function parameters from [1].
567+ let expected = exp_found. expected . map_bound ( |x| x. substs . get ( 1 ) . cloned ( ) ) . transpose ( ) ;
568+ let found = exp_found. found . map_bound ( |x| x. substs . get ( 1 ) . cloned ( ) ) . transpose ( ) ;
569+
570+ // 3. Extract the tuple type from Fn trait and suggest the change.
571+ if let ( Some ( expected) , Some ( found) ) = ( expected, found) {
572+ let expected = expected. skip_binder ( ) . unpack ( ) ;
573+ let found = found. skip_binder ( ) . unpack ( ) ;
574+ if let ( GenericArgKind :: Type ( expected) , GenericArgKind :: Type ( found) ) = ( expected, found)
575+ && let ( ty:: Tuple ( expected) , ty:: Tuple ( found) ) = ( expected. kind ( ) , found. kind ( ) )
576+ && expected. len ( ) == found. len ( ) {
577+ let mut suggestion = "|" . to_string ( ) ;
578+ let mut is_first = true ;
579+ let mut has_suggestion = false ;
580+
581+ for ( expected, found) in expected. iter ( ) . zip ( found. iter ( ) ) {
582+ if is_first {
583+ is_first = true ;
584+ } else {
585+ suggestion += ", " ;
586+ }
587+
588+ if let ( ty:: Ref ( expected_region, _, _) , ty:: Ref ( found_region, _, _) ) = ( expected. kind ( ) , found. kind ( ) )
589+ && expected_region. is_late_bound ( ) && !found_region. is_late_bound ( ) {
590+ // If the expected region is late bound, and the found region is not, we can suggest adding `: &_`.
591+ // FIXME: use the actual type + variable name provided by user instead of `_`.
592+ suggestion += "_: &_" ;
593+ has_suggestion = true ;
594+ } else {
595+ // Otherwise, keep it as-is.
596+ suggestion += "_" ;
597+ }
598+ }
599+ suggestion += "|" ;
600+
601+ if has_suggestion {
602+ diag. span_suggestion_verbose (
603+ span,
604+ "consider changing the type of the closure parameters" ,
605+ suggestion,
606+ Applicability :: MaybeIncorrect ,
607+ ) ;
608+ }
609+ }
610+ }
611+ }
556612}
557613
558614impl < ' tcx > TypeErrCtxt < ' _ , ' tcx > {
0 commit comments