@@ -8,7 +8,7 @@ use rustc_middle::traits::{
8
8
StatementAsExpression ,
9
9
} ;
10
10
use 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 } ;
12
12
use rustc_span:: { sym, BytePos , Span } ;
13
13
14
14
use crate :: errors:: {
@@ -553,6 +553,62 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
553
553
}
554
554
}
555
555
}
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
+ }
556
612
}
557
613
558
614
impl < ' tcx > TypeErrCtxt < ' _ , ' tcx > {
0 commit comments