@@ -76,10 +76,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7676 found : Ty < ' tcx > ,
7777 can_satisfy : impl FnOnce ( Ty < ' tcx > ) -> bool ,
7878 ) -> bool {
79- enum DefIdOrName {
80- DefId ( DefId ) ,
81- Name ( & ' static str ) ,
79+ let Some ( ( def_id_or_name, output, num_inputs) ) = self . extract_callable_info ( expr, found)
80+ else { return false ; } ;
81+ if can_satisfy ( output) {
82+ let ( sugg_call, mut applicability) = match num_inputs {
83+ 0 => ( "" . to_string ( ) , Applicability :: MachineApplicable ) ,
84+ 1 ..=4 => (
85+ ( 0 ..num_inputs) . map ( |_| "_" ) . collect :: < Vec < _ > > ( ) . join ( ", " ) ,
86+ Applicability :: MachineApplicable ,
87+ ) ,
88+ _ => ( "..." . to_string ( ) , Applicability :: HasPlaceholders ) ,
89+ } ;
90+
91+ let msg = match def_id_or_name {
92+ DefIdOrName :: DefId ( def_id) => match self . tcx . def_kind ( def_id) {
93+ DefKind :: Ctor ( CtorOf :: Struct , _) => "instantiate this tuple struct" . to_string ( ) ,
94+ DefKind :: Ctor ( CtorOf :: Variant , _) => {
95+ "instantiate this tuple variant" . to_string ( )
96+ }
97+ kind => format ! ( "call this {}" , kind. descr( def_id) ) ,
98+ } ,
99+ DefIdOrName :: Name ( name) => format ! ( "call this {name}" ) ,
100+ } ;
101+
102+ let sugg = match expr. kind {
103+ hir:: ExprKind :: Call ( ..)
104+ | hir:: ExprKind :: Path ( ..)
105+ | hir:: ExprKind :: Index ( ..)
106+ | hir:: ExprKind :: Lit ( ..) => {
107+ vec ! [ ( expr. span. shrink_to_hi( ) , format!( "({sugg_call})" ) ) ]
108+ }
109+ hir:: ExprKind :: Closure { .. } => {
110+ // Might be `{ expr } || { bool }`
111+ applicability = Applicability :: MaybeIncorrect ;
112+ vec ! [
113+ ( expr. span. shrink_to_lo( ) , "(" . to_string( ) ) ,
114+ ( expr. span. shrink_to_hi( ) , format!( ")({sugg_call})" ) ) ,
115+ ]
116+ }
117+ _ => {
118+ vec ! [
119+ ( expr. span. shrink_to_lo( ) , "(" . to_string( ) ) ,
120+ ( expr. span. shrink_to_hi( ) , format!( ")({sugg_call})" ) ) ,
121+ ]
122+ }
123+ } ;
124+
125+ err. multipart_suggestion_verbose (
126+ format ! ( "use parentheses to {msg}" ) ,
127+ sugg,
128+ applicability,
129+ ) ;
130+
131+ return true ;
82132 }
133+ false
134+ }
135+
136+ fn extract_callable_info (
137+ & self ,
138+ expr : & Expr < ' _ > ,
139+ found : Ty < ' tcx > ,
140+ ) -> Option < ( DefIdOrName , Ty < ' tcx > , usize ) > {
83141 // Autoderef is useful here because sometimes we box callables, etc.
84142 let Some ( ( def_id_or_name, output, inputs) ) = self . autoderef ( expr. span , found) . silence_errors ( ) . find_map ( |( found, _) | {
85143 match * found. kind ( ) {
@@ -148,67 +206,83 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
148206 }
149207 _ => None ,
150208 }
151- } ) else { return false ; } ;
209+ } ) else { return None ; } ;
152210
153211 let output = self . replace_bound_vars_with_fresh_vars ( expr. span , infer:: FnCall , output) ;
212+
154213 // We don't want to register any extra obligations, which should be
155214 // implied by wf, but also because that would possibly result in
156215 // erroneous errors later on.
157216 let infer:: InferOk { value : output, obligations : _ } =
158217 self . normalize_associated_types_in_as_infer_ok ( expr. span , output) ;
159- if !output. is_ty_var ( ) && can_satisfy ( output) {
160- let ( sugg_call, mut applicability) = match inputs {
161- 0 => ( "" . to_string ( ) , Applicability :: MachineApplicable ) ,
162- 1 ..=4 => (
163- ( 0 ..inputs) . map ( |_| "_" ) . collect :: < Vec < _ > > ( ) . join ( ", " ) ,
164- Applicability :: MachineApplicable ,
165- ) ,
166- _ => ( "..." . to_string ( ) , Applicability :: HasPlaceholders ) ,
167- } ;
168218
169- let msg = match def_id_or_name {
170- DefIdOrName :: DefId ( def_id) => match self . tcx . def_kind ( def_id) {
171- DefKind :: Ctor ( CtorOf :: Struct , _) => "instantiate this tuple struct" . to_string ( ) ,
172- DefKind :: Ctor ( CtorOf :: Variant , _) => {
173- "instantiate this tuple variant" . to_string ( )
174- }
175- kind => format ! ( "call this {}" , kind. descr( def_id) ) ,
176- } ,
177- DefIdOrName :: Name ( name) => format ! ( "call this {name}" ) ,
178- } ;
219+ if output. is_ty_var ( ) { None } else { Some ( ( def_id_or_name, output, inputs) ) }
220+ }
179221
180- let sugg = match expr. kind {
181- hir:: ExprKind :: Call ( ..)
182- | hir:: ExprKind :: Path ( ..)
183- | hir:: ExprKind :: Index ( ..)
184- | hir:: ExprKind :: Lit ( ..) => {
185- vec ! [ ( expr. span. shrink_to_hi( ) , format!( "({sugg_call})" ) ) ]
186- }
187- hir:: ExprKind :: Closure { .. } => {
188- // Might be `{ expr } || { bool }`
189- applicability = Applicability :: MaybeIncorrect ;
190- vec ! [
191- ( expr. span. shrink_to_lo( ) , "(" . to_string( ) ) ,
192- ( expr. span. shrink_to_hi( ) , format!( ")({sugg_call})" ) ) ,
193- ]
194- }
195- _ => {
196- vec ! [
197- ( expr. span. shrink_to_lo( ) , "(" . to_string( ) ) ,
198- ( expr. span. shrink_to_hi( ) , format!( ")({sugg_call})" ) ) ,
199- ]
222+ pub fn suggest_two_fn_call (
223+ & self ,
224+ err : & mut Diagnostic ,
225+ lhs_expr : & ' tcx hir:: Expr < ' tcx > ,
226+ lhs_ty : Ty < ' tcx > ,
227+ rhs_expr : & ' tcx hir:: Expr < ' tcx > ,
228+ rhs_ty : Ty < ' tcx > ,
229+ can_satisfy : impl FnOnce ( Ty < ' tcx > , Ty < ' tcx > ) -> bool ,
230+ ) -> bool {
231+ let Some ( ( _, lhs_output_ty, num_lhs_inputs) ) = self . extract_callable_info ( lhs_expr, lhs_ty)
232+ else { return false ; } ;
233+ let Some ( ( _, rhs_output_ty, num_rhs_inputs) ) = self . extract_callable_info ( rhs_expr, rhs_ty)
234+ else { return false ; } ;
235+
236+ if can_satisfy ( lhs_output_ty, rhs_output_ty) {
237+ let mut sugg = vec ! [ ] ;
238+ let mut applicability = Applicability :: MachineApplicable ;
239+
240+ for ( expr, num_inputs) in [ ( lhs_expr, num_lhs_inputs) , ( rhs_expr, num_rhs_inputs) ] {
241+ let ( sugg_call, this_applicability) = match num_inputs {
242+ 0 => ( "" . to_string ( ) , Applicability :: MachineApplicable ) ,
243+ 1 ..=4 => (
244+ ( 0 ..num_inputs) . map ( |_| "_" ) . collect :: < Vec < _ > > ( ) . join ( ", " ) ,
245+ Applicability :: MachineApplicable ,
246+ ) ,
247+ _ => ( "..." . to_string ( ) , Applicability :: HasPlaceholders ) ,
248+ } ;
249+
250+ applicability = applicability. max ( this_applicability) ;
251+
252+ match expr. kind {
253+ hir:: ExprKind :: Call ( ..)
254+ | hir:: ExprKind :: Path ( ..)
255+ | hir:: ExprKind :: Index ( ..)
256+ | hir:: ExprKind :: Lit ( ..) => {
257+ sugg. extend ( [ ( expr. span . shrink_to_hi ( ) , format ! ( "({sugg_call})" ) ) ] ) ;
258+ }
259+ hir:: ExprKind :: Closure { .. } => {
260+ // Might be `{ expr } || { bool }`
261+ applicability = Applicability :: MaybeIncorrect ;
262+ sugg. extend ( [
263+ ( expr. span . shrink_to_lo ( ) , "(" . to_string ( ) ) ,
264+ ( expr. span . shrink_to_hi ( ) , format ! ( ")({sugg_call})" ) ) ,
265+ ] ) ;
266+ }
267+ _ => {
268+ sugg. extend ( [
269+ ( expr. span . shrink_to_lo ( ) , "(" . to_string ( ) ) ,
270+ ( expr. span . shrink_to_hi ( ) , format ! ( ")({sugg_call})" ) ) ,
271+ ] ) ;
272+ }
200273 }
201- } ;
274+ }
202275
203276 err. multipart_suggestion_verbose (
204- format ! ( "use parentheses to {msg} " ) ,
277+ format ! ( "use parentheses to call these " ) ,
205278 sugg,
206279 applicability,
207280 ) ;
208281
209- return true ;
282+ true
283+ } else {
284+ false
210285 }
211- false
212286 }
213287
214288 pub fn suggest_deref_ref_or_into (
@@ -959,3 +1033,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
9591033 }
9601034 }
9611035}
1036+
1037+ enum DefIdOrName {
1038+ DefId ( DefId ) ,
1039+ Name ( & ' static str ) ,
1040+ }
0 commit comments