@@ -16,6 +16,7 @@ use rustc_errors::{
16
16
use rustc_hir as hir;
17
17
use rustc_hir:: def:: { CtorOf , DefKind , Res } ;
18
18
use rustc_hir:: def_id:: DefId ;
19
+ use rustc_hir:: intravisit:: Visitor ;
19
20
use rustc_hir:: { ExprKind , Node , QPath } ;
20
21
use rustc_hir_analysis:: astconv:: AstConv ;
21
22
use rustc_hir_analysis:: check:: intrinsicck:: InlineAsmCtxt ;
@@ -28,7 +29,7 @@ use rustc_infer::infer::TypeTrace;
28
29
use rustc_infer:: infer:: { DefineOpaqueTypes , InferOk } ;
29
30
use rustc_middle:: ty:: adjustment:: AllowTwoPhase ;
30
31
use rustc_middle:: ty:: visit:: TypeVisitableExt ;
31
- use rustc_middle:: ty:: { self , IsSuggestable , Ty } ;
32
+ use rustc_middle:: ty:: { self , IsSuggestable , Ty , TyCtxt } ;
32
33
use rustc_session:: Session ;
33
34
use rustc_span:: symbol:: { kw, Ident } ;
34
35
use rustc_span:: { self , sym, BytePos , Span } ;
@@ -722,6 +723,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
722
723
& mut err,
723
724
fn_def_id,
724
725
callee_ty,
726
+ call_expr,
727
+ None ,
725
728
Some ( mismatch_idx) ,
726
729
is_method,
727
730
) ;
@@ -826,6 +829,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
826
829
& mut err,
827
830
fn_def_id,
828
831
callee_ty,
832
+ call_expr,
833
+ Some ( expected_ty) ,
829
834
Some ( expected_idx. as_usize ( ) ) ,
830
835
is_method,
831
836
) ;
@@ -1208,7 +1213,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1208
1213
}
1209
1214
1210
1215
// Call out where the function is defined
1211
- self . label_fn_like ( & mut err, fn_def_id, callee_ty, None , is_method) ;
1216
+ self . label_fn_like ( & mut err, fn_def_id, callee_ty, call_expr , None , None , is_method) ;
1212
1217
1213
1218
// And add a suggestion block for all of the parameters
1214
1219
let suggestion_text = match suggestion_text {
@@ -1899,6 +1904,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1899
1904
err : & mut Diagnostic ,
1900
1905
callable_def_id : Option < DefId > ,
1901
1906
callee_ty : Option < Ty < ' tcx > > ,
1907
+ call_expr : & ' tcx hir:: Expr < ' tcx > ,
1908
+ expected_ty : Option < Ty < ' tcx > > ,
1902
1909
// A specific argument should be labeled, instead of all of them
1903
1910
expected_idx : Option < usize > ,
1904
1911
is_method : bool ,
@@ -2015,6 +2022,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2015
2022
let param = expected_idx
2016
2023
. and_then ( |expected_idx| self . tcx . hir ( ) . body ( * body) . params . get ( expected_idx) ) ;
2017
2024
let ( kind, span) = if let Some ( param) = param {
2025
+ // Try to find earlier invocations of this closure to find if the type mismatch
2026
+ // is because of inference. If we find one, point at them.
2027
+ let mut call_finder = FindClosureArg { tcx : self . tcx , calls : vec ! [ ] } ;
2028
+ let node = self . tcx
2029
+ . opt_local_def_id_to_hir_id ( self . tcx . hir ( ) . get_parent_item ( call_expr. hir_id ) )
2030
+ . and_then ( |hir_id| self . tcx . hir ( ) . find ( hir_id) ) ;
2031
+ match node {
2032
+ Some ( hir:: Node :: Item ( item) ) => call_finder. visit_item ( item) ,
2033
+ Some ( hir:: Node :: TraitItem ( item) ) => call_finder. visit_trait_item ( item) ,
2034
+ Some ( hir:: Node :: ImplItem ( item) ) => call_finder. visit_impl_item ( item) ,
2035
+ _ => { }
2036
+ }
2037
+ let typeck = self . typeck_results . borrow ( ) ;
2038
+ for ( rcvr, args) in call_finder. calls {
2039
+ if let Some ( rcvr_ty) = typeck. node_type_opt ( rcvr. hir_id )
2040
+ && let ty:: Closure ( call_def_id, _) = rcvr_ty. kind ( )
2041
+ && def_id == * call_def_id
2042
+ && let Some ( idx) = expected_idx
2043
+ && let Some ( arg) = args. get ( idx)
2044
+ && let Some ( arg_ty) = typeck. node_type_opt ( arg. hir_id )
2045
+ && let Some ( expected_ty) = expected_ty
2046
+ && self . can_eq ( self . param_env , arg_ty, expected_ty)
2047
+ {
2048
+ let mut sp: MultiSpan = vec ! [ arg. span] . into ( ) ;
2049
+ sp. push_span_label (
2050
+ arg. span ,
2051
+ format ! ( "expected because this argument is of type `{arg_ty}`" ) ,
2052
+ ) ;
2053
+ sp. push_span_label ( rcvr. span , "in this closure call" ) ;
2054
+ err. span_note (
2055
+ sp,
2056
+ format ! (
2057
+ "expected because the closure was earlier called with an \
2058
+ argument of type `{arg_ty}`",
2059
+ ) ,
2060
+ ) ;
2061
+ break ;
2062
+ }
2063
+ }
2064
+
2018
2065
( "closure parameter" , param. span )
2019
2066
} else {
2020
2067
( "closure" , self . tcx . def_span ( def_id) )
@@ -2028,3 +2075,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2028
2075
}
2029
2076
}
2030
2077
}
2078
+
2079
+ struct FindClosureArg < ' tcx > {
2080
+ tcx : TyCtxt < ' tcx > ,
2081
+ calls : Vec < ( & ' tcx hir:: Expr < ' tcx > , & ' tcx [ hir:: Expr < ' tcx > ] ) > ,
2082
+ }
2083
+
2084
+ impl < ' tcx > Visitor < ' tcx > for FindClosureArg < ' tcx > {
2085
+ type NestedFilter = rustc_middle:: hir:: nested_filter:: All ;
2086
+
2087
+ fn nested_visit_map ( & mut self ) -> Self :: Map {
2088
+ self . tcx . hir ( )
2089
+ }
2090
+
2091
+ fn visit_expr ( & mut self , ex : & ' tcx hir:: Expr < ' tcx > ) {
2092
+ if let hir:: ExprKind :: Call ( rcvr, args) = ex. kind {
2093
+ self . calls . push ( ( rcvr, args) ) ;
2094
+ }
2095
+ hir:: intravisit:: walk_expr ( self , ex) ;
2096
+ }
2097
+ }
0 commit comments