]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
Rollup merge of #85852 - m-ou-se:machineapplicable-docs, r=nikomatsakis
[rust.git] / compiler / rustc_infer / src / infer / error_reporting / need_type_info.rs
1 use crate::infer::type_variable::TypeVariableOriginKind;
2 use crate::infer::InferCtxt;
3 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
4 use rustc_hir as hir;
5 use rustc_hir::def::{DefKind, Namespace};
6 use rustc_hir::def_id::DefId;
7 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
8 use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat};
9 use rustc_middle::hir::map::Map;
10 use rustc_middle::infer::unify_key::ConstVariableOriginKind;
11 use rustc_middle::ty::print::Print;
12 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
13 use rustc_middle::ty::{self, DefIdTree, InferConst, Ty, TyCtxt};
14 use rustc_span::source_map::DesugaringKind;
15 use rustc_span::symbol::kw;
16 use rustc_span::Span;
17 use std::borrow::Cow;
18
19 struct FindHirNodeVisitor<'a, 'tcx> {
20     infcx: &'a InferCtxt<'a, 'tcx>,
21     target: GenericArg<'tcx>,
22     target_span: Span,
23     found_node_ty: Option<Ty<'tcx>>,
24     found_local_pattern: Option<&'tcx Pat<'tcx>>,
25     found_arg_pattern: Option<&'tcx Pat<'tcx>>,
26     found_closure: Option<&'tcx Expr<'tcx>>,
27     found_method_call: Option<&'tcx Expr<'tcx>>,
28     found_exact_method_call: Option<&'tcx Expr<'tcx>>,
29     found_use_diagnostic: Option<UseDiagnostic<'tcx>>,
30 }
31
32 impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
33     fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>, target_span: Span) -> Self {
34         Self {
35             infcx,
36             target,
37             target_span,
38             found_node_ty: None,
39             found_local_pattern: None,
40             found_arg_pattern: None,
41             found_closure: None,
42             found_method_call: None,
43             found_exact_method_call: None,
44             found_use_diagnostic: None,
45         }
46     }
47
48     fn node_type_opt(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
49         self.infcx.in_progress_typeck_results?.borrow().node_type_opt(hir_id)
50     }
51
52     fn node_ty_contains_target(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
53         self.node_type_opt(hir_id).map(|ty| self.infcx.resolve_vars_if_possible(ty)).filter(|ty| {
54             ty.walk().any(|inner| {
55                 inner == self.target
56                     || match (inner.unpack(), self.target.unpack()) {
57                         (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {
58                             use ty::{Infer, TyVar};
59                             match (inner_ty.kind(), target_ty.kind()) {
60                                 (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => self
61                                     .infcx
62                                     .inner
63                                     .borrow_mut()
64                                     .type_variables()
65                                     .sub_unified(a_vid, b_vid),
66                                 _ => false,
67                             }
68                         }
69                         _ => false,
70                     }
71             })
72         })
73     }
74
75     /// Determine whether the expression, assumed to be the callee within a `Call`,
76     /// corresponds to the `From::from` emitted in desugaring of the `?` operator.
77     fn is_try_conversion(&self, callee: &Expr<'tcx>) -> bool {
78         self.infcx
79             .trait_def_from_hir_fn(callee.hir_id)
80             .map_or(false, |def_id| self.infcx.is_try_conversion(callee.span, def_id))
81     }
82 }
83
84 impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> {
85     type Map = Map<'tcx>;
86
87     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
88         NestedVisitorMap::OnlyBodies(self.infcx.tcx.hir())
89     }
90
91     fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
92         if let (None, Some(ty)) =
93             (self.found_local_pattern, self.node_ty_contains_target(local.hir_id))
94         {
95             self.found_local_pattern = Some(&*local.pat);
96             self.found_node_ty = Some(ty);
97         }
98         intravisit::walk_local(self, local);
99     }
100
101     fn visit_body(&mut self, body: &'tcx Body<'tcx>) {
102         for param in body.params {
103             if let (None, Some(ty)) =
104                 (self.found_arg_pattern, self.node_ty_contains_target(param.hir_id))
105             {
106                 self.found_arg_pattern = Some(&*param.pat);
107                 self.found_node_ty = Some(ty);
108             }
109         }
110         intravisit::walk_body(self, body);
111     }
112
113     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
114         if let ExprKind::MethodCall(_, call_span, exprs, _) = expr.kind {
115             if call_span == self.target_span
116                 && Some(self.target)
117                     == self.infcx.in_progress_typeck_results.and_then(|typeck_results| {
118                         typeck_results
119                             .borrow()
120                             .node_type_opt(exprs.first().unwrap().hir_id)
121                             .map(Into::into)
122                     })
123             {
124                 self.found_exact_method_call = Some(&expr);
125                 return;
126             }
127         }
128
129         // FIXME(const_generics): Currently, any uninferred `const` generics arguments
130         // are handled specially, but instead they should be handled in `annotate_method_call`,
131         // which currently doesn't work because this evaluates to `false` for const arguments.
132         // See https://github.com/rust-lang/rust/pull/77758 for more details.
133         if let Some(ty) = self.node_ty_contains_target(expr.hir_id) {
134             match expr.kind {
135                 ExprKind::Closure(..) => self.found_closure = Some(&expr),
136                 ExprKind::MethodCall(..) => self.found_method_call = Some(&expr),
137
138                 // If the given expression falls within the target span and is a
139                 // `From::from(e)` call emitted during desugaring of the `?` operator,
140                 // extract the types inferred before and after the call
141                 ExprKind::Call(callee, [arg])
142                     if self.target_span.contains(expr.span)
143                         && self.found_use_diagnostic.is_none()
144                         && self.is_try_conversion(callee) =>
145                 {
146                     self.found_use_diagnostic = self.node_type_opt(arg.hir_id).map(|pre_ty| {
147                         UseDiagnostic::TryConversion { pre_ty, post_ty: ty, span: callee.span }
148                     });
149                 }
150                 _ => {}
151             }
152         }
153         intravisit::walk_expr(self, expr);
154     }
155 }
156
157 /// An observation about the use site of a type to be emitted as an additional
158 /// note in an inference failure error.
159 enum UseDiagnostic<'tcx> {
160     /// Records the types inferred before and after `From::from` is called on the
161     /// error value within the desugaring of the `?` operator.
162     TryConversion { pre_ty: Ty<'tcx>, post_ty: Ty<'tcx>, span: Span },
163 }
164
165 impl UseDiagnostic<'_> {
166     /// Return a descriptor of the value at the use site
167     fn descr(&self) -> &'static str {
168         match self {
169             Self::TryConversion { .. } => "error for `?` operator",
170         }
171     }
172
173     /// Return a descriptor of the type at the use site
174     fn type_descr(&self) -> &'static str {
175         match self {
176             Self::TryConversion { .. } => "error type for `?` operator",
177         }
178     }
179
180     fn applies_to(&self, span: Span) -> bool {
181         match *self {
182             // In some cases the span for an inference failure due to try
183             // conversion contains the antecedent expression as well as the `?`
184             Self::TryConversion { span: s, .. } => span.contains(s) && span.hi() == s.hi(),
185         }
186     }
187
188     fn attach_note(&self, err: &mut DiagnosticBuilder<'_>) {
189         match *self {
190             Self::TryConversion { pre_ty, post_ty, .. } => {
191                 let intro = "`?` implicitly converts the error value";
192
193                 let msg = match (pre_ty.is_ty_infer(), post_ty.is_ty_infer()) {
194                     (true, true) => format!("{} using the `From` trait", intro),
195                     (false, true) => {
196                         format!("{} into a type implementing `From<{}>`", intro, pre_ty)
197                     }
198                     (true, false) => {
199                         format!("{} into `{}` using the `From` trait", intro, post_ty)
200                     }
201                     (false, false) => {
202                         format!(
203                             "{} into `{}` using its implementation of `From<{}>`",
204                             intro, post_ty, pre_ty
205                         )
206                     }
207                 };
208
209                 err.note(&msg);
210             }
211         }
212     }
213 }
214
215 /// Suggest giving an appropriate return type to a closure expression.
216 fn closure_return_type_suggestion(
217     err: &mut DiagnosticBuilder<'_>,
218     output: &FnRetTy<'_>,
219     body: &Body<'_>,
220     ret: &str,
221 ) {
222     let (arrow, post) = match output {
223         FnRetTy::DefaultReturn(_) => ("-> ", " "),
224         _ => ("", ""),
225     };
226     let suggestion = match body.value.kind {
227         ExprKind::Block(..) => vec![(output.span(), format!("{}{}{}", arrow, ret, post))],
228         _ => vec![
229             (output.span(), format!("{}{}{}{{ ", arrow, ret, post)),
230             (body.value.span.shrink_to_hi(), " }".to_string()),
231         ],
232     };
233     err.multipart_suggestion(
234         "give this closure an explicit return type without `_` placeholders",
235         suggestion,
236         Applicability::HasPlaceholders,
237     );
238 }
239
240 /// Given a closure signature, return a `String` containing a list of all its argument types.
241 fn closure_args(fn_sig: &ty::PolyFnSig<'_>) -> String {
242     fn_sig
243         .inputs()
244         .skip_binder()
245         .iter()
246         .next()
247         .map(|args| args.tuple_fields().map(|arg| arg.to_string()).collect::<Vec<_>>().join(", "))
248         .unwrap_or_default()
249 }
250
251 pub enum TypeAnnotationNeeded {
252     /// ```compile_fail,E0282
253     /// let x = "hello".chars().rev().collect();
254     /// ```
255     E0282,
256     /// An implementation cannot be chosen unambiguously because of lack of information.
257     /// ```compile_fail,E0283
258     /// let _ = Default::default();
259     /// ```
260     E0283,
261     /// ```compile_fail,E0284
262     /// let mut d: u64 = 2;
263     /// d = d % 1u32.into();
264     /// ```
265     E0284,
266 }
267
268 impl Into<rustc_errors::DiagnosticId> for TypeAnnotationNeeded {
269     fn into(self) -> rustc_errors::DiagnosticId {
270         match self {
271             Self::E0282 => rustc_errors::error_code!(E0282),
272             Self::E0283 => rustc_errors::error_code!(E0283),
273             Self::E0284 => rustc_errors::error_code!(E0284),
274         }
275     }
276 }
277
278 /// Information about a constant or a type containing inference variables.
279 pub struct InferenceDiagnosticsData {
280     pub name: String,
281     pub span: Option<Span>,
282     pub kind: UnderspecifiedArgKind,
283     pub parent: Option<InferenceDiagnosticsParentData>,
284 }
285
286 /// Data on the parent definition where a generic argument was declared.
287 pub struct InferenceDiagnosticsParentData {
288     pub prefix: &'static str,
289     pub name: String,
290     pub def_id: DefId,
291 }
292
293 pub enum UnderspecifiedArgKind {
294     Type { prefix: Cow<'static, str> },
295     Const { is_parameter: bool },
296 }
297
298 impl InferenceDiagnosticsData {
299     /// Generate a label for a generic argument which can't be inferred. When not
300     /// much is known about the argument, `use_diag` may be used to describe the
301     /// labeled value.
302     fn cannot_infer_msg(&self, use_diag: Option<&UseDiagnostic<'_>>) -> String {
303         if self.name == "_" && matches!(self.kind, UnderspecifiedArgKind::Type { .. }) {
304             if let Some(use_diag) = use_diag {
305                 return format!("cannot infer type of {}", use_diag.descr());
306             }
307
308             return "cannot infer type".to_string();
309         }
310
311         let suffix = match (&self.parent, use_diag) {
312             (Some(parent), _) => format!(" declared on the {} `{}`", parent.prefix, parent.name),
313             (None, Some(use_diag)) => format!(" in {}", use_diag.type_descr()),
314             (None, None) => String::new(),
315         };
316
317         // For example: "cannot infer type for type parameter `T`"
318         format!("cannot infer {} `{}`{}", self.kind.prefix_string(), self.name, suffix)
319     }
320 }
321
322 impl InferenceDiagnosticsParentData {
323     fn for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<InferenceDiagnosticsParentData> {
324         let parent_def_id = tcx.parent(def_id)?;
325
326         let parent_name =
327             tcx.def_key(parent_def_id).disambiguated_data.data.get_opt_name()?.to_string();
328
329         Some(InferenceDiagnosticsParentData {
330             prefix: tcx.def_kind(parent_def_id).descr(parent_def_id),
331             name: parent_name,
332             def_id: parent_def_id,
333         })
334     }
335 }
336
337 impl UnderspecifiedArgKind {
338     fn prefix_string(&self) -> Cow<'static, str> {
339         match self {
340             Self::Type { prefix } => format!("type for {}", prefix).into(),
341             Self::Const { is_parameter: true } => "the value of const parameter".into(),
342             Self::Const { is_parameter: false } => "the value of the constant".into(),
343         }
344     }
345 }
346
347 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
348     /// Extracts data used by diagnostic for either types or constants
349     /// which were stuck during inference.
350     pub fn extract_inference_diagnostics_data(
351         &self,
352         arg: GenericArg<'tcx>,
353         highlight: Option<ty::print::RegionHighlightMode>,
354     ) -> InferenceDiagnosticsData {
355         match arg.unpack() {
356             GenericArgKind::Type(ty) => {
357                 if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() {
358                     let mut inner = self.inner.borrow_mut();
359                     let ty_vars = &inner.type_variables();
360                     let var_origin = ty_vars.var_origin(ty_vid);
361                     if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) =
362                         var_origin.kind
363                     {
364                         if name != kw::SelfUpper {
365                             return InferenceDiagnosticsData {
366                                 name: name.to_string(),
367                                 span: Some(var_origin.span),
368                                 kind: UnderspecifiedArgKind::Type {
369                                     prefix: "type parameter".into(),
370                                 },
371                                 parent: def_id.and_then(|def_id| {
372                                     InferenceDiagnosticsParentData::for_def_id(self.tcx, def_id)
373                                 }),
374                             };
375                         }
376                     }
377                 }
378
379                 let mut s = String::new();
380                 let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
381                 if let Some(highlight) = highlight {
382                     printer.region_highlight_mode = highlight;
383                 }
384                 let _ = ty.print(printer);
385                 InferenceDiagnosticsData {
386                     name: s,
387                     span: None,
388                     kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string(self.tcx) },
389                     parent: None,
390                 }
391             }
392             GenericArgKind::Const(ct) => {
393                 if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val {
394                     let origin =
395                         self.inner.borrow_mut().const_unification_table().probe_value(vid).origin;
396                     if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
397                         origin.kind
398                     {
399                         return InferenceDiagnosticsData {
400                             name: name.to_string(),
401                             span: Some(origin.span),
402                             kind: UnderspecifiedArgKind::Const { is_parameter: true },
403                             parent: InferenceDiagnosticsParentData::for_def_id(self.tcx, def_id),
404                         };
405                     }
406
407                     debug_assert!(!origin.span.is_dummy());
408                     let mut s = String::new();
409                     let mut printer =
410                         ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS);
411                     if let Some(highlight) = highlight {
412                         printer.region_highlight_mode = highlight;
413                     }
414                     let _ = ct.print(printer);
415                     InferenceDiagnosticsData {
416                         name: s,
417                         span: Some(origin.span),
418                         kind: UnderspecifiedArgKind::Const { is_parameter: false },
419                         parent: None,
420                     }
421                 } else {
422                     bug!("unexpect const: {:?}", ct);
423                 }
424             }
425             GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
426         }
427     }
428
429     pub fn emit_inference_failure_err(
430         &self,
431         body_id: Option<hir::BodyId>,
432         span: Span,
433         arg: GenericArg<'tcx>,
434         impl_candidates: Vec<ty::TraitRef<'tcx>>,
435         error_code: TypeAnnotationNeeded,
436     ) -> DiagnosticBuilder<'tcx> {
437         let arg = self.resolve_vars_if_possible(arg);
438         let arg_data = self.extract_inference_diagnostics_data(arg, None);
439
440         let mut local_visitor = FindHirNodeVisitor::new(&self, arg, span);
441         let ty_to_string = |ty: Ty<'tcx>| -> String {
442             let mut s = String::new();
443             let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
444             let mut inner = self.inner.borrow_mut();
445             let ty_vars = inner.type_variables();
446             let getter = move |ty_vid| {
447                 let var_origin = ty_vars.var_origin(ty_vid);
448                 if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = var_origin.kind {
449                     return Some(name.to_string());
450                 }
451                 None
452             };
453             printer.name_resolver = Some(Box::new(&getter));
454             let _ = if let ty::FnDef(..) = ty.kind() {
455                 // We don't want the regular output for `fn`s because it includes its path in
456                 // invalid pseudo-syntax, we want the `fn`-pointer output instead.
457                 ty.fn_sig(self.tcx).print(printer)
458             } else {
459                 ty.print(printer)
460             };
461             s
462         };
463
464         if let Some(body_id) = body_id {
465             let expr = self.tcx.hir().expect_expr(body_id.hir_id);
466             local_visitor.visit_expr(expr);
467         }
468         let err_span = if let Some(pattern) = local_visitor.found_arg_pattern {
469             pattern.span
470         } else if let Some(span) = arg_data.span {
471             // `span` here lets us point at `sum` instead of the entire right hand side expr:
472             // error[E0282]: type annotations needed
473             //  --> file2.rs:3:15
474             //   |
475             // 3 |     let _ = x.sum() as f64;
476             //   |               ^^^ cannot infer type for `S`
477             span
478         } else if let Some(ExprKind::MethodCall(_, call_span, _, _)) =
479             local_visitor.found_method_call.map(|e| &e.kind)
480         {
481             // Point at the call instead of the whole expression:
482             // error[E0284]: type annotations needed
483             //  --> file.rs:2:5
484             //   |
485             // 2 |     vec![Ok(2)].into_iter().collect()?;
486             //   |                             ^^^^^^^ cannot infer type
487             //   |
488             //   = note: cannot resolve `<_ as std::ops::Try>::Ok == _`
489             if span.contains(*call_span) { *call_span } else { span }
490         } else {
491             span
492         };
493
494         let is_named_and_not_impl_trait = |ty: Ty<'_>| {
495             &ty.to_string() != "_" &&
496                 // FIXME: Remove this check after `impl_trait_in_bindings` is stabilized. #63527
497                 (!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings)
498         };
499
500         let ty_msg = match (local_visitor.found_node_ty, local_visitor.found_exact_method_call) {
501             (_, Some(_)) => String::new(),
502             (Some(ty), _) if ty.is_closure() => {
503                 let substs =
504                     if let ty::Closure(_, substs) = *ty.kind() { substs } else { unreachable!() };
505                 let fn_sig = substs.as_closure().sig();
506                 let args = closure_args(&fn_sig);
507                 let ret = fn_sig.output().skip_binder().to_string();
508                 format!(" for the closure `fn({}) -> {}`", args, ret)
509             }
510             (Some(ty), _) if is_named_and_not_impl_trait(ty) => {
511                 let ty = ty_to_string(ty);
512                 format!(" for `{}`", ty)
513             }
514             _ => String::new(),
515         };
516
517         // When `arg_data.name` corresponds to a type argument, show the path of the full type we're
518         // trying to infer. In the following example, `ty_msg` contains
519         // " for `std::result::Result<i32, E>`":
520         // ```
521         // error[E0282]: type annotations needed for `std::result::Result<i32, E>`
522         //  --> file.rs:L:CC
523         //   |
524         // L |     let b = Ok(4);
525         //   |         -   ^^ cannot infer type for `E` in `std::result::Result<i32, E>`
526         //   |         |
527         //   |         consider giving `b` the explicit type `std::result::Result<i32, E>`, where
528         //   |         the type parameter `E` is specified
529         // ```
530         let error_code = error_code.into();
531         let mut err = self.tcx.sess.struct_span_err_with_code(
532             err_span,
533             &format!("type annotations needed{}", ty_msg),
534             error_code,
535         );
536
537         let use_diag = local_visitor.found_use_diagnostic.as_ref();
538         if let Some(use_diag) = use_diag {
539             if use_diag.applies_to(err_span) {
540                 use_diag.attach_note(&mut err);
541             }
542         }
543
544         let suffix = match local_visitor.found_node_ty {
545             Some(ty) if ty.is_closure() => {
546                 let substs =
547                     if let ty::Closure(_, substs) = *ty.kind() { substs } else { unreachable!() };
548                 let fn_sig = substs.as_closure().sig();
549                 let ret = fn_sig.output().skip_binder().to_string();
550
551                 let closure_decl_and_body_id =
552                     local_visitor.found_closure.and_then(|closure| match &closure.kind {
553                         ExprKind::Closure(_, decl, body_id, ..) => Some((decl, *body_id)),
554                         _ => None,
555                     });
556
557                 if let Some((decl, body_id)) = closure_decl_and_body_id {
558                     closure_return_type_suggestion(
559                         &mut err,
560                         &decl.output,
561                         self.tcx.hir().body(body_id),
562                         &ret,
563                     );
564                     // We don't want to give the other suggestions when the problem is the
565                     // closure return type.
566                     err.span_label(
567                         span,
568                         arg_data.cannot_infer_msg(use_diag.filter(|d| d.applies_to(span))),
569                     );
570                     return err;
571                 }
572
573                 // This shouldn't be reachable, but just in case we leave a reasonable fallback.
574                 let args = closure_args(&fn_sig);
575                 // This suggestion is incomplete, as the user will get further type inference
576                 // errors due to the `_` placeholders and the introduction of `Box`, but it does
577                 // nudge them in the right direction.
578                 format!("a boxed closure type like `Box<dyn Fn({}) -> {}>`", args, ret)
579             }
580             Some(ty) if is_named_and_not_impl_trait(ty) && arg_data.name == "_" => {
581                 let ty = ty_to_string(ty);
582                 format!("the explicit type `{}`, with the type parameters specified", ty)
583             }
584             Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != arg_data.name => {
585                 let ty = ty_to_string(ty);
586                 format!(
587                     "the explicit type `{}`, where the type parameter `{}` is specified",
588                     ty, arg_data.name,
589                 )
590             }
591             _ => "a type".to_string(),
592         };
593
594         if let Some(e) = local_visitor.found_exact_method_call {
595             if let ExprKind::MethodCall(segment, ..) = &e.kind {
596                 // Suggest specifying type params or point out the return type of the call:
597                 //
598                 // error[E0282]: type annotations needed
599                 //   --> $DIR/type-annotations-needed-expr.rs:2:39
600                 //    |
601                 // LL |     let _ = x.into_iter().sum() as f64;
602                 //    |                           ^^^
603                 //    |                           |
604                 //    |                           cannot infer type for `S`
605                 //    |                           help: consider specifying the type argument in
606                 //    |                           the method call: `sum::<S>`
607                 //    |
608                 //    = note: type must be known at this point
609                 //
610                 // or
611                 //
612                 // error[E0282]: type annotations needed
613                 //   --> $DIR/issue-65611.rs:59:20
614                 //    |
615                 // LL |     let x = buffer.last().unwrap().0.clone();
616                 //    |             -------^^^^--
617                 //    |             |      |
618                 //    |             |      cannot infer type for `T`
619                 //    |             this method call resolves to `std::option::Option<&T>`
620                 //    |
621                 //    = note: type must be known at this point
622                 self.annotate_method_call(segment, e, &mut err);
623             }
624         } else if let Some(pattern) = local_visitor.found_arg_pattern {
625             // We don't want to show the default label for closures.
626             //
627             // So, before clearing, the output would look something like this:
628             // ```
629             // let x = |_| {  };
630             //          -  ^^^^ cannot infer type for `[_; 0]`
631             //          |
632             //          consider giving this closure parameter a type
633             // ```
634             //
635             // After clearing, it looks something like this:
636             // ```
637             // let x = |_| {  };
638             //          ^ consider giving this closure parameter the type `[_; 0]`
639             //            with the type parameter `_` specified
640             // ```
641             err.span_label(
642                 pattern.span,
643                 format!("consider giving this closure parameter {}", suffix),
644             );
645         } else if let Some(pattern) = local_visitor.found_local_pattern {
646             let msg = if let Some(simple_ident) = pattern.simple_ident() {
647                 match pattern.span.desugaring_kind() {
648                     None => format!("consider giving `{}` {}", simple_ident, suffix),
649                     Some(DesugaringKind::ForLoop(_)) => {
650                         "the element type for this iterator is not specified".to_string()
651                     }
652                     _ => format!("this needs {}", suffix),
653                 }
654             } else {
655                 format!("consider giving this pattern {}", suffix)
656             };
657             err.span_label(pattern.span, msg);
658         } else if let Some(e) = local_visitor.found_method_call {
659             if let ExprKind::MethodCall(segment, _, exprs, _) = &e.kind {
660                 // Suggest impl candidates:
661                 //
662                 // error[E0283]: type annotations needed
663                 //   --> $DIR/E0283.rs:35:24
664                 //    |
665                 // LL |     let bar = foo_impl.into() * 1u32;
666                 //    |               ---------^^^^--
667                 //    |               |        |
668                 //    |               |        cannot infer type for type parameter `T` declared on the trait `Into`
669                 //    |               this method call resolves to `T`
670                 //    |               help: specify type like: `<Impl as Into<u32>>::into(foo_impl)`
671                 //    |
672                 //    = note: cannot satisfy `Impl: Into<_>`
673                 if !impl_candidates.is_empty() && e.span.contains(span) {
674                     if let Some(expr) = exprs.first() {
675                         if let ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind {
676                             if let [path_segment] = path.segments {
677                                 let candidate_len = impl_candidates.len();
678                                 let suggestions = impl_candidates.iter().map(|candidate| {
679                                     format!(
680                                         "{}::{}({})",
681                                         candidate, segment.ident, path_segment.ident
682                                     )
683                                 });
684                                 err.span_suggestions(
685                                     e.span,
686                                     &format!(
687                                         "use the fully qualified path for the potential candidate{}",
688                                         pluralize!(candidate_len),
689                                     ),
690                                     suggestions,
691                                     Applicability::MaybeIncorrect,
692                                 );
693                             }
694                         }
695                     };
696                 }
697                 // Suggest specifying type params or point out the return type of the call:
698                 //
699                 // error[E0282]: type annotations needed
700                 //   --> $DIR/type-annotations-needed-expr.rs:2:39
701                 //    |
702                 // LL |     let _ = x.into_iter().sum() as f64;
703                 //    |                           ^^^
704                 //    |                           |
705                 //    |                           cannot infer type for `S`
706                 //    |                           help: consider specifying the type argument in
707                 //    |                           the method call: `sum::<S>`
708                 //    |
709                 //    = note: type must be known at this point
710                 //
711                 // or
712                 //
713                 // error[E0282]: type annotations needed
714                 //   --> $DIR/issue-65611.rs:59:20
715                 //    |
716                 // LL |     let x = buffer.last().unwrap().0.clone();
717                 //    |             -------^^^^--
718                 //    |             |      |
719                 //    |             |      cannot infer type for `T`
720                 //    |             this method call resolves to `std::option::Option<&T>`
721                 //    |
722                 //    = note: type must be known at this point
723                 self.annotate_method_call(segment, e, &mut err);
724             }
725         }
726         // Instead of the following:
727         // error[E0282]: type annotations needed
728         //  --> file2.rs:3:15
729         //   |
730         // 3 |     let _ = x.sum() as f64;
731         //   |             --^^^--------- cannot infer type for `S`
732         //   |
733         //   = note: type must be known at this point
734         // We want:
735         // error[E0282]: type annotations needed
736         //  --> file2.rs:3:15
737         //   |
738         // 3 |     let _ = x.sum() as f64;
739         //   |               ^^^ cannot infer type for `S`
740         //   |
741         //   = note: type must be known at this point
742         let span = arg_data.span.unwrap_or(err_span);
743
744         // Avoid multiple labels pointing at `span`.
745         if !err
746             .span
747             .span_labels()
748             .iter()
749             .any(|span_label| span_label.label.is_some() && span_label.span == span)
750             && local_visitor.found_arg_pattern.is_none()
751         {
752             // FIXME(const_generics): we would like to handle const arguments
753             // as part of the normal diagnostics flow below, but there appear to
754             // be subtleties in doing so, so for now we special-case const args
755             // here.
756             if let (UnderspecifiedArgKind::Const { .. }, Some(parent_data)) =
757                 (&arg_data.kind, &arg_data.parent)
758             {
759                 let has_impl_trait =
760                     self.tcx.generics_of(parent_data.def_id).params.iter().any(|param| {
761                         matches!(
762                             param.kind,
763                             ty::GenericParamDefKind::Type {
764                                 synthetic: Some(
765                                     hir::SyntheticTyParamKind::ImplTrait
766                                         | hir::SyntheticTyParamKind::FromAttr,
767                                 ),
768                                 ..
769                             }
770                         )
771                     });
772
773                 // (#83606): Do not emit a suggestion if the parent has an `impl Trait`
774                 // as an argument otherwise it will cause the E0282 error.
775                 if !has_impl_trait {
776                     err.span_suggestion_verbose(
777                         span,
778                         "consider specifying the const argument",
779                         format!("{}::<{}>", parent_data.name, arg_data.name),
780                         Applicability::MaybeIncorrect,
781                     );
782                 }
783             }
784
785             err.span_label(
786                 span,
787                 arg_data.cannot_infer_msg(use_diag.filter(|d| d.applies_to(span))),
788             );
789         }
790
791         err
792     }
793
794     fn trait_def_from_hir_fn(&self, hir_id: hir::HirId) -> Option<DefId> {
795         // The DefId will be the method's trait item ID unless this is an inherent impl
796         if let Some((DefKind::AssocFn, def_id)) =
797             self.in_progress_typeck_results?.borrow().type_dependent_def(hir_id)
798         {
799             return self
800                 .tcx
801                 .parent(def_id)
802                 .filter(|&parent_def_id| self.tcx.is_trait(parent_def_id));
803         }
804
805         None
806     }
807
808     /// If the `FnSig` for the method call can be found and type arguments are identified as
809     /// needed, suggest annotating the call, otherwise point out the resulting type of the call.
810     fn annotate_method_call(
811         &self,
812         segment: &hir::PathSegment<'_>,
813         e: &Expr<'_>,
814         err: &mut DiagnosticBuilder<'_>,
815     ) {
816         if let (Some(typeck_results), None) = (self.in_progress_typeck_results, &segment.args) {
817             let borrow = typeck_results.borrow();
818             if let Some((DefKind::AssocFn, did)) = borrow.type_dependent_def(e.hir_id) {
819                 let generics = self.tcx.generics_of(did);
820                 if !generics.params.is_empty() {
821                     err.span_suggestion_verbose(
822                         segment.ident.span.shrink_to_hi(),
823                         &format!(
824                             "consider specifying the type argument{} in the method call",
825                             pluralize!(generics.params.len()),
826                         ),
827                         format!(
828                             "::<{}>",
829                             generics
830                                 .params
831                                 .iter()
832                                 .map(|p| p.name.to_string())
833                                 .collect::<Vec<String>>()
834                                 .join(", ")
835                         ),
836                         Applicability::HasPlaceholders,
837                     );
838                 } else {
839                     let sig = self.tcx.fn_sig(did);
840                     let bound_output = sig.output();
841                     let output = bound_output.skip_binder();
842                     err.span_label(e.span, &format!("this method call resolves to `{}`", output));
843                     let kind = output.kind();
844                     if let ty::Projection(proj) = kind {
845                         if let Some(span) = self.tcx.hir().span_if_local(proj.item_def_id) {
846                             err.span_label(span, &format!("`{}` defined here", output));
847                         }
848                     }
849                 }
850             }
851         }
852     }
853
854     pub fn need_type_info_err_in_generator(
855         &self,
856         kind: hir::GeneratorKind,
857         span: Span,
858         ty: Ty<'tcx>,
859     ) -> DiagnosticBuilder<'tcx> {
860         let ty = self.resolve_vars_if_possible(ty);
861         let data = self.extract_inference_diagnostics_data(ty.into(), None);
862
863         let mut err = struct_span_err!(
864             self.tcx.sess,
865             span,
866             E0698,
867             "type inside {} must be known in this context",
868             kind,
869         );
870         err.span_label(span, data.cannot_infer_msg(None));
871         err
872     }
873 }