1 use crate::infer::type_variable::TypeVariableOriginKind;
2 use crate::infer::InferCtxt;
3 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
5 use rustc_hir::def::{DefKind, Namespace};
6 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
7 use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat};
8 use rustc_middle::hir::map::Map;
9 use rustc_middle::infer::unify_key::ConstVariableOriginKind;
10 use rustc_middle::ty::print::Print;
11 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
12 use rustc_middle::ty::{self, DefIdTree, InferConst, Ty};
13 use rustc_span::source_map::DesugaringKind;
14 use rustc_span::symbol::kw;
18 struct FindHirNodeVisitor<'a, 'tcx> {
19 infcx: &'a InferCtxt<'a, 'tcx>,
20 target: GenericArg<'tcx>,
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>>,
30 impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
31 fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>, target_span: Span) -> Self {
37 found_local_pattern: None,
38 found_arg_pattern: None,
40 found_method_call: None,
41 found_exact_method_call: None,
45 fn node_ty_contains_target(&mut self, hir_id: HirId) -> Option<Ty<'tcx>> {
48 .in_progress_typeck_results
49 .and_then(|typeck_results| typeck_results.borrow().node_type_opt(hir_id));
52 let ty = self.infcx.resolve_vars_if_possible(&ty);
53 if ty.walk().any(|inner| {
55 || match (inner.unpack(), self.target.unpack()) {
56 (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {
57 match (inner_ty.kind(), target_ty.kind()) {
59 &ty::Infer(ty::TyVar(a_vid)),
60 &ty::Infer(ty::TyVar(b_vid)),
66 .sub_unified(a_vid, b_vid),
83 impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> {
86 fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
87 NestedVisitorMap::OnlyBodies(self.infcx.tcx.hir())
90 fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
91 if let (None, Some(ty)) =
92 (self.found_local_pattern, self.node_ty_contains_target(local.hir_id))
94 // FIXME: There's a trade-off here - we can either check that our target span
95 // is contained in `local.span` or not. If we choose to check containment
96 // we can avoid some spurious suggestions (see #72690), but we lose
97 // the ability to report on things like:
103 // because the target span will be in the macro expansion of `vec![]`.
104 // At present we choose not to check containment.
105 self.found_local_pattern = Some(&*local.pat);
106 self.found_node_ty = Some(ty);
108 intravisit::walk_local(self, local);
111 fn visit_body(&mut self, body: &'tcx Body<'tcx>) {
112 for param in body.params {
113 if let (None, Some(ty)) =
114 (self.found_arg_pattern, self.node_ty_contains_target(param.hir_id))
116 if self.target_span.contains(param.pat.span) {
117 self.found_arg_pattern = Some(&*param.pat);
118 self.found_node_ty = Some(ty);
122 intravisit::walk_body(self, body);
125 fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
126 if let ExprKind::MethodCall(_, call_span, exprs, _) = expr.kind {
127 if call_span == self.target_span
129 == self.infcx.in_progress_typeck_results.and_then(|typeck_results| {
132 .node_type_opt(exprs.first().unwrap().hir_id)
136 self.found_exact_method_call = Some(&expr);
140 if self.node_ty_contains_target(expr.hir_id).is_some() {
142 ExprKind::Closure(..) => self.found_closure = Some(&expr),
143 ExprKind::MethodCall(..) => self.found_method_call = Some(&expr),
147 intravisit::walk_expr(self, expr);
151 /// Suggest giving an appropriate return type to a closure expression.
152 fn closure_return_type_suggestion(
154 err: &mut DiagnosticBuilder<'_>,
155 output: &FnRetTy<'_>,
160 parent_name: Option<String>,
161 parent_descr: Option<&str>,
163 let (arrow, post) = match output {
164 FnRetTy::DefaultReturn(_) => ("-> ", " "),
167 let suggestion = match body.value.kind {
168 ExprKind::Block(..) => vec![(output.span(), format!("{}{}{}", arrow, ret, post))],
170 (output.span(), format!("{}{}{}{{ ", arrow, ret, post)),
171 (body.value.span.shrink_to_hi(), " }".to_string()),
174 err.multipart_suggestion(
175 "give this closure an explicit return type without `_` placeholders",
177 Applicability::HasPlaceholders,
181 InferCtxt::cannot_infer_msg("type", &name, &descr, parent_name, parent_descr),
185 /// Given a closure signature, return a `String` containing a list of all its argument types.
186 fn closure_args(fn_sig: &ty::PolyFnSig<'_>) -> String {
192 .map(|args| args.tuple_fields().map(|arg| arg.to_string()).collect::<Vec<_>>().join(", "))
196 pub enum TypeAnnotationNeeded {
197 /// ```compile_fail,E0282
198 /// let x = "hello".chars().rev().collect();
201 /// An implementation cannot be chosen unambiguously because of lack of information.
202 /// ```compile_fail,E0283
203 /// let _ = Default::default();
206 /// ```compile_fail,E0284
207 /// let mut d: u64 = 2;
208 /// d = d % 1u32.into();
213 impl Into<rustc_errors::DiagnosticId> for TypeAnnotationNeeded {
214 fn into(self) -> rustc_errors::DiagnosticId {
216 Self::E0282 => rustc_errors::error_code!(E0282),
217 Self::E0283 => rustc_errors::error_code!(E0283),
218 Self::E0284 => rustc_errors::error_code!(E0284),
223 /// Information about a constant or a type containing inference variables.
224 pub struct InferenceDiagnosticsData {
226 pub span: Option<Span>,
227 pub description: Cow<'static, str>,
228 pub parent_name: Option<String>,
229 pub parent_description: Option<&'static str>,
232 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
233 /// Extracts data used by diagnostic for either types or constants
234 /// which were stuck during inference.
235 pub fn extract_inference_diagnostics_data(
237 arg: GenericArg<'tcx>,
238 highlight: Option<ty::print::RegionHighlightMode>,
239 ) -> InferenceDiagnosticsData {
241 GenericArgKind::Type(ty) => {
242 if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() {
243 let mut inner = self.inner.borrow_mut();
244 let ty_vars = &inner.type_variables();
245 let var_origin = ty_vars.var_origin(ty_vid);
246 if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) =
249 let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id));
250 let (parent_name, parent_description) =
251 if let Some(parent_def_id) = parent_def_id {
252 let parent_name = self
254 .def_key(parent_def_id)
258 .map(|parent_symbol| parent_symbol.to_string());
262 Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)),
268 if name != kw::SelfUpper {
269 return InferenceDiagnosticsData {
270 name: name.to_string(),
271 span: Some(var_origin.span),
272 description: "type parameter".into(),
280 let mut s = String::new();
281 let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
282 if let Some(highlight) = highlight {
283 printer.region_highlight_mode = highlight;
285 let _ = ty.print(printer);
286 InferenceDiagnosticsData {
289 description: ty.prefix_string(),
291 parent_description: None,
294 GenericArgKind::Const(ct) => {
295 if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val {
297 self.inner.borrow_mut().const_unification_table().probe_value(vid).origin;
298 if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
301 let parent_def_id = self.tcx.parent(def_id);
302 let (parent_name, parent_description) =
303 if let Some(parent_def_id) = parent_def_id {
304 let parent_name = self
306 .def_key(parent_def_id)
310 .map(|parent_symbol| parent_symbol.to_string());
314 Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)),
320 return InferenceDiagnosticsData {
321 name: name.to_string(),
322 span: Some(origin.span),
323 description: "const parameter".into(),
329 debug_assert!(!origin.span.is_dummy());
330 let mut s = String::new();
332 ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS);
333 if let Some(highlight) = highlight {
334 printer.region_highlight_mode = highlight;
336 let _ = ct.print(printer);
337 InferenceDiagnosticsData {
339 span: Some(origin.span),
340 description: "the constant".into(),
342 parent_description: None,
345 bug!("unexpect const: {:?}", ct);
348 GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
352 pub fn emit_inference_failure_err(
354 body_id: Option<hir::BodyId>,
356 arg: GenericArg<'tcx>,
357 error_code: TypeAnnotationNeeded,
358 ) -> DiagnosticBuilder<'tcx> {
359 let arg = self.resolve_vars_if_possible(&arg);
360 let arg_data = self.extract_inference_diagnostics_data(arg, None);
361 let kind_str = match arg.unpack() {
362 GenericArgKind::Type(_) => "type",
363 GenericArgKind::Const(_) => "the value",
364 GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
367 let mut local_visitor = FindHirNodeVisitor::new(&self, arg, span);
368 let ty_to_string = |ty: Ty<'tcx>| -> String {
369 let mut s = String::new();
370 let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
371 let mut inner = self.inner.borrow_mut();
372 let ty_vars = inner.type_variables();
373 let getter = move |ty_vid| {
374 let var_origin = ty_vars.var_origin(ty_vid);
375 if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = var_origin.kind {
376 return Some(name.to_string());
380 printer.name_resolver = Some(Box::new(&getter));
381 let _ = if let ty::FnDef(..) = ty.kind() {
382 // We don't want the regular output for `fn`s because it includes its path in
383 // invalid pseudo-syntax, we want the `fn`-pointer output instead.
384 ty.fn_sig(self.tcx).print(printer)
391 if let Some(body_id) = body_id {
392 let expr = self.tcx.hir().expect_expr(body_id.hir_id);
393 local_visitor.visit_expr(expr);
395 let err_span = if let Some(pattern) = local_visitor.found_arg_pattern {
397 } else if let Some(span) = arg_data.span {
398 // `span` here lets us point at `sum` instead of the entire right hand side expr:
399 // error[E0282]: type annotations needed
402 // 3 | let _ = x.sum() as f64;
403 // | ^^^ cannot infer type for `S`
405 } else if let Some(ExprKind::MethodCall(_, call_span, _, _)) =
406 local_visitor.found_method_call.map(|e| &e.kind)
408 // Point at the call instead of the whole expression:
409 // error[E0284]: type annotations needed
412 // 2 | vec![Ok(2)].into_iter().collect()?;
413 // | ^^^^^^^ cannot infer type
415 // = note: cannot resolve `<_ as std::ops::Try>::Ok == _`
416 if span.contains(*call_span) { *call_span } else { span }
421 let is_named_and_not_impl_trait = |ty: Ty<'_>| {
422 &ty.to_string() != "_" &&
423 // FIXME: Remove this check after `impl_trait_in_bindings` is stabilized. #63527
424 (!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings)
427 let ty_msg = match (local_visitor.found_node_ty, local_visitor.found_exact_method_call) {
428 (_, Some(_)) => String::new(),
429 (Some(ty), _) if ty.is_closure() => {
431 if let ty::Closure(_, substs) = *ty.kind() { substs } else { unreachable!() };
432 let fn_sig = substs.as_closure().sig();
433 let args = closure_args(&fn_sig);
434 let ret = fn_sig.output().skip_binder().to_string();
435 format!(" for the closure `fn({}) -> {}`", args, ret)
437 (Some(ty), _) if is_named_and_not_impl_trait(ty) => {
438 let ty = ty_to_string(ty);
439 format!(" for `{}`", ty)
444 // When `arg_data.name` corresponds to a type argument, show the path of the full type we're
445 // trying to infer. In the following example, `ty_msg` contains
446 // " in `std::result::Result<i32, E>`":
448 // error[E0282]: type annotations needed for `std::result::Result<i32, E>`
451 // L | let b = Ok(4);
452 // | - ^^ cannot infer type for `E` in `std::result::Result<i32, E>`
454 // | consider giving `b` the explicit type `std::result::Result<i32, E>`, where
455 // | the type parameter `E` is specified
457 let error_code = error_code.into();
458 let mut err = self.tcx.sess.struct_span_err_with_code(
460 &format!("type annotations needed{}", ty_msg),
464 let suffix = match local_visitor.found_node_ty {
465 Some(ty) if ty.is_closure() => {
467 if let ty::Closure(_, substs) = *ty.kind() { substs } else { unreachable!() };
468 let fn_sig = substs.as_closure().sig();
469 let ret = fn_sig.output().skip_binder().to_string();
471 let closure_decl_and_body_id =
472 local_visitor.found_closure.and_then(|closure| match &closure.kind {
473 ExprKind::Closure(_, decl, body_id, ..) => Some((decl, *body_id)),
477 if let Some((decl, body_id)) = closure_decl_and_body_id {
478 closure_return_type_suggestion(
482 self.tcx.hir().body(body_id),
483 &arg_data.description,
486 arg_data.parent_name,
487 arg_data.parent_description,
489 // We don't want to give the other suggestions when the problem is the
490 // closure return type.
494 // This shouldn't be reachable, but just in case we leave a reasonable fallback.
495 let args = closure_args(&fn_sig);
496 // This suggestion is incomplete, as the user will get further type inference
497 // errors due to the `_` placeholders and the introduction of `Box`, but it does
498 // nudge them in the right direction.
499 format!("a boxed closure type like `Box<dyn Fn({}) -> {}>`", args, ret)
501 Some(ty) if is_named_and_not_impl_trait(ty) && arg_data.name == "_" => {
502 let ty = ty_to_string(ty);
503 format!("the explicit type `{}`, with the type parameters specified", ty)
505 Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != arg_data.name => {
506 let ty = ty_to_string(ty);
508 "the explicit type `{}`, where the type parameter `{}` is specified",
512 _ => "a type".to_string(),
515 if let Some(e) = local_visitor.found_exact_method_call {
516 if let ExprKind::MethodCall(segment, ..) = &e.kind {
517 // Suggest specifying type params or point out the return type of the call:
519 // error[E0282]: type annotations needed
520 // --> $DIR/type-annotations-needed-expr.rs:2:39
522 // LL | let _ = x.into_iter().sum() as f64;
525 // | cannot infer type for `S`
526 // | help: consider specifying the type argument in
527 // | the method call: `sum::<S>`
529 // = note: type must be known at this point
533 // error[E0282]: type annotations needed
534 // --> $DIR/issue-65611.rs:59:20
536 // LL | let x = buffer.last().unwrap().0.clone();
539 // | | cannot infer type for `T`
540 // | this method call resolves to `std::option::Option<&T>`
542 // = note: type must be known at this point
543 self.annotate_method_call(segment, e, &mut err);
545 } else if let Some(pattern) = local_visitor.found_arg_pattern {
546 // We don't want to show the default label for closures.
548 // So, before clearing, the output would look something like this:
551 // - ^^^^ cannot infer type for `[_; 0]`
553 // consider giving this closure parameter a type
556 // After clearing, it looks something like this:
559 // ^ consider giving this closure parameter the type `[_; 0]`
560 // with the type parameter `_` specified
564 format!("consider giving this closure parameter {}", suffix),
566 } else if let Some(pattern) = local_visitor.found_local_pattern {
567 let msg = if let Some(simple_ident) = pattern.simple_ident() {
568 match pattern.span.desugaring_kind() {
569 None => format!("consider giving `{}` {}", simple_ident, suffix),
570 Some(DesugaringKind::ForLoop(_)) => {
571 "the element type for this iterator is not specified".to_string()
573 _ => format!("this needs {}", suffix),
576 format!("consider giving this pattern {}", suffix)
578 err.span_label(pattern.span, msg);
579 } else if let Some(e) = local_visitor.found_method_call {
580 if let ExprKind::MethodCall(segment, ..) = &e.kind {
581 // Suggest specifying type params or point out the return type of the call:
583 // error[E0282]: type annotations needed
584 // --> $DIR/type-annotations-needed-expr.rs:2:39
586 // LL | let _ = x.into_iter().sum() as f64;
589 // | cannot infer type for `S`
590 // | help: consider specifying the type argument in
591 // | the method call: `sum::<S>`
593 // = note: type must be known at this point
597 // error[E0282]: type annotations needed
598 // --> $DIR/issue-65611.rs:59:20
600 // LL | let x = buffer.last().unwrap().0.clone();
603 // | | cannot infer type for `T`
604 // | this method call resolves to `std::option::Option<&T>`
606 // = note: type must be known at this point
607 self.annotate_method_call(segment, e, &mut err);
610 // Instead of the following:
611 // error[E0282]: type annotations needed
614 // 3 | let _ = x.sum() as f64;
615 // | --^^^--------- cannot infer type for `S`
617 // = note: type must be known at this point
619 // error[E0282]: type annotations needed
622 // 3 | let _ = x.sum() as f64;
623 // | ^^^ cannot infer type for `S`
625 // = note: type must be known at this point
626 let span = arg_data.span.unwrap_or(err_span);
631 .any(|span_label| span_label.label.is_some() && span_label.span == span)
632 && local_visitor.found_arg_pattern.is_none()
634 // Avoid multiple labels pointing at `span`.
637 InferCtxt::cannot_infer_msg(
640 &arg_data.description,
641 arg_data.parent_name,
642 arg_data.parent_description,
650 /// If the `FnSig` for the method call can be found and type arguments are identified as
651 /// needed, suggest annotating the call, otherwise point out the resulting type of the call.
652 fn annotate_method_call(
654 segment: &hir::PathSegment<'_>,
656 err: &mut DiagnosticBuilder<'_>,
658 if let (Some(typeck_results), None) = (self.in_progress_typeck_results, &segment.args) {
659 let borrow = typeck_results.borrow();
660 if let Some((DefKind::AssocFn, did)) = borrow.type_dependent_def(e.hir_id) {
661 let generics = self.tcx.generics_of(did);
662 if !generics.params.is_empty() {
663 err.span_suggestion_verbose(
664 segment.ident.span.shrink_to_hi(),
666 "consider specifying the type argument{} in the method call",
667 pluralize!(generics.params.len()),
674 .map(|p| p.name.to_string())
675 .collect::<Vec<String>>()
678 Applicability::HasPlaceholders,
681 let sig = self.tcx.fn_sig(did);
682 let bound_output = sig.output();
683 let output = bound_output.skip_binder();
684 err.span_label(e.span, &format!("this method call resolves to `{}`", output));
685 let kind = output.kind();
686 if let ty::Projection(proj) = kind {
687 if let Some(span) = self.tcx.hir().span_if_local(proj.item_def_id) {
688 err.span_label(span, &format!("`{}` defined here", output));
696 pub fn need_type_info_err_in_generator(
698 kind: hir::GeneratorKind,
701 ) -> DiagnosticBuilder<'tcx> {
702 let ty = self.resolve_vars_if_possible(&ty);
703 let data = self.extract_inference_diagnostics_data(ty.into(), None);
705 let mut err = struct_span_err!(
709 "type inside {} must be known in this context",
714 InferCtxt::cannot_infer_msg(
719 data.parent_description,
729 parent_name: Option<String>,
730 parent_descr: Option<&str>,
732 if type_name == "_" {
733 format!("cannot infer {}", kind_str)
735 let parent_desc = if let Some(parent_name) = parent_name {
736 let parent_type_descr = if let Some(parent_descr) = parent_descr {
737 format!(" the {}", parent_descr)
742 format!(" declared on{} `{}`", parent_type_descr, parent_name)
747 // FIXME: We really shouldn't be dealing with strings here
748 // but instead use a sensible enum for cases like this.
749 let preposition = if "the value" == kind_str { "of" } else { "for" };
750 // For example: "cannot infer type for type parameter `T`"
752 "cannot infer {} {} {} `{}`{}",
753 kind_str, preposition, descr, type_name, parent_desc