@@ -25,7 +25,7 @@ use rustc_infer::infer::InferOk;
2525use rustc_infer:: infer:: TypeTrace ;
2626use rustc_middle:: ty:: adjustment:: AllowTwoPhase ;
2727use rustc_middle:: ty:: visit:: TypeVisitable ;
28- use rustc_middle:: ty:: { self , IsSuggestable , Ty , TyCtxt } ;
28+ use rustc_middle:: ty:: { self , DefIdTree , IsSuggestable , Ty } ;
2929use rustc_session:: Session ;
3030use rustc_span:: symbol:: Ident ;
3131use rustc_span:: { self , Span } ;
@@ -89,7 +89,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
8989 args_no_rcvr,
9090 false ,
9191 tuple_arguments,
92- None ,
92+ method . ok ( ) . map ( |method| method . def_id ) ,
9393 ) ;
9494 return self . tcx . ty_error ( ) ;
9595 }
@@ -458,6 +458,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
458458 c_variadic,
459459 err_code,
460460 fn_def_id,
461+ call_expr,
461462 ) ;
462463 }
463464 }
@@ -474,6 +475,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
474475 c_variadic : bool ,
475476 err_code : & str ,
476477 fn_def_id : Option < DefId > ,
478+ call_expr : & hir:: Expr < ' tcx > ,
477479 ) {
478480 // Don't print if it has error types or is just plain `_`
479481 fn has_error_or_infer < ' tcx > ( tys : impl IntoIterator < Item = Ty < ' tcx > > ) -> bool {
@@ -495,6 +497,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
495497 ( self . resolve_vars_if_possible ( ty) , expr. span )
496498 } )
497499 . collect ( ) ;
500+ let callee_expr = match & call_expr. peel_blocks ( ) . kind {
501+ hir:: ExprKind :: Call ( callee, _) => Some ( * callee) ,
502+ hir:: ExprKind :: MethodCall ( _, callee, _) => {
503+ if let Some ( ( DefKind :: AssocFn , def_id) ) =
504+ self . typeck_results . borrow ( ) . type_dependent_def ( call_expr. hir_id )
505+ && let Some ( assoc) = tcx. opt_associated_item ( def_id)
506+ && assoc. fn_has_self_parameter
507+ {
508+ Some ( & callee[ 0 ] )
509+ } else {
510+ None
511+ }
512+ }
513+ _ => None ,
514+ } ;
515+ let callee_ty = callee_expr
516+ . and_then ( |callee_expr| self . typeck_results . borrow ( ) . expr_ty_adjusted_opt ( callee_expr) ) ;
498517
499518 // A "softer" version of the `demand_compatible`, which checks types without persisting them,
500519 // and treats error types differently
@@ -631,7 +650,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
631650 Applicability :: MachineApplicable ,
632651 ) ;
633652 } ;
634- label_fn_like ( tcx , & mut err, fn_def_id) ;
653+ self . label_fn_like ( & mut err, fn_def_id, callee_ty ) ;
635654 err. emit ( ) ;
636655 return ;
637656 }
@@ -721,7 +740,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
721740 format ! ( "arguments to this {} are incorrect" , call_name) ,
722741 ) ;
723742 // Call out where the function is defined
724- label_fn_like ( tcx , & mut err, fn_def_id) ;
743+ self . label_fn_like ( & mut err, fn_def_id, callee_ty ) ;
725744 err. emit ( ) ;
726745 return ;
727746 }
@@ -1003,7 +1022,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10031022 }
10041023
10051024 // Call out where the function is defined
1006- label_fn_like ( tcx , & mut err, fn_def_id) ;
1025+ self . label_fn_like ( & mut err, fn_def_id, callee_ty ) ;
10071026
10081027 // And add a suggestion block for all of the parameters
10091028 let suggestion_text = match suggestion_text {
@@ -1795,47 +1814,86 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17951814 }
17961815 }
17971816 }
1798- }
17991817
1800- fn label_fn_like < ' tcx > (
1801- tcx : TyCtxt < ' tcx > ,
1802- err : & mut rustc_errors:: DiagnosticBuilder < ' tcx , rustc_errors:: ErrorGuaranteed > ,
1803- def_id : Option < DefId > ,
1804- ) {
1805- let Some ( def_id) = def_id else {
1806- return ;
1807- } ;
1808-
1809- if let Some ( def_span) = tcx. def_ident_span ( def_id) {
1810- let mut spans: MultiSpan = def_span. into ( ) ;
1811-
1812- let params = tcx
1813- . hir ( )
1814- . get_if_local ( def_id)
1815- . and_then ( |node| node. body_id ( ) )
1816- . into_iter ( )
1817- . flat_map ( |id| tcx. hir ( ) . body ( id) . params ) ;
1818-
1819- for param in params {
1820- spans. push_span_label ( param. span , "" ) ;
1818+ fn label_fn_like (
1819+ & self ,
1820+ err : & mut rustc_errors:: DiagnosticBuilder < ' tcx , rustc_errors:: ErrorGuaranteed > ,
1821+ def_id : Option < DefId > ,
1822+ callee_ty : Option < Ty < ' tcx > > ,
1823+ ) {
1824+ let Some ( mut def_id) = def_id else {
1825+ return ;
1826+ } ;
1827+
1828+ if let Some ( assoc_item) = self . tcx . opt_associated_item ( def_id)
1829+ && let trait_def_id = assoc_item. trait_item_def_id . unwrap_or_else ( || self . tcx . parent ( def_id) )
1830+ // Just an easy way to check "trait_def_id == Fn/FnMut/FnOnce"
1831+ && ty:: ClosureKind :: from_def_id ( self . tcx , trait_def_id) . is_some ( )
1832+ && let Some ( callee_ty) = callee_ty
1833+ {
1834+ let callee_ty = callee_ty. peel_refs ( ) ;
1835+ match * callee_ty. kind ( ) {
1836+ ty:: Param ( param) => {
1837+ let param =
1838+ self . tcx . generics_of ( self . body_id . owner ) . type_param ( & param, self . tcx ) ;
1839+ if param. kind . is_synthetic ( ) {
1840+ // if it's `impl Fn() -> ..` then just fall down to the def-id based logic
1841+ def_id = param. def_id ;
1842+ } else {
1843+ // Otherwise, find the predicate that makes this generic callable,
1844+ // and point at that.
1845+ let instantiated = self
1846+ . tcx
1847+ . explicit_predicates_of ( self . body_id . owner )
1848+ . instantiate_identity ( self . tcx ) ;
1849+ // FIXME(compiler-errors): This could be problematic if something has two
1850+ // fn-like predicates with different args, but callable types really never
1851+ // do that, so it's OK.
1852+ for ( predicate, span) in
1853+ std:: iter:: zip ( instantiated. predicates , instantiated. spans )
1854+ {
1855+ if let ty:: PredicateKind :: Trait ( pred) = predicate. kind ( ) . skip_binder ( )
1856+ && pred. self_ty ( ) == callee_ty
1857+ && ty:: ClosureKind :: from_def_id ( self . tcx , pred. def_id ( ) ) . is_some ( )
1858+ {
1859+ err. span_note ( span, "callable defined here" ) ;
1860+ return ;
1861+ }
1862+ }
1863+ }
1864+ }
1865+ ty:: Opaque ( new_def_id, _) | ty:: Closure ( new_def_id, _) | ty:: FnDef ( new_def_id, _) => {
1866+ def_id = new_def_id;
1867+ }
1868+ _ => {
1869+ return ;
1870+ }
1871+ }
18211872 }
18221873
1823- let def_kind = tcx. def_kind ( def_id) ;
1824- err. span_note ( spans, & format ! ( "{} defined here" , def_kind. descr( def_id) ) ) ;
1825- } else {
1826- match tcx. hir ( ) . get_if_local ( def_id) {
1827- Some ( hir:: Node :: Expr ( hir:: Expr {
1828- kind : hir:: ExprKind :: Closure ( hir:: Closure { fn_decl_span, .. } ) ,
1829- ..
1830- } ) ) => {
1831- let spans: MultiSpan = ( * fn_decl_span) . into ( ) ;
1874+ if let Some ( def_span) = self . tcx . def_ident_span ( def_id) && !def_span. is_dummy ( ) {
1875+ let mut spans: MultiSpan = def_span. into ( ) ;
18321876
1833- // Note: We don't point to param spans here because they overlap
1834- // with the closure span itself
1877+ let params = self
1878+ . tcx
1879+ . hir ( )
1880+ . get_if_local ( def_id)
1881+ . and_then ( |node| node. body_id ( ) )
1882+ . into_iter ( )
1883+ . flat_map ( |id| self . tcx . hir ( ) . body ( id) . params ) ;
18351884
1836- err. span_note ( spans, "closure defined here" ) ;
1885+ for param in params {
1886+ spans. push_span_label ( param. span , "" ) ;
18371887 }
1838- _ => { }
1888+
1889+ let def_kind = self . tcx . def_kind ( def_id) ;
1890+ err. span_note ( spans, & format ! ( "{} defined here" , def_kind. descr( def_id) ) ) ;
1891+ } else if let def_kind @ ( DefKind :: Closure | DefKind :: OpaqueTy ) = self . tcx . def_kind ( def_id)
1892+ {
1893+ err. span_note (
1894+ self . tcx . def_span ( def_id) ,
1895+ & format ! ( "{} defined here" , def_kind. descr( def_id) ) ,
1896+ ) ;
18391897 }
18401898 }
18411899}
0 commit comments