@@ -61,55 +61,64 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
6161 pointing_at_return_type
6262 }
6363
64- /// When encountering an fn-like ctor that needs to unify with a value, check whether calling
65- /// the ctor would successfully solve the type mismatch and if so, suggest it:
64+ /// When encountering an fn-like type, try accessing the output of the type
65+ /// // and suggesting calling it if it satisfies a predicate (i.e. if the
66+ /// output has a method or a field):
6667 /// ```compile_fail,E0308
6768 /// fn foo(x: usize) -> usize { x }
6869 /// let x: usize = foo; // suggest calling the `foo` function: `foo(42)`
6970 /// ```
70- fn suggest_fn_call (
71+ pub ( crate ) fn suggest_fn_call (
7172 & self ,
7273 err : & mut Diagnostic ,
7374 expr : & hir:: Expr < ' _ > ,
74- expected : Ty < ' tcx > ,
7575 found : Ty < ' tcx > ,
76+ can_satisfy : impl FnOnce ( Ty < ' tcx > ) -> bool ,
7677 ) -> bool {
77- let ( def_id, output, inputs) = match * found. kind ( ) {
78- ty:: FnDef ( def_id, _) => {
79- let fn_sig = found. fn_sig ( self . tcx ) ;
80- ( def_id, fn_sig. output ( ) , fn_sig. inputs ( ) . skip_binder ( ) . len ( ) )
81- }
82- ty:: Closure ( def_id, substs) => {
83- let fn_sig = substs. as_closure ( ) . sig ( ) ;
84- ( def_id, fn_sig. output ( ) , fn_sig. inputs ( ) . skip_binder ( ) . len ( ) - 1 )
85- }
86- ty:: Opaque ( def_id, substs) => {
87- let sig = self . tcx . bound_item_bounds ( def_id) . subst ( self . tcx , substs) . iter ( ) . find_map ( |pred| {
88- if let ty:: PredicateKind :: Projection ( proj) = pred. kind ( ) . skip_binder ( )
89- && Some ( proj. projection_ty . item_def_id ) == self . tcx . lang_items ( ) . fn_once_output ( )
90- // args tuple will always be substs[1]
91- && let ty:: Tuple ( args) = proj. projection_ty . substs . type_at ( 1 ) . kind ( )
92- {
93- Some ( (
94- pred. kind ( ) . rebind ( proj. term . ty ( ) . unwrap ( ) ) ,
95- args. len ( ) ,
96- ) )
78+ // Autoderef is useful here because sometimes we box callables, etc.
79+ let Some ( ( def_id, output, inputs) ) = self . autoderef ( expr. span , found) . silence_errors ( ) . find_map ( |( found, _) | {
80+ match * found. kind ( ) {
81+ ty:: FnPtr ( fn_sig) => Some ( ( None , fn_sig. output ( ) , fn_sig. inputs ( ) . skip_binder ( ) . len ( ) ) ) ,
82+ ty:: FnDef ( def_id, _) => {
83+ let fn_sig = found. fn_sig ( self . tcx ) ;
84+ Some ( ( Some ( def_id) , fn_sig. output ( ) , fn_sig. inputs ( ) . skip_binder ( ) . len ( ) ) )
85+ }
86+ ty:: Closure ( def_id, substs) => {
87+ let fn_sig = substs. as_closure ( ) . sig ( ) ;
88+ Some ( ( Some ( def_id) , fn_sig. output ( ) , fn_sig. inputs ( ) . skip_binder ( ) . len ( ) - 1 ) )
89+ }
90+ ty:: Opaque ( def_id, substs) => {
91+ let sig = self . tcx . bound_item_bounds ( def_id) . subst ( self . tcx , substs) . iter ( ) . find_map ( |pred| {
92+ if let ty:: PredicateKind :: Projection ( proj) = pred. kind ( ) . skip_binder ( )
93+ && Some ( proj. projection_ty . item_def_id ) == self . tcx . lang_items ( ) . fn_once_output ( )
94+ // args tuple will always be substs[1]
95+ && let ty:: Tuple ( args) = proj. projection_ty . substs . type_at ( 1 ) . kind ( )
96+ {
97+ Some ( (
98+ pred. kind ( ) . rebind ( proj. term . ty ( ) . unwrap ( ) ) ,
99+ args. len ( ) ,
100+ ) )
101+ } else {
102+ None
103+ }
104+ } ) ;
105+ if let Some ( ( output, inputs) ) = sig {
106+ Some ( ( Some ( def_id) , output, inputs) )
97107 } else {
98108 None
99109 }
100- } ) ;
101- if let Some ( ( output, inputs) ) = sig {
102- ( def_id, output, inputs)
103- } else {
104- return false ;
105110 }
111+ _ => None ,
106112 }
107- _ => return false ,
108- } ;
113+ } ) else { return false ; } ;
109114
110115 let output = self . replace_bound_vars_with_fresh_vars ( expr. span , infer:: FnCall , output) ;
111- let output = self . normalize_associated_types_in ( expr. span , output) ;
112- if !output. is_ty_var ( ) && self . can_coerce ( output, expected) {
116+ // We don't want to register any extra obligations, which should be
117+ // implied by wf, but also because that would possibly result in
118+ // erroneous errors later on.
119+ let infer:: InferOk { value : output, obligations : _ } =
120+ self . normalize_associated_types_in_as_infer_ok ( expr. span , output) ;
121+ if !output. is_ty_var ( ) && can_satisfy ( output) {
113122 let ( sugg_call, mut applicability) = match inputs {
114123 0 => ( "" . to_string ( ) , Applicability :: MachineApplicable ) ,
115124 1 ..=4 => (
@@ -119,11 +128,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
119128 _ => ( "..." . to_string ( ) , Applicability :: HasPlaceholders ) ,
120129 } ;
121130
122- let msg = match self . tcx . def_kind ( def_id) {
123- DefKind :: Fn => "call this function" ,
124- DefKind :: Closure | DefKind :: OpaqueTy => "call this closure" ,
125- DefKind :: Ctor ( CtorOf :: Struct , _) => "instantiate this tuple struct" ,
126- DefKind :: Ctor ( CtorOf :: Variant , _) => "instantiate this tuple variant" ,
131+ let msg = match def_id . map ( |def_id| self . tcx . def_kind ( def_id) ) {
132+ Some ( DefKind :: Fn ) => "call this function" ,
133+ Some ( DefKind :: Closure | DefKind :: OpaqueTy ) => "call this closure" ,
134+ Some ( DefKind :: Ctor ( CtorOf :: Struct , _) ) => "instantiate this tuple struct" ,
135+ Some ( DefKind :: Ctor ( CtorOf :: Variant , _) ) => "instantiate this tuple variant" ,
127136 _ => "call this function" ,
128137 } ;
129138
@@ -178,12 +187,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
178187 } else {
179188 err. span_suggestion ( sp, & msg, suggestion, applicability) ;
180189 }
181- } else if let ( ty:: FnDef ( def_id, ..) , true ) =
182- ( & found. kind ( ) , self . suggest_fn_call ( err, expr, expected, found) )
190+ } else if self . suggest_fn_call ( err, expr, found, |output| self . can_coerce ( output, expected) )
191+ && let ty:: FnDef ( def_id, ..) = & found. kind ( )
192+ && let Some ( sp) = self . tcx . hir ( ) . span_if_local ( * def_id)
183193 {
184- if let Some ( sp) = self . tcx . hir ( ) . span_if_local ( * def_id) {
185- err. span_label ( sp, format ! ( "{found} defined here" ) ) ;
186- }
194+ err. span_label ( sp, format ! ( "{found} defined here" ) ) ;
187195 } else if !self . check_for_cast ( err, expr, found, expected, expected_ty_expr) {
188196 let methods = self . get_conversion_methods ( expr. span , expected, found, expr. hir_id ) ;
189197 if !methods. is_empty ( ) {
0 commit comments