@@ -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 } ;
1313use rustc_target:: abi:: FieldIdx ;
1414
@@ -536,6 +536,62 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
536536 }
537537 None
538538 }
539+
540+ /// For "one type is more general than the other" errors on closures, suggest changing the lifetime
541+ /// of the parameters to accept all lifetimes.
542+ pub ( super ) fn suggest_for_all_lifetime_closure (
543+ & self ,
544+ span : Span ,
545+ exp_found : & ty:: error:: ExpectedFound < ty:: PolyTraitRef < ' tcx > > ,
546+ diag : & mut Diagnostic ,
547+ ) {
548+ // 1. Get the substs of the closure.
549+ // 2. Assume exp_found is FnOnce / FnMut / Fn, we can extract function parameters from [1].
550+ let expected = exp_found. expected . map_bound ( |x| x. substs . get ( 1 ) . cloned ( ) ) . transpose ( ) ;
551+ let found = exp_found. found . map_bound ( |x| x. substs . get ( 1 ) . cloned ( ) ) . transpose ( ) ;
552+
553+ // 3. Extract the tuple type from Fn trait and suggest the change.
554+ if let ( Some ( expected) , Some ( found) ) = ( expected, found) {
555+ let expected = expected. skip_binder ( ) . unpack ( ) ;
556+ let found = found. skip_binder ( ) . unpack ( ) ;
557+ if let ( GenericArgKind :: Type ( expected) , GenericArgKind :: Type ( found) ) = ( expected, found)
558+ && let ( ty:: Tuple ( expected) , ty:: Tuple ( found) ) = ( expected. kind ( ) , found. kind ( ) )
559+ && expected. len ( ) == found. len ( ) {
560+ let mut suggestion = "|" . to_string ( ) ;
561+ let mut is_first = true ;
562+ let mut has_suggestion = false ;
563+
564+ for ( expected, found) in expected. iter ( ) . zip ( found. iter ( ) ) {
565+ if is_first {
566+ is_first = true ;
567+ } else {
568+ suggestion += ", " ;
569+ }
570+
571+ if let ( ty:: Ref ( expected_region, _, _) , ty:: Ref ( found_region, _, _) ) = ( expected. kind ( ) , found. kind ( ) )
572+ && expected_region. is_late_bound ( ) && !found_region. is_late_bound ( ) {
573+ // If the expected region is late bound, and the found region is not, we can suggest adding `: &_`.
574+ // FIXME: use the actual type + variable name provided by user instead of `_`.
575+ suggestion += "_: &_" ;
576+ has_suggestion = true ;
577+ } else {
578+ // Otherwise, keep it as-is.
579+ suggestion += "_" ;
580+ }
581+ }
582+ suggestion += "|" ;
583+
584+ if has_suggestion {
585+ diag. span_suggestion_verbose (
586+ span,
587+ "consider changing the type of the closure parameters" ,
588+ suggestion,
589+ Applicability :: MaybeIncorrect ,
590+ ) ;
591+ }
592+ }
593+ }
594+ }
539595}
540596
541597impl < ' tcx > TypeErrCtxt < ' _ , ' tcx > {
0 commit comments