]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
New upstream version 1.56.0~beta.4+dfsg1
[rustc.git] / compiler / rustc_infer / src / infer / error_reporting / need_type_info.rs
CommitLineData
dc9dc135 1use crate::infer::type_variable::TypeVariableOriginKind;
dfeec247 2use crate::infer::InferCtxt;
ba9703b0 3use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
dfeec247
XL
4use rustc_hir as hir;
5use rustc_hir::def::{DefKind, Namespace};
5869c6ff 6use rustc_hir::def_id::DefId;
dfeec247 7use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
74b04a01 8use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat};
ba9703b0 9use rustc_middle::hir::map::Map;
1b1a35ee 10use rustc_middle::infer::unify_key::ConstVariableOriginKind;
ba9703b0
XL
11use rustc_middle::ty::print::Print;
12use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
5869c6ff 13use rustc_middle::ty::{self, DefIdTree, InferConst, Ty, TyCtxt};
dfeec247
XL
14use rustc_span::source_map::DesugaringKind;
15use rustc_span::symbol::kw;
16use rustc_span::Span;
60c5eb7d
XL
17use std::borrow::Cow;
18
ba9703b0 19struct FindHirNodeVisitor<'a, 'tcx> {
dc9dc135 20 infcx: &'a InferCtxt<'a, 'tcx>,
ba9703b0 21 target: GenericArg<'tcx>,
f9f354fc 22 target_span: Span,
ba9703b0 23 found_node_ty: Option<Ty<'tcx>>,
dfeec247
XL
24 found_local_pattern: Option<&'tcx Pat<'tcx>>,
25 found_arg_pattern: Option<&'tcx Pat<'tcx>>,
ba9703b0 26 found_closure: Option<&'tcx Expr<'tcx>>,
dfeec247 27 found_method_call: Option<&'tcx Expr<'tcx>>,
f9f354fc 28 found_exact_method_call: Option<&'tcx Expr<'tcx>>,
5869c6ff 29 found_use_diagnostic: Option<UseDiagnostic<'tcx>>,
041b39d2
XL
30}
31
ba9703b0 32impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
f9f354fc 33 fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>, target_span: Span) -> Self {
e1599b0c
XL
34 Self {
35 infcx,
ba9703b0 36 target,
f9f354fc 37 target_span,
ba9703b0 38 found_node_ty: None,
e1599b0c
XL
39 found_local_pattern: None,
40 found_arg_pattern: None,
e1599b0c 41 found_closure: None,
60c5eb7d 42 found_method_call: None,
f9f354fc 43 found_exact_method_call: None,
5869c6ff 44 found_use_diagnostic: None,
e1599b0c
XL
45 }
46 }
47
5869c6ff
XL
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| {
94222f64 54 ty.walk(self.infcx.tcx).any(|inner| {
5869c6ff
XL
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,
ba9703b0 67 }
041b39d2 68 }
5869c6ff
XL
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))
041b39d2
XL
81 }
82}
83
ba9703b0 84impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> {
dfeec247
XL
85 type Map = Map<'tcx>;
86
ba9703b0
XL
87 fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
88 NestedVisitorMap::OnlyBodies(self.infcx.tcx.hir())
041b39d2
XL
89 }
90
dfeec247 91 fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
ba9703b0
XL
92 if let (None, Some(ty)) =
93 (self.found_local_pattern, self.node_ty_contains_target(local.hir_id))
94 {
041b39d2 95 self.found_local_pattern = Some(&*local.pat);
ba9703b0 96 self.found_node_ty = Some(ty);
041b39d2
XL
97 }
98 intravisit::walk_local(self, local);
99 }
100
dfeec247
XL
101 fn visit_body(&mut self, body: &'tcx Body<'tcx>) {
102 for param in body.params {
ba9703b0
XL
103 if let (None, Some(ty)) =
104 (self.found_arg_pattern, self.node_ty_contains_target(param.hir_id))
dfeec247 105 {
29967ef6
XL
106 self.found_arg_pattern = Some(&*param.pat);
107 self.found_node_ty = Some(ty);
041b39d2
XL
108 }
109 }
110 intravisit::walk_body(self, body);
111 }
e1599b0c 112
dfeec247 113 fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
f035d41b 114 if let ExprKind::MethodCall(_, call_span, exprs, _) = expr.kind {
f9f354fc
XL
115 if call_span == self.target_span
116 && Some(self.target)
3dfed10e
XL
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)
f9f354fc
XL
122 })
123 {
124 self.found_exact_method_call = Some(&expr);
125 return;
126 }
127 }
fc512014
XL
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.
5869c6ff 133 if let Some(ty) = self.node_ty_contains_target(expr.hir_id) {
60c5eb7d 134 match expr.kind {
ba9703b0 135 ExprKind::Closure(..) => self.found_closure = Some(&expr),
60c5eb7d 136 ExprKind::MethodCall(..) => self.found_method_call = Some(&expr),
5869c6ff
XL
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 }
60c5eb7d
XL
150 _ => {}
151 }
e1599b0c
XL
152 }
153 intravisit::walk_expr(self, expr);
154 }
155}
156
5869c6ff
XL
157/// An observation about the use site of a type to be emitted as an additional
158/// note in an inference failure error.
159enum 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
165impl 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
e1599b0c
XL
215/// Suggest giving an appropriate return type to a closure expression.
216fn closure_return_type_suggestion(
e1599b0c 217 err: &mut DiagnosticBuilder<'_>,
74b04a01 218 output: &FnRetTy<'_>,
dfeec247 219 body: &Body<'_>,
e1599b0c
XL
220 ret: &str,
221) {
222 let (arrow, post) = match output {
74b04a01 223 FnRetTy::DefaultReturn(_) => ("-> ", " "),
e1599b0c
XL
224 _ => ("", ""),
225 };
e74abb32 226 let suggestion = match body.value.kind {
dfeec247
XL
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 ],
e1599b0c
XL
232 };
233 err.multipart_suggestion(
234 "give this closure an explicit return type without `_` placeholders",
235 suggestion,
236 Applicability::HasPlaceholders,
237 );
e1599b0c
XL
238}
239
240/// Given a closure signature, return a `String` containing a list of all its argument types.
241fn closure_args(fn_sig: &ty::PolyFnSig<'_>) -> String {
dfeec247
XL
242 fn_sig
243 .inputs()
e1599b0c
XL
244 .skip_binder()
245 .iter()
246 .next()
dfeec247 247 .map(|args| args.tuple_fields().map(|arg| arg.to_string()).collect::<Vec<_>>().join(", "))
e1599b0c 248 .unwrap_or_default()
041b39d2
XL
249}
250
60c5eb7d 251pub enum TypeAnnotationNeeded {
f9f354fc
XL
252 /// ```compile_fail,E0282
253 /// let x = "hello".chars().rev().collect();
254 /// ```
60c5eb7d 255 E0282,
f9f354fc
XL
256 /// An implementation cannot be chosen unambiguously because of lack of information.
257 /// ```compile_fail,E0283
258 /// let _ = Default::default();
259 /// ```
60c5eb7d 260 E0283,
f9f354fc
XL
261 /// ```compile_fail,E0284
262 /// let mut d: u64 = 2;
263 /// d = d % 1u32.into();
264 /// ```
60c5eb7d
XL
265 E0284,
266}
267
dfeec247
XL
268impl 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 }
60c5eb7d
XL
275 }
276}
277
1b1a35ee
XL
278/// Information about a constant or a type containing inference variables.
279pub struct InferenceDiagnosticsData {
280 pub name: String,
281 pub span: Option<Span>,
5869c6ff
XL
282 pub kind: UnderspecifiedArgKind,
283 pub parent: Option<InferenceDiagnosticsParentData>,
284}
285
286/// Data on the parent definition where a generic argument was declared.
287pub struct InferenceDiagnosticsParentData {
288 pub prefix: &'static str,
289 pub name: String,
cdc7bbd5 290 pub def_id: DefId,
5869c6ff
XL
291}
292
293pub enum UnderspecifiedArgKind {
294 Type { prefix: Cow<'static, str> },
295 Const { is_parameter: bool },
296}
297
298impl 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
322impl 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,
cdc7bbd5 332 def_id: parent_def_id,
5869c6ff
XL
333 })
334 }
335}
336
337impl 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 }
1b1a35ee
XL
345}
346
dc9dc135 347impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1b1a35ee
XL
348 /// Extracts data used by diagnostic for either types or constants
349 /// which were stuck during inference.
350 pub fn extract_inference_diagnostics_data(
532ac7d7 351 &self,
1b1a35ee 352 arg: GenericArg<'tcx>,
532ac7d7 353 highlight: Option<ty::print::RegionHighlightMode>,
1b1a35ee
XL
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 {
1b1a35ee
XL
364 if name != kw::SelfUpper {
365 return InferenceDiagnosticsData {
366 name: name.to_string(),
367 span: Some(var_origin.span),
5869c6ff
XL
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 }),
1b1a35ee
XL
374 };
375 }
376 }
377 }
dfeec247 378
1b1a35ee
XL
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,
6a06907d 388 kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string(self.tcx) },
5869c6ff 389 parent: None,
60c5eb7d 390 }
041b39d2 391 }
1b1a35ee
XL
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 {
1b1a35ee
XL
399 return InferenceDiagnosticsData {
400 name: name.to_string(),
401 span: Some(origin.span),
5869c6ff
XL
402 kind: UnderspecifiedArgKind::Const { is_parameter: true },
403 parent: InferenceDiagnosticsParentData::for_def_id(self.tcx, def_id),
1b1a35ee
XL
404 };
405 }
532ac7d7 406
1b1a35ee
XL
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),
5869c6ff
XL
418 kind: UnderspecifiedArgKind::Const { is_parameter: false },
419 parent: None,
1b1a35ee
XL
420 }
421 } else {
422 bug!("unexpect const: {:?}", ct);
423 }
424 }
425 GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
532ac7d7 426 }
041b39d2
XL
427 }
428
1b1a35ee 429 pub fn emit_inference_failure_err(
48663c56
XL
430 &self,
431 body_id: Option<hir::BodyId>,
432 span: Span,
1b1a35ee 433 arg: GenericArg<'tcx>,
5869c6ff 434 impl_candidates: Vec<ty::TraitRef<'tcx>>,
60c5eb7d 435 error_code: TypeAnnotationNeeded,
dc9dc135 436 ) -> DiagnosticBuilder<'tcx> {
fc512014 437 let arg = self.resolve_vars_if_possible(arg);
1b1a35ee 438 let arg_data = self.extract_inference_diagnostics_data(arg, None);
041b39d2 439
1b1a35ee 440 let mut local_visitor = FindHirNodeVisitor::new(&self, arg, span);
dc9dc135
XL
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);
f9f354fc
XL
444 let mut inner = self.inner.borrow_mut();
445 let ty_vars = inner.type_variables();
dc9dc135 446 let getter = move |ty_vid| {
60c5eb7d 447 let var_origin = ty_vars.var_origin(ty_vid);
dfeec247 448 if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = var_origin.kind {
dc9dc135
XL
449 return Some(name.to_string());
450 }
451 None
452 };
453 printer.name_resolver = Some(Box::new(&getter));
1b1a35ee 454 let _ = if let ty::FnDef(..) = ty.kind() {
f9f354fc
XL
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 };
dc9dc135 461 s
041b39d2
XL
462 };
463
464 if let Some(body_id) = body_id {
dc9dc135 465 let expr = self.tcx.hir().expect_expr(body_id.hir_id);
041b39d2
XL
466 local_visitor.visit_expr(expr);
467 }
e1599b0c
XL
468 let err_span = if let Some(pattern) = local_visitor.found_arg_pattern {
469 pattern.span
1b1a35ee 470 } else if let Some(span) = arg_data.span {
e1599b0c
XL
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
f035d41b 478 } else if let Some(ExprKind::MethodCall(_, call_span, _, _)) =
dfeec247
XL
479 local_visitor.found_method_call.map(|e| &e.kind)
480 {
60c5eb7d
XL
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 == _`
dfeec247 489 if span.contains(*call_span) { *call_span } else { span }
e1599b0c
XL
490 } else {
491 span
492 };
493
136023e0
XL
494 let is_named_and_not_impl_trait =
495 |ty: Ty<'_>| &ty.to_string() != "_" && !ty.is_impl_trait();
e1599b0c 496
f9f354fc
XL
497 let ty_msg = match (local_visitor.found_node_ty, local_visitor.found_exact_method_call) {
498 (_, Some(_)) => String::new(),
1b1a35ee
XL
499 (Some(ty), _) if ty.is_closure() => {
500 let substs =
501 if let ty::Closure(_, substs) = *ty.kind() { substs } else { unreachable!() };
ba9703b0 502 let fn_sig = substs.as_closure().sig();
e1599b0c
XL
503 let args = closure_args(&fn_sig);
504 let ret = fn_sig.output().skip_binder().to_string();
505 format!(" for the closure `fn({}) -> {}`", args, ret)
506 }
f9f354fc 507 (Some(ty), _) if is_named_and_not_impl_trait(ty) => {
e1599b0c
XL
508 let ty = ty_to_string(ty);
509 format!(" for `{}`", ty)
510 }
511 _ => String::new(),
512 };
041b39d2 513
1b1a35ee 514 // When `arg_data.name` corresponds to a type argument, show the path of the full type we're
dc9dc135 515 // trying to infer. In the following example, `ty_msg` contains
5869c6ff 516 // " for `std::result::Result<i32, E>`":
dc9dc135
XL
517 // ```
518 // error[E0282]: type annotations needed for `std::result::Result<i32, E>`
519 // --> file.rs:L:CC
520 // |
521 // L | let b = Ok(4);
522 // | - ^^ cannot infer type for `E` in `std::result::Result<i32, E>`
523 // | |
524 // | consider giving `b` the explicit type `std::result::Result<i32, E>`, where
525 // | the type parameter `E` is specified
526 // ```
60c5eb7d
XL
527 let error_code = error_code.into();
528 let mut err = self.tcx.sess.struct_span_err_with_code(
e1599b0c 529 err_span,
60c5eb7d
XL
530 &format!("type annotations needed{}", ty_msg),
531 error_code,
e1599b0c
XL
532 );
533
5869c6ff
XL
534 let use_diag = local_visitor.found_use_diagnostic.as_ref();
535 if let Some(use_diag) = use_diag {
536 if use_diag.applies_to(err_span) {
537 use_diag.attach_note(&mut err);
538 }
539 }
540
ba9703b0 541 let suffix = match local_visitor.found_node_ty {
1b1a35ee
XL
542 Some(ty) if ty.is_closure() => {
543 let substs =
544 if let ty::Closure(_, substs) = *ty.kind() { substs } else { unreachable!() };
ba9703b0 545 let fn_sig = substs.as_closure().sig();
e1599b0c
XL
546 let ret = fn_sig.output().skip_binder().to_string();
547
ba9703b0
XL
548 let closure_decl_and_body_id =
549 local_visitor.found_closure.and_then(|closure| match &closure.kind {
550 ExprKind::Closure(_, decl, body_id, ..) => Some((decl, *body_id)),
551 _ => None,
552 });
553
554 if let Some((decl, body_id)) = closure_decl_and_body_id {
555 closure_return_type_suggestion(
ba9703b0
XL
556 &mut err,
557 &decl.output,
558 self.tcx.hir().body(body_id),
ba9703b0 559 &ret,
ba9703b0
XL
560 );
561 // We don't want to give the other suggestions when the problem is the
562 // closure return type.
5869c6ff
XL
563 err.span_label(
564 span,
565 arg_data.cannot_infer_msg(use_diag.filter(|d| d.applies_to(span))),
566 );
ba9703b0 567 return err;
e1599b0c
XL
568 }
569
570 // This shouldn't be reachable, but just in case we leave a reasonable fallback.
571 let args = closure_args(&fn_sig);
572 // This suggestion is incomplete, as the user will get further type inference
573 // errors due to the `_` placeholders and the introduction of `Box`, but it does
574 // nudge them in the right direction.
575 format!("a boxed closure type like `Box<dyn Fn({}) -> {}>`", args, ret)
576 }
1b1a35ee 577 Some(ty) if is_named_and_not_impl_trait(ty) && arg_data.name == "_" => {
dc9dc135 578 let ty = ty_to_string(ty);
e1599b0c 579 format!("the explicit type `{}`, with the type parameters specified", ty)
dc9dc135 580 }
1b1a35ee 581 Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != arg_data.name => {
dc9dc135 582 let ty = ty_to_string(ty);
e1599b0c
XL
583 format!(
584 "the explicit type `{}`, where the type parameter `{}` is specified",
1b1a35ee 585 ty, arg_data.name,
e1599b0c 586 )
dc9dc135 587 }
e1599b0c 588 _ => "a type".to_string(),
dc9dc135 589 };
dc9dc135 590
f9f354fc
XL
591 if let Some(e) = local_visitor.found_exact_method_call {
592 if let ExprKind::MethodCall(segment, ..) = &e.kind {
593 // Suggest specifying type params or point out the return type of the call:
594 //
595 // error[E0282]: type annotations needed
596 // --> $DIR/type-annotations-needed-expr.rs:2:39
597 // |
598 // LL | let _ = x.into_iter().sum() as f64;
599 // | ^^^
600 // | |
601 // | cannot infer type for `S`
602 // | help: consider specifying the type argument in
603 // | the method call: `sum::<S>`
604 // |
605 // = note: type must be known at this point
606 //
607 // or
608 //
609 // error[E0282]: type annotations needed
610 // --> $DIR/issue-65611.rs:59:20
611 // |
612 // LL | let x = buffer.last().unwrap().0.clone();
613 // | -------^^^^--
614 // | | |
615 // | | cannot infer type for `T`
616 // | this method call resolves to `std::option::Option<&T>`
617 // |
618 // = note: type must be known at this point
619 self.annotate_method_call(segment, e, &mut err);
620 }
621 } else if let Some(pattern) = local_visitor.found_arg_pattern {
041b39d2
XL
622 // We don't want to show the default label for closures.
623 //
624 // So, before clearing, the output would look something like this:
625 // ```
626 // let x = |_| { };
627 // - ^^^^ cannot infer type for `[_; 0]`
628 // |
629 // consider giving this closure parameter a type
630 // ```
631 //
632 // After clearing, it looks something like this:
633 // ```
634 // let x = |_| { };
dc9dc135
XL
635 // ^ consider giving this closure parameter the type `[_; 0]`
636 // with the type parameter `_` specified
041b39d2 637 // ```
e1599b0c 638 err.span_label(
dc9dc135
XL
639 pattern.span,
640 format!("consider giving this closure parameter {}", suffix),
e1599b0c 641 );
ff7c6d11 642 } else if let Some(pattern) = local_visitor.found_local_pattern {
e1599b0c 643 let msg = if let Some(simple_ident) = pattern.simple_ident() {
416331ca 644 match pattern.span.desugaring_kind() {
dfeec247 645 None => format!("consider giving `{}` {}", simple_ident, suffix),
f035d41b 646 Some(DesugaringKind::ForLoop(_)) => {
e1599b0c
XL
647 "the element type for this iterator is not specified".to_string()
648 }
649 _ => format!("this needs {}", suffix),
8faf50e0 650 }
041b39d2 651 } else {
e1599b0c
XL
652 format!("consider giving this pattern {}", suffix)
653 };
654 err.span_label(pattern.span, msg);
60c5eb7d 655 } else if let Some(e) = local_visitor.found_method_call {
5869c6ff
XL
656 if let ExprKind::MethodCall(segment, _, exprs, _) = &e.kind {
657 // Suggest impl candidates:
658 //
659 // error[E0283]: type annotations needed
660 // --> $DIR/E0283.rs:35:24
661 // |
662 // LL | let bar = foo_impl.into() * 1u32;
663 // | ---------^^^^--
664 // | | |
665 // | | cannot infer type for type parameter `T` declared on the trait `Into`
666 // | this method call resolves to `T`
667 // | help: specify type like: `<Impl as Into<u32>>::into(foo_impl)`
668 // |
669 // = note: cannot satisfy `Impl: Into<_>`
670 if !impl_candidates.is_empty() && e.span.contains(span) {
671 if let Some(expr) = exprs.first() {
672 if let ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind {
6a06907d 673 if let [path_segment] = path.segments {
5869c6ff
XL
674 let candidate_len = impl_candidates.len();
675 let suggestions = impl_candidates.iter().map(|candidate| {
676 format!(
677 "{}::{}({})",
678 candidate, segment.ident, path_segment.ident
679 )
680 });
681 err.span_suggestions(
682 e.span,
683 &format!(
684 "use the fully qualified path for the potential candidate{}",
685 pluralize!(candidate_len),
686 ),
687 suggestions,
688 Applicability::MaybeIncorrect,
689 );
690 }
691 }
692 };
693 }
74b04a01 694 // Suggest specifying type params or point out the return type of the call:
60c5eb7d
XL
695 //
696 // error[E0282]: type annotations needed
697 // --> $DIR/type-annotations-needed-expr.rs:2:39
698 // |
699 // LL | let _ = x.into_iter().sum() as f64;
700 // | ^^^
701 // | |
702 // | cannot infer type for `S`
703 // | help: consider specifying the type argument in
704 // | the method call: `sum::<S>`
705 // |
706 // = note: type must be known at this point
707 //
708 // or
709 //
710 // error[E0282]: type annotations needed
711 // --> $DIR/issue-65611.rs:59:20
712 // |
713 // LL | let x = buffer.last().unwrap().0.clone();
714 // | -------^^^^--
715 // | | |
716 // | | cannot infer type for `T`
717 // | this method call resolves to `std::option::Option<&T>`
718 // |
719 // = note: type must be known at this point
720 self.annotate_method_call(segment, e, &mut err);
721 }
e1599b0c
XL
722 }
723 // Instead of the following:
724 // error[E0282]: type annotations needed
725 // --> file2.rs:3:15
726 // |
727 // 3 | let _ = x.sum() as f64;
728 // | --^^^--------- cannot infer type for `S`
729 // |
730 // = note: type must be known at this point
731 // We want:
732 // error[E0282]: type annotations needed
733 // --> file2.rs:3:15
734 // |
735 // 3 | let _ = x.sum() as f64;
736 // | ^^^ cannot infer type for `S`
737 // |
738 // = note: type must be known at this point
1b1a35ee 739 let span = arg_data.span.unwrap_or(err_span);
5869c6ff
XL
740
741 // Avoid multiple labels pointing at `span`.
dfeec247
XL
742 if !err
743 .span
744 .span_labels()
745 .iter()
746 .any(|span_label| span_label.label.is_some() && span_label.span == span)
747 && local_visitor.found_arg_pattern.is_none()
748 {
fc512014
XL
749 // FIXME(const_generics): we would like to handle const arguments
750 // as part of the normal diagnostics flow below, but there appear to
751 // be subtleties in doing so, so for now we special-case const args
752 // here.
5869c6ff
XL
753 if let (UnderspecifiedArgKind::Const { .. }, Some(parent_data)) =
754 (&arg_data.kind, &arg_data.parent)
fc512014 755 {
cdc7bbd5
XL
756 // (#83606): Do not emit a suggestion if the parent has an `impl Trait`
757 // as an argument otherwise it will cause the E0282 error.
94222f64
XL
758 if !self.tcx.generics_of(parent_data.def_id).has_impl_trait()
759 || self.tcx.features().explicit_generic_args_with_impl_trait
760 {
cdc7bbd5
XL
761 err.span_suggestion_verbose(
762 span,
763 "consider specifying the const argument",
764 format!("{}::<{}>", parent_data.name, arg_data.name),
765 Applicability::MaybeIncorrect,
766 );
767 }
fc512014
XL
768 }
769
dfeec247
XL
770 err.span_label(
771 span,
5869c6ff 772 arg_data.cannot_infer_msg(use_diag.filter(|d| d.applies_to(span))),
dfeec247 773 );
041b39d2
XL
774 }
775
94b46f34 776 err
041b39d2 777 }
48663c56 778
5869c6ff
XL
779 fn trait_def_from_hir_fn(&self, hir_id: hir::HirId) -> Option<DefId> {
780 // The DefId will be the method's trait item ID unless this is an inherent impl
781 if let Some((DefKind::AssocFn, def_id)) =
782 self.in_progress_typeck_results?.borrow().type_dependent_def(hir_id)
783 {
784 return self
785 .tcx
786 .parent(def_id)
787 .filter(|&parent_def_id| self.tcx.is_trait(parent_def_id));
788 }
789
790 None
791 }
792
60c5eb7d
XL
793 /// If the `FnSig` for the method call can be found and type arguments are identified as
794 /// needed, suggest annotating the call, otherwise point out the resulting type of the call.
795 fn annotate_method_call(
796 &self,
dfeec247
XL
797 segment: &hir::PathSegment<'_>,
798 e: &Expr<'_>,
60c5eb7d
XL
799 err: &mut DiagnosticBuilder<'_>,
800 ) {
3dfed10e
XL
801 if let (Some(typeck_results), None) = (self.in_progress_typeck_results, &segment.args) {
802 let borrow = typeck_results.borrow();
ba9703b0 803 if let Some((DefKind::AssocFn, did)) = borrow.type_dependent_def(e.hir_id) {
60c5eb7d 804 let generics = self.tcx.generics_of(did);
94222f64 805 if !generics.params.is_empty() && !generics.has_impl_trait() {
ba9703b0
XL
806 err.span_suggestion_verbose(
807 segment.ident.span.shrink_to_hi(),
60c5eb7d
XL
808 &format!(
809 "consider specifying the type argument{} in the method call",
ba9703b0 810 pluralize!(generics.params.len()),
dfeec247
XL
811 ),
812 format!(
ba9703b0 813 "::<{}>",
dfeec247
XL
814 generics
815 .params
816 .iter()
817 .map(|p| p.name.to_string())
818 .collect::<Vec<String>>()
819 .join(", ")
60c5eb7d 820 ),
60c5eb7d
XL
821 Applicability::HasPlaceholders,
822 );
823 } else {
824 let sig = self.tcx.fn_sig(did);
825 let bound_output = sig.output();
826 let output = bound_output.skip_binder();
1b1a35ee
XL
827 err.span_label(e.span, &format!("this method call resolves to `{}`", output));
828 let kind = output.kind();
f9f354fc 829 if let ty::Projection(proj) = kind {
60c5eb7d 830 if let Some(span) = self.tcx.hir().span_if_local(proj.item_def_id) {
1b1a35ee 831 err.span_label(span, &format!("`{}` defined here", output));
60c5eb7d
XL
832 }
833 }
834 }
835 }
836 }
837 }
838
48663c56
XL
839 pub fn need_type_info_err_in_generator(
840 &self,
dc9dc135 841 kind: hir::GeneratorKind,
48663c56 842 span: Span,
dc9dc135
XL
843 ty: Ty<'tcx>,
844 ) -> DiagnosticBuilder<'tcx> {
fc512014 845 let ty = self.resolve_vars_if_possible(ty);
1b1a35ee 846 let data = self.extract_inference_diagnostics_data(ty.into(), None);
dfeec247 847
dc9dc135 848 let mut err = struct_span_err!(
dfeec247
XL
849 self.tcx.sess,
850 span,
851 E0698,
852 "type inside {} must be known in this context",
853 kind,
dc9dc135 854 );
5869c6ff 855 err.span_label(span, data.cannot_infer_msg(None));
48663c56
XL
856 err
857 }
041b39d2 858}