@@ -21,15 +21,18 @@ use rustc_hir::def_id::DefId;
21
21
use rustc_hir:: { ExprKind , Node , QPath } ;
22
22
use rustc_index:: vec:: IndexVec ;
23
23
use rustc_infer:: infer:: error_reporting:: { FailureCode , ObligationCauseExt } ;
24
+ use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
24
25
use rustc_infer:: infer:: InferOk ;
25
26
use rustc_infer:: infer:: TypeTrace ;
26
27
use rustc_middle:: ty:: adjustment:: AllowTwoPhase ;
27
28
use rustc_middle:: ty:: visit:: TypeVisitable ;
28
- use rustc_middle:: ty:: { self , IsSuggestable , Ty , TyCtxt } ;
29
+ use rustc_middle:: ty:: { self , DefIdTree , IsSuggestable , Ty } ;
29
30
use rustc_session:: Session ;
30
31
use rustc_span:: symbol:: Ident ;
31
32
use rustc_span:: { self , Span } ;
32
- use rustc_trait_selection:: traits:: { self , ObligationCauseCode , StatementAsExpression } ;
33
+ use rustc_trait_selection:: traits:: {
34
+ self , ObligationCauseCode , SelectionContext , StatementAsExpression ,
35
+ } ;
33
36
34
37
use std:: iter;
35
38
use std:: slice;
@@ -89,7 +92,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
89
92
args_no_rcvr,
90
93
false ,
91
94
tuple_arguments,
92
- None ,
95
+ method . ok ( ) . map ( |method| method . def_id ) ,
93
96
) ;
94
97
return self . tcx . ty_error ( ) ;
95
98
}
@@ -393,41 +396,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
393
396
}
394
397
395
398
if !call_appears_satisfied {
396
- // Next, let's construct the error
397
- let ( error_span, full_call_span, ctor_of) = match & call_expr. kind {
398
- hir:: ExprKind :: Call (
399
- hir:: Expr {
400
- span,
401
- kind :
402
- hir:: ExprKind :: Path ( hir:: QPath :: Resolved (
403
- _,
404
- hir:: Path { res : Res :: Def ( DefKind :: Ctor ( of, _) , _) , .. } ,
405
- ) ) ,
406
- ..
407
- } ,
408
- _,
409
- ) => ( call_span, * span, Some ( of) ) ,
410
- hir:: ExprKind :: Call ( hir:: Expr { span, .. } , _) => ( call_span, * span, None ) ,
411
- hir:: ExprKind :: MethodCall ( path_segment, _, span) => {
412
- let ident_span = path_segment. ident . span ;
413
- let ident_span = if let Some ( args) = path_segment. args {
414
- ident_span. with_hi ( args. span_ext . hi ( ) )
415
- } else {
416
- ident_span
417
- } ;
418
- (
419
- * span, ident_span, None , // methods are never ctors
420
- )
421
- }
422
- k => span_bug ! ( call_span, "checking argument types on a non-call: `{:?}`" , k) ,
423
- } ;
424
- let args_span = error_span. trim_start ( full_call_span) . unwrap_or ( error_span) ;
425
- let call_name = match ctor_of {
426
- Some ( CtorOf :: Struct ) => "struct" ,
427
- Some ( CtorOf :: Variant ) => "enum variant" ,
428
- None => "function" ,
429
- } ;
430
-
431
399
let compatibility_diagonal = IndexVec :: from_raw ( compatibility_diagonal) ;
432
400
let provided_args = IndexVec :: from_iter ( provided_args. iter ( ) . take ( if c_variadic {
433
401
minimum_input_count
@@ -451,13 +419,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
451
419
compatibility_diagonal,
452
420
formal_and_expected_inputs,
453
421
provided_args,
454
- full_call_span,
455
- error_span,
456
- args_span,
457
- call_name,
458
422
c_variadic,
459
423
err_code,
460
424
fn_def_id,
425
+ call_span,
426
+ call_expr,
461
427
) ;
462
428
}
463
429
}
@@ -467,14 +433,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
467
433
compatibility_diagonal : IndexVec < ProvidedIdx , Compatibility < ' tcx > > ,
468
434
formal_and_expected_inputs : IndexVec < ExpectedIdx , ( Ty < ' tcx > , Ty < ' tcx > ) > ,
469
435
provided_args : IndexVec < ProvidedIdx , & ' tcx hir:: Expr < ' tcx > > ,
470
- full_call_span : Span ,
471
- error_span : Span ,
472
- args_span : Span ,
473
- call_name : & str ,
474
436
c_variadic : bool ,
475
437
err_code : & str ,
476
438
fn_def_id : Option < DefId > ,
439
+ call_span : Span ,
440
+ call_expr : & hir:: Expr < ' tcx > ,
477
441
) {
442
+ // Next, let's construct the error
443
+ let ( error_span, full_call_span, ctor_of) = match & call_expr. kind {
444
+ hir:: ExprKind :: Call (
445
+ hir:: Expr {
446
+ span,
447
+ kind :
448
+ hir:: ExprKind :: Path ( hir:: QPath :: Resolved (
449
+ _,
450
+ hir:: Path { res : Res :: Def ( DefKind :: Ctor ( of, _) , _) , .. } ,
451
+ ) ) ,
452
+ ..
453
+ } ,
454
+ _,
455
+ ) => ( call_span, * span, Some ( of) ) ,
456
+ hir:: ExprKind :: Call ( hir:: Expr { span, .. } , _) => ( call_span, * span, None ) ,
457
+ hir:: ExprKind :: MethodCall ( path_segment, _, span) => {
458
+ let ident_span = path_segment. ident . span ;
459
+ let ident_span = if let Some ( args) = path_segment. args {
460
+ ident_span. with_hi ( args. span_ext . hi ( ) )
461
+ } else {
462
+ ident_span
463
+ } ;
464
+ (
465
+ * span, ident_span, None , // methods are never ctors
466
+ )
467
+ }
468
+ k => span_bug ! ( call_span, "checking argument types on a non-call: `{:?}`" , k) ,
469
+ } ;
470
+ let args_span = error_span. trim_start ( full_call_span) . unwrap_or ( error_span) ;
471
+ let call_name = match ctor_of {
472
+ Some ( CtorOf :: Struct ) => "struct" ,
473
+ Some ( CtorOf :: Variant ) => "enum variant" ,
474
+ None => "function" ,
475
+ } ;
476
+
478
477
// Don't print if it has error types or is just plain `_`
479
478
fn has_error_or_infer < ' tcx > ( tys : impl IntoIterator < Item = Ty < ' tcx > > ) -> bool {
480
479
tys. into_iter ( ) . any ( |ty| ty. references_error ( ) || ty. is_ty_var ( ) )
@@ -495,6 +494,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
495
494
( self . resolve_vars_if_possible ( ty) , expr. span )
496
495
} )
497
496
. collect ( ) ;
497
+ let callee_expr = match & call_expr. peel_blocks ( ) . kind {
498
+ hir:: ExprKind :: Call ( callee, _) => Some ( * callee) ,
499
+ hir:: ExprKind :: MethodCall ( _, callee, _) => {
500
+ if let Some ( ( DefKind :: AssocFn , def_id) ) =
501
+ self . typeck_results . borrow ( ) . type_dependent_def ( call_expr. hir_id )
502
+ && let Some ( assoc) = tcx. opt_associated_item ( def_id)
503
+ && assoc. fn_has_self_parameter
504
+ {
505
+ Some ( & callee[ 0 ] )
506
+ } else {
507
+ None
508
+ }
509
+ }
510
+ _ => None ,
511
+ } ;
512
+ let callee_ty = callee_expr
513
+ . and_then ( |callee_expr| self . typeck_results . borrow ( ) . expr_ty_adjusted_opt ( callee_expr) ) ;
498
514
499
515
// A "softer" version of the `demand_compatible`, which checks types without persisting them,
500
516
// and treats error types differently
@@ -631,7 +647,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
631
647
Applicability :: MachineApplicable ,
632
648
) ;
633
649
} ;
634
- label_fn_like ( tcx , & mut err, fn_def_id) ;
650
+ self . label_fn_like ( & mut err, fn_def_id, callee_ty ) ;
635
651
err. emit ( ) ;
636
652
return ;
637
653
}
@@ -721,7 +737,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
721
737
format ! ( "arguments to this {} are incorrect" , call_name) ,
722
738
) ;
723
739
// Call out where the function is defined
724
- label_fn_like ( tcx , & mut err, fn_def_id) ;
740
+ self . label_fn_like ( & mut err, fn_def_id, callee_ty ) ;
725
741
err. emit ( ) ;
726
742
return ;
727
743
}
@@ -1003,7 +1019,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1003
1019
}
1004
1020
1005
1021
// Call out where the function is defined
1006
- label_fn_like ( tcx , & mut err, fn_def_id) ;
1022
+ self . label_fn_like ( & mut err, fn_def_id, callee_ty ) ;
1007
1023
1008
1024
// And add a suggestion block for all of the parameters
1009
1025
let suggestion_text = match suggestion_text {
@@ -1795,47 +1811,126 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1795
1811
}
1796
1812
}
1797
1813
}
1798
- }
1799
1814
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 , "" ) ;
1815
+ fn label_fn_like (
1816
+ & self ,
1817
+ err : & mut rustc_errors:: DiagnosticBuilder < ' tcx , rustc_errors:: ErrorGuaranteed > ,
1818
+ callable_def_id : Option < DefId > ,
1819
+ callee_ty : Option < Ty < ' tcx > > ,
1820
+ ) {
1821
+ let Some ( mut def_id) = callable_def_id else {
1822
+ return ;
1823
+ } ;
1824
+
1825
+ if let Some ( assoc_item) = self . tcx . opt_associated_item ( def_id)
1826
+ // Possibly points at either impl or trait item, so try to get it
1827
+ // to point to trait item, then get the parent.
1828
+ // This parent might be an impl in the case of an inherent function,
1829
+ // but the next check will fail.
1830
+ && let maybe_trait_item_def_id = assoc_item. trait_item_def_id . unwrap_or ( def_id)
1831
+ && let maybe_trait_def_id = self . tcx . parent ( maybe_trait_item_def_id)
1832
+ // Just an easy way to check "trait_def_id == Fn/FnMut/FnOnce"
1833
+ && let Some ( call_kind) = ty:: ClosureKind :: from_def_id ( self . tcx , maybe_trait_def_id)
1834
+ && let Some ( callee_ty) = callee_ty
1835
+ {
1836
+ let callee_ty = callee_ty. peel_refs ( ) ;
1837
+ match * callee_ty. kind ( ) {
1838
+ ty:: Param ( param) => {
1839
+ let param =
1840
+ self . tcx . generics_of ( self . body_id . owner ) . type_param ( & param, self . tcx ) ;
1841
+ if param. kind . is_synthetic ( ) {
1842
+ // if it's `impl Fn() -> ..` then just fall down to the def-id based logic
1843
+ def_id = param. def_id ;
1844
+ } else {
1845
+ // Otherwise, find the predicate that makes this generic callable,
1846
+ // and point at that.
1847
+ let instantiated = self
1848
+ . tcx
1849
+ . explicit_predicates_of ( self . body_id . owner )
1850
+ . instantiate_identity ( self . tcx ) ;
1851
+ // FIXME(compiler-errors): This could be problematic if something has two
1852
+ // fn-like predicates with different args, but callable types really never
1853
+ // do that, so it's OK.
1854
+ for ( predicate, span) in
1855
+ std:: iter:: zip ( instantiated. predicates , instantiated. spans )
1856
+ {
1857
+ if let ty:: PredicateKind :: Trait ( pred) = predicate. kind ( ) . skip_binder ( )
1858
+ && pred. self_ty ( ) . peel_refs ( ) == callee_ty
1859
+ && ty:: ClosureKind :: from_def_id ( self . tcx , pred. def_id ( ) ) . is_some ( )
1860
+ {
1861
+ err. span_note ( span, "callable defined here" ) ;
1862
+ return ;
1863
+ }
1864
+ }
1865
+ }
1866
+ }
1867
+ ty:: Opaque ( new_def_id, _)
1868
+ | ty:: Closure ( new_def_id, _)
1869
+ | ty:: FnDef ( new_def_id, _) => {
1870
+ def_id = new_def_id;
1871
+ }
1872
+ _ => {
1873
+ // Look for a user-provided impl of a `Fn` trait, and point to it.
1874
+ let new_def_id = self . probe ( |_| {
1875
+ let trait_ref = ty:: TraitRef :: new (
1876
+ call_kind. to_def_id ( self . tcx ) ,
1877
+ self . tcx . mk_substs ( [
1878
+ ty:: GenericArg :: from ( callee_ty) ,
1879
+ self . next_ty_var ( TypeVariableOrigin {
1880
+ kind : TypeVariableOriginKind :: MiscVariable ,
1881
+ span : rustc_span:: DUMMY_SP ,
1882
+ } )
1883
+ . into ( ) ,
1884
+ ] . into_iter ( ) ) ,
1885
+ ) ;
1886
+ let obligation = traits:: Obligation :: new (
1887
+ traits:: ObligationCause :: dummy ( ) ,
1888
+ self . param_env ,
1889
+ ty:: Binder :: dummy ( ty:: TraitPredicate {
1890
+ trait_ref,
1891
+ constness : ty:: BoundConstness :: NotConst ,
1892
+ polarity : ty:: ImplPolarity :: Positive ,
1893
+ } ) ,
1894
+ ) ;
1895
+ match SelectionContext :: new ( & self ) . select ( & obligation) {
1896
+ Ok ( Some ( traits:: ImplSource :: UserDefined ( impl_source) ) ) => {
1897
+ Some ( impl_source. impl_def_id )
1898
+ }
1899
+ _ => None
1900
+ }
1901
+ } ) ;
1902
+ if let Some ( new_def_id) = new_def_id {
1903
+ def_id = new_def_id;
1904
+ } else {
1905
+ return ;
1906
+ }
1907
+ }
1908
+ }
1821
1909
}
1822
1910
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 ( ) ;
1911
+ if let Some ( def_span) = self . tcx . def_ident_span ( def_id) && !def_span. is_dummy ( ) {
1912
+ let mut spans: MultiSpan = def_span. into ( ) ;
1832
1913
1833
- // Note: We don't point to param spans here because they overlap
1834
- // with the closure span itself
1914
+ let params = self
1915
+ . tcx
1916
+ . hir ( )
1917
+ . get_if_local ( def_id)
1918
+ . and_then ( |node| node. body_id ( ) )
1919
+ . into_iter ( )
1920
+ . flat_map ( |id| self . tcx . hir ( ) . body ( id) . params ) ;
1835
1921
1836
- err. span_note ( spans, "closure defined here" ) ;
1922
+ for param in params {
1923
+ spans. push_span_label ( param. span , "" ) ;
1837
1924
}
1838
- _ => { }
1925
+
1926
+ let def_kind = self . tcx . def_kind ( def_id) ;
1927
+ err. span_note ( spans, & format ! ( "{} defined here" , def_kind. descr( def_id) ) ) ;
1928
+ } else {
1929
+ let def_kind = self . tcx . def_kind ( def_id) ;
1930
+ err. span_note (
1931
+ self . tcx . def_span ( def_id) ,
1932
+ & format ! ( "{} defined here" , def_kind. descr( def_id) ) ,
1933
+ ) ;
1839
1934
}
1840
1935
}
1841
1936
}
0 commit comments