@@ -16,6 +16,7 @@ use rustc_errors::{
1616use rustc_hir as hir;
1717use rustc_hir:: def:: { CtorOf , DefKind , Res } ;
1818use rustc_hir:: def_id:: DefId ;
19+ use rustc_hir:: intravisit:: Visitor ;
1920use rustc_hir:: { ExprKind , Node , QPath } ;
2021use rustc_hir_analysis:: astconv:: AstConv ;
2122use rustc_hir_analysis:: check:: intrinsicck:: InlineAsmCtxt ;
@@ -28,7 +29,7 @@ use rustc_infer::infer::TypeTrace;
2829use rustc_infer:: infer:: { DefineOpaqueTypes , InferOk } ;
2930use rustc_middle:: ty:: adjustment:: AllowTwoPhase ;
3031use rustc_middle:: ty:: visit:: TypeVisitableExt ;
31- use rustc_middle:: ty:: { self , IsSuggestable , Ty } ;
32+ use rustc_middle:: ty:: { self , IsSuggestable , Ty , TyCtxt } ;
3233use rustc_session:: Session ;
3334use rustc_span:: symbol:: { kw, Ident } ;
3435use rustc_span:: { self , sym, BytePos , Span } ;
@@ -722,6 +723,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
722723 & mut err,
723724 fn_def_id,
724725 callee_ty,
726+ call_expr,
727+ None ,
725728 Some ( mismatch_idx) ,
726729 is_method,
727730 ) ;
@@ -826,6 +829,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
826829 & mut err,
827830 fn_def_id,
828831 callee_ty,
832+ call_expr,
833+ Some ( expected_ty) ,
829834 Some ( expected_idx. as_usize ( ) ) ,
830835 is_method,
831836 ) ;
@@ -1208,7 +1213,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12081213 }
12091214
12101215 // 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) ;
12121217
12131218 // And add a suggestion block for all of the parameters
12141219 let suggestion_text = match suggestion_text {
@@ -1899,6 +1904,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18991904 err : & mut Diagnostic ,
19001905 callable_def_id : Option < DefId > ,
19011906 callee_ty : Option < Ty < ' tcx > > ,
1907+ call_expr : & ' tcx hir:: Expr < ' tcx > ,
1908+ expected_ty : Option < Ty < ' tcx > > ,
19021909 // A specific argument should be labeled, instead of all of them
19031910 expected_idx : Option < usize > ,
19041911 is_method : bool ,
@@ -2015,6 +2022,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20152022 let param = expected_idx
20162023 . and_then ( |expected_idx| self . tcx . hir ( ) . body ( * body) . params . get ( expected_idx) ) ;
20172024 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+
20182065 ( "closure parameter" , param. span )
20192066 } else {
20202067 ( "closure" , self . tcx . def_span ( def_id) )
@@ -2028,3 +2075,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20282075 }
20292076 }
20302077}
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