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