@@ -76,10 +76,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
76
76
found : Ty < ' tcx > ,
77
77
can_satisfy : impl FnOnce ( Ty < ' tcx > ) -> bool ,
78
78
) -> 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 ;
82
132
}
133
+ false
134
+ }
135
+
136
+ fn extract_callable_info (
137
+ & self ,
138
+ expr : & Expr < ' _ > ,
139
+ found : Ty < ' tcx > ,
140
+ ) -> Option < ( DefIdOrName , Ty < ' tcx > , usize ) > {
83
141
// Autoderef is useful here because sometimes we box callables, etc.
84
142
let Some ( ( def_id_or_name, output, inputs) ) = self . autoderef ( expr. span , found) . silence_errors ( ) . find_map ( |( found, _) | {
85
143
match * found. kind ( ) {
@@ -148,67 +206,83 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
148
206
}
149
207
_ => None ,
150
208
}
151
- } ) else { return false ; } ;
209
+ } ) else { return None ; } ;
152
210
153
211
let output = self . replace_bound_vars_with_fresh_vars ( expr. span , infer:: FnCall , output) ;
212
+
154
213
// We don't want to register any extra obligations, which should be
155
214
// implied by wf, but also because that would possibly result in
156
215
// erroneous errors later on.
157
216
let infer:: InferOk { value : output, obligations : _ } =
158
217
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
- } ;
168
218
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
+ }
179
221
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
+ }
200
273
}
201
- } ;
274
+ }
202
275
203
276
err. multipart_suggestion_verbose (
204
- format ! ( "use parentheses to {msg} " ) ,
277
+ format ! ( "use parentheses to call these " ) ,
205
278
sugg,
206
279
applicability,
207
280
) ;
208
281
209
- return true ;
282
+ true
283
+ } else {
284
+ false
210
285
}
211
- false
212
286
}
213
287
214
288
pub fn suggest_deref_ref_or_into (
@@ -959,3 +1033,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
959
1033
}
960
1034
}
961
1035
}
1036
+
1037
+ enum DefIdOrName {
1038
+ DefId ( DefId ) ,
1039
+ Name ( & ' static str ) ,
1040
+ }
0 commit comments