@@ -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
use rustc_target:: abi:: FieldIdx ;
14
14
@@ -536,6 +536,62 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
536
536
}
537
537
None
538
538
}
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
+ }
539
595
}
540
596
541
597
impl < ' tcx > TypeErrCtxt < ' _ , ' tcx > {
0 commit comments