1
- use crate :: hir:: def:: Namespace ;
1
+ use crate :: hir:: def:: { DefKind , Namespace } ;
2
2
use crate :: hir:: { self , Body , FunctionRetTy , Expr , ExprKind , HirId , Local , Pat } ;
3
3
use crate :: hir:: intravisit:: { self , Visitor , NestedVisitorMap } ;
4
4
use crate :: infer:: InferCtxt ;
5
5
use crate :: infer:: type_variable:: TypeVariableOriginKind ;
6
6
use crate :: ty:: { self , Ty , Infer , TyVar } ;
7
7
use crate :: ty:: print:: Print ;
8
8
use syntax:: source_map:: DesugaringKind ;
9
+ use syntax:: symbol:: kw;
9
10
use syntax_pos:: Span ;
10
11
use errors:: { Applicability , DiagnosticBuilder } ;
12
+ use std:: borrow:: Cow ;
11
13
12
14
use rustc_error_codes:: * ;
13
15
@@ -19,6 +21,7 @@ struct FindLocalByTypeVisitor<'a, 'tcx> {
19
21
found_arg_pattern : Option < & ' tcx Pat > ,
20
22
found_ty : Option < Ty < ' tcx > > ,
21
23
found_closure : Option < & ' tcx ExprKind > ,
24
+ found_method_call : Option < & ' tcx Expr > ,
22
25
}
23
26
24
27
impl < ' a , ' tcx > FindLocalByTypeVisitor < ' a , ' tcx > {
@@ -35,6 +38,7 @@ impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
35
38
found_arg_pattern : None ,
36
39
found_ty : None ,
37
40
found_closure : None ,
41
+ found_method_call : None ,
38
42
}
39
43
}
40
44
@@ -93,11 +97,12 @@ impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> {
93
97
}
94
98
95
99
fn visit_expr ( & mut self , expr : & ' tcx Expr ) {
96
- if let ( ExprKind :: Closure ( _, _fn_decl, _id, _sp, _) , Some ( _) ) = (
97
- & expr. kind ,
98
- self . node_matches_type ( expr. hir_id ) ,
99
- ) {
100
- self . found_closure = Some ( & expr. kind ) ;
100
+ if self . node_matches_type ( expr. hir_id ) . is_some ( ) {
101
+ match expr. kind {
102
+ ExprKind :: Closure ( ..) => self . found_closure = Some ( & expr. kind ) ,
103
+ ExprKind :: MethodCall ( ..) => self . found_method_call = Some ( & expr) ,
104
+ _ => { }
105
+ }
101
106
}
102
107
intravisit:: walk_expr ( self , expr) ;
103
108
}
@@ -109,6 +114,7 @@ fn closure_return_type_suggestion(
109
114
err : & mut DiagnosticBuilder < ' _ > ,
110
115
output : & FunctionRetTy ,
111
116
body : & Body ,
117
+ descr : & str ,
112
118
name : & str ,
113
119
ret : & str ,
114
120
) {
@@ -132,7 +138,7 @@ fn closure_return_type_suggestion(
132
138
suggestion,
133
139
Applicability :: HasPlaceholders ,
134
140
) ;
135
- err. span_label ( span, InferCtxt :: missing_type_msg ( & name) ) ;
141
+ err. span_label ( span, InferCtxt :: missing_type_msg ( & name, & descr ) ) ;
136
142
}
137
143
138
144
/// Given a closure signature, return a `String` containing a list of all its argument types.
@@ -147,17 +153,42 @@ fn closure_args(fn_sig: &ty::PolyFnSig<'_>) -> String {
147
153
. unwrap_or_default ( )
148
154
}
149
155
156
+ pub enum TypeAnnotationNeeded {
157
+ E0282 ,
158
+ E0283 ,
159
+ E0284 ,
160
+ }
161
+
162
+ impl Into < errors:: DiagnosticId > for TypeAnnotationNeeded {
163
+ fn into ( self ) -> errors:: DiagnosticId {
164
+ syntax:: diagnostic_used!( E0282 ) ;
165
+ syntax:: diagnostic_used!( E0283 ) ;
166
+ syntax:: diagnostic_used!( E0284 ) ;
167
+ errors:: DiagnosticId :: Error ( match self {
168
+ Self :: E0282 => "E0282" . to_string ( ) ,
169
+ Self :: E0283 => "E0283" . to_string ( ) ,
170
+ Self :: E0284 => "E0284" . to_string ( ) ,
171
+ } )
172
+ }
173
+ }
174
+
150
175
impl < ' a , ' tcx > InferCtxt < ' a , ' tcx > {
151
176
pub fn extract_type_name (
152
177
& self ,
153
178
ty : Ty < ' tcx > ,
154
179
highlight : Option < ty:: print:: RegionHighlightMode > ,
155
- ) -> ( String , Option < Span > ) {
180
+ ) -> ( String , Option < Span > , Cow < ' static , str > ) {
156
181
if let ty:: Infer ( ty:: TyVar ( ty_vid) ) = ty. kind {
157
182
let ty_vars = self . type_variables . borrow ( ) ;
158
183
let var_origin = ty_vars. var_origin ( ty_vid) ;
159
184
if let TypeVariableOriginKind :: TypeParameterDefinition ( name) = var_origin. kind {
160
- return ( name. to_string ( ) , Some ( var_origin. span ) ) ;
185
+ if name != kw:: SelfUpper {
186
+ return (
187
+ name. to_string ( ) ,
188
+ Some ( var_origin. span ) ,
189
+ "type parameter" . into ( ) ,
190
+ ) ;
191
+ }
161
192
}
162
193
}
163
194
@@ -167,26 +198,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
167
198
printer. region_highlight_mode = highlight;
168
199
}
169
200
let _ = ty. print ( printer) ;
170
- ( s, None )
201
+ ( s, None , ty . prefix_string ( ) )
171
202
}
172
203
173
204
pub fn need_type_info_err (
174
205
& self ,
175
206
body_id : Option < hir:: BodyId > ,
176
207
span : Span ,
177
208
ty : Ty < ' tcx > ,
209
+ error_code : TypeAnnotationNeeded ,
178
210
) -> DiagnosticBuilder < ' tcx > {
179
211
let ty = self . resolve_vars_if_possible ( & ty) ;
180
- let ( name, name_sp) = self . extract_type_name ( & ty, None ) ;
212
+ let ( name, name_sp, descr ) = self . extract_type_name ( & ty, None ) ;
181
213
182
214
let mut local_visitor = FindLocalByTypeVisitor :: new ( & self , ty, & self . tcx . hir ( ) ) ;
183
215
let ty_to_string = |ty : Ty < ' tcx > | -> String {
184
216
let mut s = String :: new ( ) ;
185
217
let mut printer = ty:: print:: FmtPrinter :: new ( self . tcx , & mut s, Namespace :: TypeNS ) ;
186
218
let ty_vars = self . type_variables . borrow ( ) ;
187
219
let getter = move |ty_vid| {
188
- if let TypeVariableOriginKind :: TypeParameterDefinition ( name ) =
189
- ty_vars . var_origin ( ty_vid ) . kind {
220
+ let var_origin = ty_vars . var_origin ( ty_vid ) ;
221
+ if let TypeVariableOriginKind :: TypeParameterDefinition ( name ) = var_origin. kind {
190
222
return Some ( name. to_string ( ) ) ;
191
223
}
192
224
None
@@ -210,6 +242,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
210
242
// 3 | let _ = x.sum() as f64;
211
243
// | ^^^ cannot infer type for `S`
212
244
span
245
+ } else if let Some (
246
+ ExprKind :: MethodCall ( _, call_span, _) ,
247
+ ) = local_visitor. found_method_call . map ( |e| & e. kind ) {
248
+ // Point at the call instead of the whole expression:
249
+ // error[E0284]: type annotations needed
250
+ // --> file.rs:2:5
251
+ // |
252
+ // 2 | vec![Ok(2)].into_iter().collect()?;
253
+ // | ^^^^^^^ cannot infer type
254
+ // |
255
+ // = note: cannot resolve `<_ as std::ops::Try>::Ok == _`
256
+ if span. contains ( * call_span) {
257
+ * call_span
258
+ } else {
259
+ span
260
+ }
213
261
} else {
214
262
span
215
263
} ;
@@ -247,12 +295,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
247
295
// | consider giving `b` the explicit type `std::result::Result<i32, E>`, where
248
296
// | the type parameter `E` is specified
249
297
// ```
250
- let mut err = struct_span_err ! (
251
- self . tcx. sess,
298
+ let error_code = error_code . into ( ) ;
299
+ let mut err = self . tcx . sess . struct_span_err_with_code (
252
300
err_span,
253
- E0282 ,
254
- "type annotations needed{}" ,
255
- ty_msg,
301
+ & format ! ( "type annotations needed{}" , ty_msg) ,
302
+ error_code,
256
303
) ;
257
304
258
305
let suffix = match local_visitor. found_ty {
@@ -267,6 +314,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
267
314
& mut err,
268
315
& decl. output ,
269
316
& body,
317
+ & descr,
270
318
& name,
271
319
& ret,
272
320
) ;
@@ -334,6 +382,36 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
334
382
format ! ( "consider giving this pattern {}" , suffix)
335
383
} ;
336
384
err. span_label ( pattern. span , msg) ;
385
+ } else if let Some ( e) = local_visitor. found_method_call {
386
+ if let ExprKind :: MethodCall ( segment, ..) = & e. kind {
387
+ // Suggest specifiying type params or point out the return type of the call:
388
+ //
389
+ // error[E0282]: type annotations needed
390
+ // --> $DIR/type-annotations-needed-expr.rs:2:39
391
+ // |
392
+ // LL | let _ = x.into_iter().sum() as f64;
393
+ // | ^^^
394
+ // | |
395
+ // | cannot infer type for `S`
396
+ // | help: consider specifying the type argument in
397
+ // | the method call: `sum::<S>`
398
+ // |
399
+ // = note: type must be known at this point
400
+ //
401
+ // or
402
+ //
403
+ // error[E0282]: type annotations needed
404
+ // --> $DIR/issue-65611.rs:59:20
405
+ // |
406
+ // LL | let x = buffer.last().unwrap().0.clone();
407
+ // | -------^^^^--
408
+ // | | |
409
+ // | | cannot infer type for `T`
410
+ // | this method call resolves to `std::option::Option<&T>`
411
+ // |
412
+ // = note: type must be known at this point
413
+ self . annotate_method_call ( segment, e, & mut err) ;
414
+ }
337
415
}
338
416
// Instead of the following:
339
417
// error[E0282]: type annotations needed
@@ -351,37 +429,86 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
351
429
// | ^^^ cannot infer type for `S`
352
430
// |
353
431
// = note: type must be known at this point
354
- let span = name_sp. unwrap_or ( span ) ;
432
+ let span = name_sp. unwrap_or ( err_span ) ;
355
433
if !err. span . span_labels ( ) . iter ( ) . any ( |span_label| {
356
434
span_label. label . is_some ( ) && span_label. span == span
357
435
} ) && local_visitor. found_arg_pattern . is_none ( )
358
436
{ // Avoid multiple labels pointing at `span`.
359
- err. span_label ( span, InferCtxt :: missing_type_msg ( & name) ) ;
437
+ err. span_label ( span, InferCtxt :: missing_type_msg ( & name, & descr ) ) ;
360
438
}
361
439
362
440
err
363
441
}
364
442
443
+ /// If the `FnSig` for the method call can be found and type arguments are identified as
444
+ /// needed, suggest annotating the call, otherwise point out the resulting type of the call.
445
+ fn annotate_method_call (
446
+ & self ,
447
+ segment : & hir:: ptr:: P < hir:: PathSegment > ,
448
+ e : & Expr ,
449
+ err : & mut DiagnosticBuilder < ' _ > ,
450
+ ) {
451
+ if let ( Ok ( snippet) , Some ( tables) , None ) = (
452
+ self . tcx . sess . source_map ( ) . span_to_snippet ( segment. ident . span ) ,
453
+ self . in_progress_tables ,
454
+ & segment. args ,
455
+ ) {
456
+ let borrow = tables. borrow ( ) ;
457
+ if let Some ( ( DefKind :: Method , did) ) = borrow. type_dependent_def ( e. hir_id ) {
458
+ let generics = self . tcx . generics_of ( did) ;
459
+ if !generics. params . is_empty ( ) {
460
+ err. span_suggestion (
461
+ segment. ident . span ,
462
+ & format ! (
463
+ "consider specifying the type argument{} in the method call" ,
464
+ if generics. params. len( ) > 1 {
465
+ "s"
466
+ } else {
467
+ ""
468
+ } ,
469
+ ) ,
470
+ format ! ( "{}::<{}>" , snippet, generics. params. iter( )
471
+ . map( |p| p. name. to_string( ) )
472
+ . collect:: <Vec <String >>( )
473
+ . join( ", " ) ) ,
474
+ Applicability :: HasPlaceholders ,
475
+ ) ;
476
+ } else {
477
+ let sig = self . tcx . fn_sig ( did) ;
478
+ let bound_output = sig. output ( ) ;
479
+ let output = bound_output. skip_binder ( ) ;
480
+ err. span_label ( e. span , & format ! ( "this method call resolves to `{:?}`" , output) ) ;
481
+ let kind = & output. kind ;
482
+ if let ty:: Projection ( proj) | ty:: UnnormalizedProjection ( proj) = kind {
483
+ if let Some ( span) = self . tcx . hir ( ) . span_if_local ( proj. item_def_id ) {
484
+ err. span_label ( span, & format ! ( "`{:?}` defined here" , output) ) ;
485
+ }
486
+ }
487
+ }
488
+ }
489
+ }
490
+ }
491
+
365
492
pub fn need_type_info_err_in_generator (
366
493
& self ,
367
494
kind : hir:: GeneratorKind ,
368
495
span : Span ,
369
496
ty : Ty < ' tcx > ,
370
497
) -> DiagnosticBuilder < ' tcx > {
371
498
let ty = self . resolve_vars_if_possible ( & ty) ;
372
- let name = self . extract_type_name ( & ty, None ) . 0 ;
499
+ let ( name, _ , descr ) = self . extract_type_name ( & ty, None ) ;
373
500
let mut err = struct_span_err ! (
374
501
self . tcx. sess, span, E0698 , "type inside {} must be known in this context" , kind,
375
502
) ;
376
- err. span_label ( span, InferCtxt :: missing_type_msg ( & name) ) ;
503
+ err. span_label ( span, InferCtxt :: missing_type_msg ( & name, & descr ) ) ;
377
504
err
378
505
}
379
506
380
- fn missing_type_msg ( type_name : & str ) -> String {
507
+ fn missing_type_msg ( type_name : & str , descr : & str ) -> Cow < ' static , str > {
381
508
if type_name == "_" {
382
- "cannot infer type" . to_owned ( )
509
+ "cannot infer type" . into ( )
383
510
} else {
384
- format ! ( "cannot infer type for `{}`" , type_name)
511
+ format ! ( "cannot infer type for {} `{}`" , descr , type_name) . into ( )
385
512
}
386
513
}
387
514
}
0 commit comments