@@ -8,15 +8,14 @@ use rustc_hir as hir;
88use  rustc_hir:: def:: { CtorOf ,  DefKind } ; 
99use  rustc_hir:: lang_items:: LangItem ; 
1010use  rustc_hir:: { 
11-     Expr ,  ExprKind ,  GenericBound ,  ItemKind ,  Node ,  Path ,  QPath ,  Stmt ,  StmtKind ,  TyKind , 
12-     WherePredicate , 
11+     Expr ,  ExprKind ,  GenericBound ,  Node ,  Path ,  QPath ,  Stmt ,  StmtKind ,  TyKind ,  WherePredicate , 
1312} ; 
1413use  rustc_infer:: infer:: { self ,  TyCtxtInferExt } ; 
1514use  rustc_infer:: traits; 
1615use  rustc_middle:: lint:: in_external_macro; 
1716use  rustc_middle:: ty:: subst:: GenericArgKind ; 
18- use  rustc_middle:: ty:: { self ,  Binder ,  IsSuggestable ,  ToPredicate ,  Ty } ; 
19- use  rustc_span:: symbol:: { kw ,   sym} ; 
17+ use  rustc_middle:: ty:: { self ,  Binder ,  IsSuggestable ,  Subst ,   ToPredicate ,  Ty } ; 
18+ use  rustc_span:: symbol:: sym; 
2019use  rustc_span:: Span ; 
2120use  rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ; 
2221
@@ -78,124 +77,88 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7877        expected :  Ty < ' tcx > , 
7978        found :  Ty < ' tcx > , 
8079    )  -> bool  { 
81-         let  hir = self . tcx . hir ( ) ; 
82-         let  ( def_id,  sig)  = match  * found. kind ( )  { 
83-             ty:: FnDef ( def_id,  _)  => ( def_id,  found. fn_sig ( self . tcx ) ) , 
84-             ty:: Closure ( def_id,  substs)  => ( def_id,  substs. as_closure ( ) . sig ( ) ) , 
80+         let  ( def_id,  output,  inputs)  = match  * found. kind ( )  { 
81+             ty:: FnDef ( def_id,  _)  => { 
82+                 let  fn_sig = found. fn_sig ( self . tcx ) ; 
83+                 ( def_id,  fn_sig. output ( ) ,  fn_sig. inputs ( ) . skip_binder ( ) . len ( ) ) 
84+             } 
85+             ty:: Closure ( def_id,  substs)  => { 
86+                 let  fn_sig = substs. as_closure ( ) . sig ( ) ; 
87+                 ( def_id,  fn_sig. output ( ) ,  fn_sig. inputs ( ) . skip_binder ( ) . len ( )  - 1 ) 
88+             } 
89+             ty:: Opaque ( def_id,  substs)  => { 
90+                 let  sig = self . tcx . bound_item_bounds ( def_id) . subst ( self . tcx ,  substs) . iter ( ) . find_map ( |pred| { 
91+                     if  let  ty:: PredicateKind :: Projection ( proj)  = pred. kind ( ) . skip_binder ( ) 
92+                     && Some ( proj. projection_ty . item_def_id )  == self . tcx . lang_items ( ) . fn_once_output ( ) 
93+                     // args tuple will always be substs[1] 
94+                     && let  ty:: Tuple ( args)  = proj. projection_ty . substs . type_at ( 1 ) . kind ( ) 
95+                     { 
96+                         Some ( ( 
97+                             pred. kind ( ) . rebind ( proj. term . ty ( ) . unwrap ( ) ) , 
98+                             args. len ( ) , 
99+                         ) ) 
100+                     }  else  { 
101+                         None 
102+                     } 
103+                 } ) ; 
104+                 if  let  Some ( ( output,  inputs) )  = sig { 
105+                     ( def_id,  output,  inputs) 
106+                 }  else  { 
107+                     return  false ; 
108+                 } 
109+             } 
85110            _ => return  false , 
86111        } ; 
87112
88-         let  sig = self . replace_bound_vars_with_fresh_vars ( expr. span ,  infer:: FnCall ,  sig) ; 
89-         let  sig = self . normalize_associated_types_in ( expr. span ,  sig) ; 
90-         if  self . can_coerce ( sig. output ( ) ,  expected)  { 
91-             let  ( mut  sugg_call,  applicability)  = if  sig. inputs ( ) . is_empty ( )  { 
92-                 ( String :: new ( ) ,  Applicability :: MachineApplicable ) 
93-             }  else  { 
94-                 ( "..." . to_string ( ) ,  Applicability :: HasPlaceholders ) 
113+         let  output = self . replace_bound_vars_with_fresh_vars ( expr. span ,  infer:: FnCall ,  output) ; 
114+         let  output = self . normalize_associated_types_in ( expr. span ,  output) ; 
115+         if  !output. is_ty_var ( )  && self . can_coerce ( output,  expected)  { 
116+             let  ( sugg_call,  mut  applicability)  = match  inputs { 
117+                 0  => ( "" . to_string ( ) ,  Applicability :: MachineApplicable ) , 
118+                 1 ..=4  => ( 
119+                     ( 0 ..inputs) . map ( |_| "_" ) . collect :: < Vec < _ > > ( ) . join ( ", " ) , 
120+                     Applicability :: MachineApplicable , 
121+                 ) , 
122+                 _ => ( "..." . to_string ( ) ,  Applicability :: HasPlaceholders ) , 
95123            } ; 
96-             let  mut  msg = "call this function" ; 
97-             match  hir. get_if_local ( def_id)  { 
98-                 Some ( 
99-                     Node :: Item ( hir:: Item  {  kind :  ItemKind :: Fn ( ..,  body_id) ,  .. } ) 
100-                     | Node :: ImplItem ( hir:: ImplItem  { 
101-                         kind :  hir:: ImplItemKind :: Fn ( _,  body_id) ,  ..
102-                     } ) 
103-                     | Node :: TraitItem ( hir:: TraitItem  { 
104-                         kind :  hir:: TraitItemKind :: Fn ( ..,  hir:: TraitFn :: Provided ( body_id) ) , 
105-                         ..
106-                     } ) , 
107-                 )  => { 
108-                     let  body = hir. body ( * body_id) ; 
109-                     sugg_call = body
110-                         . params 
111-                         . iter ( ) 
112-                         . map ( |param| match  & param. pat . kind  { 
113-                             hir:: PatKind :: Binding ( _,  _,  ident,  None ) 
114-                                 if  ident. name  != kw:: SelfLower  =>
115-                             { 
116-                                 ident. to_string ( ) 
117-                             } 
118-                             _ => "_" . to_string ( ) , 
119-                         } ) 
120-                         . collect :: < Vec < _ > > ( ) 
121-                         . join ( ", " ) ; 
122-                 } 
123-                 Some ( Node :: Expr ( hir:: Expr  { 
124-                     kind :  ExprKind :: Closure  {  body :  body_id,  .. } , 
125-                     span :  full_closure_span, 
126-                     ..
127-                 } ) )  => { 
128-                     if  * full_closure_span == expr. span  { 
129-                         return  false ; 
130-                     } 
131-                     msg = "call this closure" ; 
132-                     let  body = hir. body ( * body_id) ; 
133-                     sugg_call = body
134-                         . params 
135-                         . iter ( ) 
136-                         . map ( |param| match  & param. pat . kind  { 
137-                             hir:: PatKind :: Binding ( _,  _,  ident,  None ) 
138-                                 if  ident. name  != kw:: SelfLower  =>
139-                             { 
140-                                 ident. to_string ( ) 
141-                             } 
142-                             _ => "_" . to_string ( ) , 
143-                         } ) 
144-                         . collect :: < Vec < _ > > ( ) 
145-                         . join ( ", " ) ; 
146-                 } 
147-                 Some ( Node :: Ctor ( hir:: VariantData :: Tuple ( fields,  _) ) )  => { 
148-                     sugg_call = fields. iter ( ) . map ( |_| "_" ) . collect :: < Vec < _ > > ( ) . join ( ", " ) ; 
149-                     match  def_id. as_local ( ) . map ( |def_id| self . tcx . def_kind ( def_id) )  { 
150-                         Some ( DefKind :: Ctor ( hir:: def:: CtorOf :: Variant ,  _) )  => { 
151-                             msg = "instantiate this tuple variant" ; 
152-                         } 
153-                         Some ( DefKind :: Ctor ( CtorOf :: Struct ,  _) )  => { 
154-                             msg = "instantiate this tuple struct" ; 
155-                         } 
156-                         _ => { } 
157-                     } 
124+ 
125+             let  msg = match  self . tcx . def_kind ( def_id)  { 
126+                 DefKind :: Fn  => "call this function" , 
127+                 DefKind :: Closure  | DefKind :: OpaqueTy  => "call this closure" , 
128+                 DefKind :: Ctor ( CtorOf :: Struct ,  _)  => "instantiate this tuple struct" , 
129+                 DefKind :: Ctor ( CtorOf :: Variant ,  _)  => "instantiate this tuple variant" , 
130+                 _ => "call this function" , 
131+             } ; 
132+ 
133+             let  sugg = match  expr. kind  { 
134+                 hir:: ExprKind :: Call ( ..) 
135+                 | hir:: ExprKind :: Path ( ..) 
136+                 | hir:: ExprKind :: Index ( ..) 
137+                 | hir:: ExprKind :: Lit ( ..)  => { 
138+                     vec ! [ ( expr. span. shrink_to_hi( ) ,  format!( "({sugg_call})" ) ) ] 
158139                } 
159-                 Some ( Node :: ForeignItem ( hir:: ForeignItem  { 
160-                     kind :  hir:: ForeignItemKind :: Fn ( _,  idents,  _) , 
161-                     ..
162-                 } ) )  => { 
163-                     sugg_call = idents
164-                         . iter ( ) 
165-                         . map ( |ident| { 
166-                             if  ident. name  != kw:: SelfLower  { 
167-                                 ident. to_string ( ) 
168-                             }  else  { 
169-                                 "_" . to_string ( ) 
170-                             } 
171-                         } ) 
172-                         . collect :: < Vec < _ > > ( ) 
173-                         . join ( ", " ) 
140+                 hir:: ExprKind :: Closure  {  .. }  => { 
141+                     // Might be `{ expr } || { bool }` 
142+                     applicability = Applicability :: MaybeIncorrect ; 
143+                     vec ! [ 
144+                         ( expr. span. shrink_to_lo( ) ,  "(" . to_string( ) ) , 
145+                         ( expr. span. shrink_to_hi( ) ,  format!( ")({sugg_call})" ) ) , 
146+                     ] 
174147                } 
175-                 Some ( Node :: TraitItem ( hir:: TraitItem  { 
176-                     kind :  hir:: TraitItemKind :: Fn ( ..,  hir:: TraitFn :: Required ( idents) ) , 
177-                     ..
178-                 } ) )  => { 
179-                     sugg_call = idents
180-                         . iter ( ) 
181-                         . map ( |ident| { 
182-                             if  ident. name  != kw:: SelfLower  { 
183-                                 ident. to_string ( ) 
184-                             }  else  { 
185-                                 "_" . to_string ( ) 
186-                             } 
187-                         } ) 
188-                         . collect :: < Vec < _ > > ( ) 
189-                         . join ( ", " ) 
148+                 _ => { 
149+                     vec ! [ 
150+                         ( expr. span. shrink_to_lo( ) ,  "(" . to_string( ) ) , 
151+                         ( expr. span. shrink_to_hi( ) ,  format!( ")({sugg_call})" ) ) , 
152+                     ] 
190153                } 
191-                 _ => { } 
192-             } 
193-             err. span_suggestion_verbose ( 
194-                 expr. span . shrink_to_hi ( ) , 
195-                 & format ! ( "use parentheses to {}" ,  msg) , 
196-                 format ! ( "({})" ,  sugg_call) , 
154+             } ; 
155+ 
156+             err. multipart_suggestion_verbose ( 
157+                 format ! ( "use parentheses to {msg}" ) , 
158+                 sugg, 
197159                applicability, 
198160            ) ; 
161+ 
199162            return  true ; 
200163        } 
201164        false 
0 commit comments