@@ -25,7 +25,7 @@ use rustc_infer::infer::InferOk;
25
25
use rustc_infer:: infer:: TypeTrace ;
26
26
use rustc_middle:: ty:: adjustment:: AllowTwoPhase ;
27
27
use rustc_middle:: ty:: visit:: TypeVisitable ;
28
- use rustc_middle:: ty:: { self , IsSuggestable , Ty , TyCtxt } ;
28
+ use rustc_middle:: ty:: { self , DefIdTree , IsSuggestable , Ty } ;
29
29
use rustc_session:: Session ;
30
30
use rustc_span:: symbol:: Ident ;
31
31
use rustc_span:: { self , Span } ;
@@ -89,7 +89,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
89
89
args_no_rcvr,
90
90
false ,
91
91
tuple_arguments,
92
- None ,
92
+ method . ok ( ) . map ( |method| method . def_id ) ,
93
93
) ;
94
94
return self . tcx . ty_error ( ) ;
95
95
}
@@ -458,6 +458,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
458
458
c_variadic,
459
459
err_code,
460
460
fn_def_id,
461
+ call_expr,
461
462
) ;
462
463
}
463
464
}
@@ -474,6 +475,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
474
475
c_variadic : bool ,
475
476
err_code : & str ,
476
477
fn_def_id : Option < DefId > ,
478
+ call_expr : & hir:: Expr < ' tcx > ,
477
479
) {
478
480
// Don't print if it has error types or is just plain `_`
479
481
fn has_error_or_infer < ' tcx > ( tys : impl IntoIterator < Item = Ty < ' tcx > > ) -> bool {
@@ -495,6 +497,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
495
497
( self . resolve_vars_if_possible ( ty) , expr. span )
496
498
} )
497
499
. 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) ) ;
498
517
499
518
// A "softer" version of the `demand_compatible`, which checks types without persisting them,
500
519
// and treats error types differently
@@ -631,7 +650,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
631
650
Applicability :: MachineApplicable ,
632
651
) ;
633
652
} ;
634
- label_fn_like ( tcx , & mut err, fn_def_id) ;
653
+ self . label_fn_like ( & mut err, fn_def_id, callee_ty ) ;
635
654
err. emit ( ) ;
636
655
return ;
637
656
}
@@ -721,7 +740,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
721
740
format ! ( "arguments to this {} are incorrect" , call_name) ,
722
741
) ;
723
742
// 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 ) ;
725
744
err. emit ( ) ;
726
745
return ;
727
746
}
@@ -1003,7 +1022,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1003
1022
}
1004
1023
1005
1024
// 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 ) ;
1007
1026
1008
1027
// And add a suggestion block for all of the parameters
1009
1028
let suggestion_text = match suggestion_text {
@@ -1795,47 +1814,86 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1795
1814
}
1796
1815
}
1797
1816
}
1798
- }
1799
1817
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
+ }
1821
1872
}
1822
1873
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 ( ) ;
1832
1876
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 ) ;
1835
1884
1836
- err. span_note ( spans, "closure defined here" ) ;
1885
+ for param in params {
1886
+ spans. push_span_label ( param. span , "" ) ;
1837
1887
}
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
+ ) ;
1839
1897
}
1840
1898
}
1841
1899
}
0 commit comments