@@ -21,15 +21,18 @@ use rustc_hir::def_id::DefId;
2121use rustc_hir:: { ExprKind , Node , QPath } ;
2222use rustc_index:: vec:: IndexVec ;
2323use rustc_infer:: infer:: error_reporting:: { FailureCode , ObligationCauseExt } ;
24+ use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
2425use rustc_infer:: infer:: InferOk ;
2526use rustc_infer:: infer:: TypeTrace ;
2627use rustc_middle:: ty:: adjustment:: AllowTwoPhase ;
2728use rustc_middle:: ty:: visit:: TypeVisitable ;
28- use rustc_middle:: ty:: { self , IsSuggestable , Ty , TyCtxt } ;
29+ use rustc_middle:: ty:: { self , DefIdTree , IsSuggestable , Ty } ;
2930use rustc_session:: Session ;
3031use rustc_span:: symbol:: Ident ;
3132use 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+ } ;
3336
3437use std:: iter;
3538use std:: slice;
@@ -89,7 +92,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
8992 args_no_rcvr,
9093 false ,
9194 tuple_arguments,
92- None ,
95+ method . ok ( ) . map ( |method| method . def_id ) ,
9396 ) ;
9497 return self . tcx . ty_error ( ) ;
9598 }
@@ -393,41 +396,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
393396 }
394397
395398 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-
431399 let compatibility_diagonal = IndexVec :: from_raw ( compatibility_diagonal) ;
432400 let provided_args = IndexVec :: from_iter ( provided_args. iter ( ) . take ( if c_variadic {
433401 minimum_input_count
@@ -451,13 +419,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
451419 compatibility_diagonal,
452420 formal_and_expected_inputs,
453421 provided_args,
454- full_call_span,
455- error_span,
456- args_span,
457- call_name,
458422 c_variadic,
459423 err_code,
460424 fn_def_id,
425+ call_span,
426+ call_expr,
461427 ) ;
462428 }
463429 }
@@ -467,14 +433,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
467433 compatibility_diagonal : IndexVec < ProvidedIdx , Compatibility < ' tcx > > ,
468434 formal_and_expected_inputs : IndexVec < ExpectedIdx , ( Ty < ' tcx > , Ty < ' tcx > ) > ,
469435 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 ,
474436 c_variadic : bool ,
475437 err_code : & str ,
476438 fn_def_id : Option < DefId > ,
439+ call_span : Span ,
440+ call_expr : & hir:: Expr < ' tcx > ,
477441 ) {
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+
478477 // Don't print if it has error types or is just plain `_`
479478 fn has_error_or_infer < ' tcx > ( tys : impl IntoIterator < Item = Ty < ' tcx > > ) -> bool {
480479 tys. into_iter ( ) . any ( |ty| ty. references_error ( ) || ty. is_ty_var ( ) )
@@ -495,6 +494,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
495494 ( self . resolve_vars_if_possible ( ty) , expr. span )
496495 } )
497496 . 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) ) ;
498514
499515 // A "softer" version of the `demand_compatible`, which checks types without persisting them,
500516 // and treats error types differently
@@ -631,7 +647,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
631647 Applicability :: MachineApplicable ,
632648 ) ;
633649 } ;
634- label_fn_like ( tcx , & mut err, fn_def_id) ;
650+ self . label_fn_like ( & mut err, fn_def_id, callee_ty ) ;
635651 err. emit ( ) ;
636652 return ;
637653 }
@@ -721,7 +737,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
721737 format ! ( "arguments to this {} are incorrect" , call_name) ,
722738 ) ;
723739 // 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 ) ;
725741 err. emit ( ) ;
726742 return ;
727743 }
@@ -1003,7 +1019,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10031019 }
10041020
10051021 // 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 ) ;
10071023
10081024 // And add a suggestion block for all of the parameters
10091025 let suggestion_text = match suggestion_text {
@@ -1795,47 +1811,126 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17951811 }
17961812 }
17971813 }
1798- }
17991814
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+ }
18211909 }
18221910
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 ( ) ;
18321913
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 ) ;
18351921
1836- err. span_note ( spans, "closure defined here" ) ;
1922+ for param in params {
1923+ spans. push_span_label ( param. span , "" ) ;
18371924 }
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+ ) ;
18391934 }
18401935 }
18411936}
0 commit comments