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::ty::print::Print;
10 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
11 use rustc_middle::ty::{self, DefIdTree, Ty};
12 use rustc_span::source_map::DesugaringKind;
13 use rustc_span::symbol::kw;
17 struct FindHirNodeVisitor<'a, 'tcx> {
18 infcx: &'a InferCtxt<'a, 'tcx>,
19 target: GenericArg<'tcx>,
21 found_node_ty: Option<Ty<'tcx>>,
22 found_local_pattern: Option<&'tcx Pat<'tcx>>,
23 found_arg_pattern: Option<&'tcx Pat<'tcx>>,
24 found_closure: Option<&'tcx Expr<'tcx>>,
25 found_method_call: Option<&'tcx Expr<'tcx>>,
26 found_exact_method_call: Option<&'tcx Expr<'tcx>>,
29 impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
30 fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>, target_span: Span) -> Self {
36 found_local_pattern: None,
37 found_arg_pattern: None,
39 found_method_call: None,
40 found_exact_method_call: None,
44 fn node_ty_contains_target(&mut self, hir_id: HirId) -> Option<Ty<'tcx>> {
47 .in_progress_typeck_results
48 .and_then(|typeck_results| typeck_results.borrow().node_type_opt(hir_id));
51 let ty = self.infcx.resolve_vars_if_possible(&ty);
52 if ty.walk().any(|inner| {
54 || match (inner.unpack(), self.target.unpack()) {
55 (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {
56 match (inner_ty.kind(), target_ty.kind()) {
58 &ty::Infer(ty::TyVar(a_vid)),
59 &ty::Infer(ty::TyVar(b_vid)),
65 .sub_unified(a_vid, b_vid),
82 impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> {
85 fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
86 NestedVisitorMap::OnlyBodies(self.infcx.tcx.hir())
89 fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
90 if let (None, Some(ty)) =
91 (self.found_local_pattern, self.node_ty_contains_target(local.hir_id))
93 // FIXME: There's a trade-off here - we can either check that our target span
94 // is contained in `local.span` or not. If we choose to check containment
95 // we can avoid some spurious suggestions (see #72690), but we lose
96 // the ability to report on things like:
102 // because the target span will be in the macro expansion of `vec![]`.
103 // At present we choose not to check containment.
104 self.found_local_pattern = Some(&*local.pat);
105 self.found_node_ty = Some(ty);
107 intravisit::walk_local(self, local);
110 fn visit_body(&mut self, body: &'tcx Body<'tcx>) {
111 for param in body.params {
112 if let (None, Some(ty)) =
113 (self.found_arg_pattern, self.node_ty_contains_target(param.hir_id))
115 if self.target_span.contains(param.pat.span) {
116 self.found_arg_pattern = Some(&*param.pat);
117 self.found_node_ty = Some(ty);
121 intravisit::walk_body(self, body);
124 fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
125 if let ExprKind::MethodCall(_, call_span, exprs, _) = expr.kind {
126 if call_span == self.target_span
128 == self.infcx.in_progress_typeck_results.and_then(|typeck_results| {
131 .node_type_opt(exprs.first().unwrap().hir_id)
135 self.found_exact_method_call = Some(&expr);
139 if self.node_ty_contains_target(expr.hir_id).is_some() {
141 ExprKind::Closure(..) => self.found_closure = Some(&expr),
142 ExprKind::MethodCall(..) => self.found_method_call = Some(&expr),
146 intravisit::walk_expr(self, expr);
150 /// Suggest giving an appropriate return type to a closure expression.
151 fn closure_return_type_suggestion(
153 err: &mut DiagnosticBuilder<'_>,
154 output: &FnRetTy<'_>,
159 parent_name: Option<String>,
160 parent_descr: Option<&str>,
162 let (arrow, post) = match output {
163 FnRetTy::DefaultReturn(_) => ("-> ", " "),
166 let suggestion = match body.value.kind {
167 ExprKind::Block(..) => vec![(output.span(), format!("{}{}{}", arrow, ret, post))],
169 (output.span(), format!("{}{}{}{{ ", arrow, ret, post)),
170 (body.value.span.shrink_to_hi(), " }".to_string()),
173 err.multipart_suggestion(
174 "give this closure an explicit return type without `_` placeholders",
176 Applicability::HasPlaceholders,
178 err.span_label(span, InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr));
181 /// Given a closure signature, return a `String` containing a list of all its argument types.
182 fn closure_args(fn_sig: &ty::PolyFnSig<'_>) -> String {
188 .map(|args| args.tuple_fields().map(|arg| arg.to_string()).collect::<Vec<_>>().join(", "))
192 pub enum TypeAnnotationNeeded {
193 /// ```compile_fail,E0282
194 /// let x = "hello".chars().rev().collect();
197 /// An implementation cannot be chosen unambiguously because of lack of information.
198 /// ```compile_fail,E0283
199 /// let _ = Default::default();
202 /// ```compile_fail,E0284
203 /// let mut d: u64 = 2;
204 /// d = d % 1u32.into();
209 impl Into<rustc_errors::DiagnosticId> for TypeAnnotationNeeded {
210 fn into(self) -> rustc_errors::DiagnosticId {
212 Self::E0282 => rustc_errors::error_code!(E0282),
213 Self::E0283 => rustc_errors::error_code!(E0283),
214 Self::E0284 => rustc_errors::error_code!(E0284),
219 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
220 pub fn extract_type_name(
223 highlight: Option<ty::print::RegionHighlightMode>,
224 ) -> (String, Option<Span>, Cow<'static, str>, Option<String>, Option<&'static str>) {
225 if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() {
226 let mut inner = self.inner.borrow_mut();
227 let ty_vars = &inner.type_variables();
228 let var_origin = ty_vars.var_origin(ty_vid);
229 if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind {
230 let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id));
231 let (parent_name, parent_desc) = if let Some(parent_def_id) = parent_def_id {
232 let parent_name = self
234 .def_key(parent_def_id)
238 .map(|parent_symbol| parent_symbol.to_string());
240 (parent_name, Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)))
245 if name != kw::SelfUpper {
248 Some(var_origin.span),
249 "type parameter".into(),
257 let mut s = String::new();
258 let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
259 if let Some(highlight) = highlight {
260 printer.region_highlight_mode = highlight;
262 let _ = ty.print(printer);
263 (s, None, ty.prefix_string(), None, None)
266 // FIXME(eddyb) generalize all of this to handle `ty::Const` inference variables as well.
267 pub fn need_type_info_err(
269 body_id: Option<hir::BodyId>,
272 error_code: TypeAnnotationNeeded,
273 ) -> DiagnosticBuilder<'tcx> {
274 let ty = self.resolve_vars_if_possible(&ty);
275 let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None);
277 let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into(), span);
278 let ty_to_string = |ty: Ty<'tcx>| -> String {
279 let mut s = String::new();
280 let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
281 let mut inner = self.inner.borrow_mut();
282 let ty_vars = inner.type_variables();
283 let getter = move |ty_vid| {
284 let var_origin = ty_vars.var_origin(ty_vid);
285 if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = var_origin.kind {
286 return Some(name.to_string());
290 printer.name_resolver = Some(Box::new(&getter));
291 let _ = if let ty::FnDef(..) = ty.kind() {
292 // We don't want the regular output for `fn`s because it includes its path in
293 // invalid pseudo-syntax, we want the `fn`-pointer output instead.
294 ty.fn_sig(self.tcx).print(printer)
301 if let Some(body_id) = body_id {
302 let expr = self.tcx.hir().expect_expr(body_id.hir_id);
303 local_visitor.visit_expr(expr);
305 let err_span = if let Some(pattern) = local_visitor.found_arg_pattern {
307 } else if let Some(span) = name_sp {
308 // `span` here lets us point at `sum` instead of the entire right hand side expr:
309 // error[E0282]: type annotations needed
312 // 3 | let _ = x.sum() as f64;
313 // | ^^^ cannot infer type for `S`
315 } else if let Some(ExprKind::MethodCall(_, call_span, _, _)) =
316 local_visitor.found_method_call.map(|e| &e.kind)
318 // Point at the call instead of the whole expression:
319 // error[E0284]: type annotations needed
322 // 2 | vec![Ok(2)].into_iter().collect()?;
323 // | ^^^^^^^ cannot infer type
325 // = note: cannot resolve `<_ as std::ops::Try>::Ok == _`
326 if span.contains(*call_span) { *call_span } else { span }
331 let is_named_and_not_impl_trait = |ty: Ty<'_>| {
332 &ty.to_string() != "_" &&
333 // FIXME: Remove this check after `impl_trait_in_bindings` is stabilized. #63527
334 (!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings)
337 let ty_msg = match (local_visitor.found_node_ty, local_visitor.found_exact_method_call) {
338 (_, Some(_)) => String::new(),
339 (Some(ty), _) if ty.is_closure() => {
341 if let ty::Closure(_, substs) = *ty.kind() { substs } else { unreachable!() };
342 let fn_sig = substs.as_closure().sig();
343 let args = closure_args(&fn_sig);
344 let ret = fn_sig.output().skip_binder().to_string();
345 format!(" for the closure `fn({}) -> {}`", args, ret)
347 (Some(ty), _) if is_named_and_not_impl_trait(ty) => {
348 let ty = ty_to_string(ty);
349 format!(" for `{}`", ty)
354 // When `name` corresponds to a type argument, show the path of the full type we're
355 // trying to infer. In the following example, `ty_msg` contains
356 // " in `std::result::Result<i32, E>`":
358 // error[E0282]: type annotations needed for `std::result::Result<i32, E>`
361 // L | let b = Ok(4);
362 // | - ^^ cannot infer type for `E` in `std::result::Result<i32, E>`
364 // | consider giving `b` the explicit type `std::result::Result<i32, E>`, where
365 // | the type parameter `E` is specified
367 let error_code = error_code.into();
368 let mut err = self.tcx.sess.struct_span_err_with_code(
370 &format!("type annotations needed{}", ty_msg),
374 let suffix = match local_visitor.found_node_ty {
375 Some(ty) if ty.is_closure() => {
377 if let ty::Closure(_, substs) = *ty.kind() { substs } else { unreachable!() };
378 let fn_sig = substs.as_closure().sig();
379 let ret = fn_sig.output().skip_binder().to_string();
381 let closure_decl_and_body_id =
382 local_visitor.found_closure.and_then(|closure| match &closure.kind {
383 ExprKind::Closure(_, decl, body_id, ..) => Some((decl, *body_id)),
387 if let Some((decl, body_id)) = closure_decl_and_body_id {
388 closure_return_type_suggestion(
392 self.tcx.hir().body(body_id),
399 // We don't want to give the other suggestions when the problem is the
400 // closure return type.
404 // This shouldn't be reachable, but just in case we leave a reasonable fallback.
405 let args = closure_args(&fn_sig);
406 // This suggestion is incomplete, as the user will get further type inference
407 // errors due to the `_` placeholders and the introduction of `Box`, but it does
408 // nudge them in the right direction.
409 format!("a boxed closure type like `Box<dyn Fn({}) -> {}>`", args, ret)
411 Some(ty) if is_named_and_not_impl_trait(ty) && name == "_" => {
412 let ty = ty_to_string(ty);
413 format!("the explicit type `{}`, with the type parameters specified", ty)
415 Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != name => {
416 let ty = ty_to_string(ty);
418 "the explicit type `{}`, where the type parameter `{}` is specified",
422 _ => "a type".to_string(),
425 if let Some(e) = local_visitor.found_exact_method_call {
426 if let ExprKind::MethodCall(segment, ..) = &e.kind {
427 // Suggest specifying type params or point out the return type of the call:
429 // error[E0282]: type annotations needed
430 // --> $DIR/type-annotations-needed-expr.rs:2:39
432 // LL | let _ = x.into_iter().sum() as f64;
435 // | cannot infer type for `S`
436 // | help: consider specifying the type argument in
437 // | the method call: `sum::<S>`
439 // = note: type must be known at this point
443 // error[E0282]: type annotations needed
444 // --> $DIR/issue-65611.rs:59:20
446 // LL | let x = buffer.last().unwrap().0.clone();
449 // | | cannot infer type for `T`
450 // | this method call resolves to `std::option::Option<&T>`
452 // = note: type must be known at this point
453 self.annotate_method_call(segment, e, &mut err);
455 } else if let Some(pattern) = local_visitor.found_arg_pattern {
456 // We don't want to show the default label for closures.
458 // So, before clearing, the output would look something like this:
461 // - ^^^^ cannot infer type for `[_; 0]`
463 // consider giving this closure parameter a type
466 // After clearing, it looks something like this:
469 // ^ consider giving this closure parameter the type `[_; 0]`
470 // with the type parameter `_` specified
474 format!("consider giving this closure parameter {}", suffix),
476 } else if let Some(pattern) = local_visitor.found_local_pattern {
477 let msg = if let Some(simple_ident) = pattern.simple_ident() {
478 match pattern.span.desugaring_kind() {
479 None => format!("consider giving `{}` {}", simple_ident, suffix),
480 Some(DesugaringKind::ForLoop(_)) => {
481 "the element type for this iterator is not specified".to_string()
483 _ => format!("this needs {}", suffix),
486 format!("consider giving this pattern {}", suffix)
488 err.span_label(pattern.span, msg);
489 } else if let Some(e) = local_visitor.found_method_call {
490 if let ExprKind::MethodCall(segment, ..) = &e.kind {
491 // Suggest specifying type params or point out the return type of the call:
493 // error[E0282]: type annotations needed
494 // --> $DIR/type-annotations-needed-expr.rs:2:39
496 // LL | let _ = x.into_iter().sum() as f64;
499 // | cannot infer type for `S`
500 // | help: consider specifying the type argument in
501 // | the method call: `sum::<S>`
503 // = note: type must be known at this point
507 // error[E0282]: type annotations needed
508 // --> $DIR/issue-65611.rs:59:20
510 // LL | let x = buffer.last().unwrap().0.clone();
513 // | | cannot infer type for `T`
514 // | this method call resolves to `std::option::Option<&T>`
516 // = note: type must be known at this point
517 self.annotate_method_call(segment, e, &mut err);
520 // Instead of the following:
521 // error[E0282]: type annotations needed
524 // 3 | let _ = x.sum() as f64;
525 // | --^^^--------- cannot infer type for `S`
527 // = note: type must be known at this point
529 // error[E0282]: type annotations needed
532 // 3 | let _ = x.sum() as f64;
533 // | ^^^ cannot infer type for `S`
535 // = note: type must be known at this point
536 let span = name_sp.unwrap_or(err_span);
541 .any(|span_label| span_label.label.is_some() && span_label.span == span)
542 && local_visitor.found_arg_pattern.is_none()
544 // Avoid multiple labels pointing at `span`.
547 InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr),
554 // FIXME(const_generics): We should either try and merge this with `need_type_info_err`
555 // or improve the errors created here.
557 // Unlike for type inference variables, we don't yet store the origin of const inference variables.
558 // This is needed for to get a more relevant error span.
559 pub fn need_type_info_err_const(
561 body_id: Option<hir::BodyId>,
563 ct: &'tcx ty::Const<'tcx>,
564 error_code: TypeAnnotationNeeded,
565 ) -> DiagnosticBuilder<'tcx> {
566 let mut local_visitor = FindHirNodeVisitor::new(&self, ct.into(), span);
567 if let Some(body_id) = body_id {
568 let expr = self.tcx.hir().expect_expr(body_id.hir_id);
569 local_visitor.visit_expr(expr);
572 let error_code = error_code.into();
573 let mut err = self.tcx.sess.struct_span_err_with_code(
574 local_visitor.target_span,
575 "type annotations needed",
579 err.note("unable to infer the value of a const parameter");
584 /// If the `FnSig` for the method call can be found and type arguments are identified as
585 /// needed, suggest annotating the call, otherwise point out the resulting type of the call.
586 fn annotate_method_call(
588 segment: &hir::PathSegment<'_>,
590 err: &mut DiagnosticBuilder<'_>,
592 if let (Some(typeck_results), None) = (self.in_progress_typeck_results, &segment.args) {
593 let borrow = typeck_results.borrow();
594 if let Some((DefKind::AssocFn, did)) = borrow.type_dependent_def(e.hir_id) {
595 let generics = self.tcx.generics_of(did);
596 if !generics.params.is_empty() {
597 err.span_suggestion_verbose(
598 segment.ident.span.shrink_to_hi(),
600 "consider specifying the type argument{} in the method call",
601 pluralize!(generics.params.len()),
608 .map(|p| p.name.to_string())
609 .collect::<Vec<String>>()
612 Applicability::HasPlaceholders,
615 let sig = self.tcx.fn_sig(did);
616 let bound_output = sig.output();
617 let output = bound_output.skip_binder();
618 err.span_label(e.span, &format!("this method call resolves to `{}`", output));
619 let kind = output.kind();
620 if let ty::Projection(proj) = kind {
621 if let Some(span) = self.tcx.hir().span_if_local(proj.item_def_id) {
622 err.span_label(span, &format!("`{}` defined here", output));
630 pub fn need_type_info_err_in_generator(
632 kind: hir::GeneratorKind,
635 ) -> DiagnosticBuilder<'tcx> {
636 let ty = self.resolve_vars_if_possible(&ty);
637 let (name, _, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None);
639 let mut err = struct_span_err!(
643 "type inside {} must be known in this context",
646 err.span_label(span, InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr));
653 parent_name: Option<String>,
654 parent_descr: Option<&str>,
655 ) -> Cow<'static, str> {
656 if type_name == "_" {
657 "cannot infer type".into()
659 let parent_desc = if let Some(parent_name) = parent_name {
660 let parent_type_descr = if let Some(parent_descr) = parent_descr {
661 format!(" the {}", parent_descr)
666 format!(" declared on{} `{}`", parent_type_descr, parent_name)
671 format!("cannot infer type for {} `{}`{}", descr, type_name, parent_desc).into()