1- use crate :: hir:: def:: Namespace ;
1+ use crate :: hir:: def:: { DefKind , Namespace } ;
22use crate :: hir:: { self , Body , FunctionRetTy , Expr , ExprKind , HirId , Local , Pat } ;
33use crate :: hir:: intravisit:: { self , Visitor , NestedVisitorMap } ;
44use crate :: infer:: InferCtxt ;
55use crate :: infer:: type_variable:: TypeVariableOriginKind ;
66use crate :: ty:: { self , Ty , Infer , TyVar } ;
77use crate :: ty:: print:: Print ;
88use syntax:: source_map:: DesugaringKind ;
9+ use syntax:: symbol:: kw;
910use syntax_pos:: Span ;
1011use errors:: { Applicability , DiagnosticBuilder } ;
12+ use std:: borrow:: Cow ;
1113
1214use rustc_error_codes:: * ;
1315
@@ -19,6 +21,7 @@ struct FindLocalByTypeVisitor<'a, 'tcx> {
1921 found_arg_pattern : Option < & ' tcx Pat > ,
2022 found_ty : Option < Ty < ' tcx > > ,
2123 found_closure : Option < & ' tcx ExprKind > ,
24+ found_method_call : Option < & ' tcx Expr > ,
2225}
2326
2427impl < ' a , ' tcx > FindLocalByTypeVisitor < ' a , ' tcx > {
@@ -35,6 +38,7 @@ impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
3538 found_arg_pattern : None ,
3639 found_ty : None ,
3740 found_closure : None ,
41+ found_method_call : None ,
3842 }
3943 }
4044
@@ -93,11 +97,12 @@ impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> {
9397 }
9498
9599 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+ }
101106 }
102107 intravisit:: walk_expr ( self , expr) ;
103108 }
@@ -109,6 +114,7 @@ fn closure_return_type_suggestion(
109114 err : & mut DiagnosticBuilder < ' _ > ,
110115 output : & FunctionRetTy ,
111116 body : & Body ,
117+ descr : & str ,
112118 name : & str ,
113119 ret : & str ,
114120) {
@@ -132,7 +138,7 @@ fn closure_return_type_suggestion(
132138 suggestion,
133139 Applicability :: HasPlaceholders ,
134140 ) ;
135- err. span_label ( span, InferCtxt :: missing_type_msg ( & name) ) ;
141+ err. span_label ( span, InferCtxt :: missing_type_msg ( & name, & descr ) ) ;
136142}
137143
138144/// 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 {
147153 . unwrap_or_default ( )
148154}
149155
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+
150175impl < ' a , ' tcx > InferCtxt < ' a , ' tcx > {
151176 pub fn extract_type_name (
152177 & self ,
153178 ty : Ty < ' tcx > ,
154179 highlight : Option < ty:: print:: RegionHighlightMode > ,
155- ) -> ( String , Option < Span > ) {
180+ ) -> ( String , Option < Span > , Cow < ' static , str > ) {
156181 if let ty:: Infer ( ty:: TyVar ( ty_vid) ) = ty. kind {
157182 let ty_vars = self . type_variables . borrow ( ) ;
158183 let var_origin = ty_vars. var_origin ( ty_vid) ;
159184 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+ }
161192 }
162193 }
163194
@@ -167,26 +198,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
167198 printer. region_highlight_mode = highlight;
168199 }
169200 let _ = ty. print ( printer) ;
170- ( s, None )
201+ ( s, None , ty . prefix_string ( ) )
171202 }
172203
173204 pub fn need_type_info_err (
174205 & self ,
175206 body_id : Option < hir:: BodyId > ,
176207 span : Span ,
177208 ty : Ty < ' tcx > ,
209+ error_code : TypeAnnotationNeeded ,
178210 ) -> DiagnosticBuilder < ' tcx > {
179211 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 ) ;
181213
182214 let mut local_visitor = FindLocalByTypeVisitor :: new ( & self , ty, & self . tcx . hir ( ) ) ;
183215 let ty_to_string = |ty : Ty < ' tcx > | -> String {
184216 let mut s = String :: new ( ) ;
185217 let mut printer = ty:: print:: FmtPrinter :: new ( self . tcx , & mut s, Namespace :: TypeNS ) ;
186218 let ty_vars = self . type_variables . borrow ( ) ;
187219 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 {
190222 return Some ( name. to_string ( ) ) ;
191223 }
192224 None
@@ -210,6 +242,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
210242 // 3 | let _ = x.sum() as f64;
211243 // | ^^^ cannot infer type for `S`
212244 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+ }
213261 } else {
214262 span
215263 } ;
@@ -247,12 +295,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
247295 // | consider giving `b` the explicit type `std::result::Result<i32, E>`, where
248296 // | the type parameter `E` is specified
249297 // ```
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 (
252300 err_span,
253- E0282 ,
254- "type annotations needed{}" ,
255- ty_msg,
301+ & format ! ( "type annotations needed{}" , ty_msg) ,
302+ error_code,
256303 ) ;
257304
258305 let suffix = match local_visitor. found_ty {
@@ -267,6 +314,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
267314 & mut err,
268315 & decl. output ,
269316 & body,
317+ & descr,
270318 & name,
271319 & ret,
272320 ) ;
@@ -334,6 +382,36 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
334382 format ! ( "consider giving this pattern {}" , suffix)
335383 } ;
336384 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+ }
337415 }
338416 // Instead of the following:
339417 // error[E0282]: type annotations needed
@@ -351,37 +429,86 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
351429 // | ^^^ cannot infer type for `S`
352430 // |
353431 // = 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 ) ;
355433 if !err. span . span_labels ( ) . iter ( ) . any ( |span_label| {
356434 span_label. label . is_some ( ) && span_label. span == span
357435 } ) && local_visitor. found_arg_pattern . is_none ( )
358436 { // 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 ) ) ;
360438 }
361439
362440 err
363441 }
364442
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+
365492 pub fn need_type_info_err_in_generator (
366493 & self ,
367494 kind : hir:: GeneratorKind ,
368495 span : Span ,
369496 ty : Ty < ' tcx > ,
370497 ) -> DiagnosticBuilder < ' tcx > {
371498 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 ) ;
373500 let mut err = struct_span_err ! (
374501 self . tcx. sess, span, E0698 , "type inside {} must be known in this context" , kind,
375502 ) ;
376- err. span_label ( span, InferCtxt :: missing_type_msg ( & name) ) ;
503+ err. span_label ( span, InferCtxt :: missing_type_msg ( & name, & descr ) ) ;
377504 err
378505 }
379506
380- fn missing_type_msg ( type_name : & str ) -> String {
507+ fn missing_type_msg ( type_name : & str , descr : & str ) -> Cow < ' static , str > {
381508 if type_name == "_" {
382- "cannot infer type" . to_owned ( )
509+ "cannot infer type" . into ( )
383510 } else {
384- format ! ( "cannot infer type for `{}`" , type_name)
511+ format ! ( "cannot infer type for {} `{}`" , descr , type_name) . into ( )
385512 }
386513 }
387514}
0 commit comments