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