1 use crate::hir::def::{DefKind, Namespace};
2 use crate::hir::intravisit::{self, NestedVisitorMap, Visitor};
3 use crate::hir::{self, Body, Expr, ExprKind, FunctionRetTy, HirId, Local, Pat};
4 use crate::infer::type_variable::TypeVariableOriginKind;
5 use crate::infer::InferCtxt;
6 use crate::ty::print::Print;
7 use crate::ty::{self, DefIdTree, Infer, Ty, TyVar};
8 use errors::{Applicability, DiagnosticBuilder};
10 use syntax::source_map::DesugaringKind;
11 use syntax::symbol::kw;
14 use rustc_error_codes::*;
16 struct FindLocalByTypeVisitor<'a, 'tcx> {
17 infcx: &'a InferCtxt<'a, 'tcx>,
19 hir_map: &'a hir::map::Map<'tcx>,
20 found_local_pattern: Option<&'tcx Pat<'tcx>>,
21 found_arg_pattern: Option<&'tcx Pat<'tcx>>,
22 found_ty: Option<Ty<'tcx>>,
23 found_closure: Option<&'tcx ExprKind<'tcx>>,
24 found_method_call: Option<&'tcx Expr<'tcx>>,
27 impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
29 infcx: &'a InferCtxt<'a, 'tcx>,
31 hir_map: &'a hir::map::Map<'tcx>,
37 found_local_pattern: None,
38 found_arg_pattern: None,
41 found_method_call: None,
45 fn node_matches_type(&mut self, hir_id: HirId) -> Option<Ty<'tcx>> {
47 self.infcx.in_progress_tables.and_then(|tables| tables.borrow().node_type_opt(hir_id));
50 let ty = self.infcx.resolve_vars_if_possible(&ty);
51 if ty.walk().any(|inner_ty| {
52 inner_ty == self.target_ty
53 || match (&inner_ty.kind, &self.target_ty.kind) {
54 (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => {
55 self.infcx.type_variables.borrow_mut().sub_unified(a_vid, b_vid)
70 impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> {
71 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
72 NestedVisitorMap::OnlyBodies(&self.hir_map)
75 fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
76 if let (None, Some(ty)) = (self.found_local_pattern, self.node_matches_type(local.hir_id)) {
77 self.found_local_pattern = Some(&*local.pat);
78 self.found_ty = Some(ty);
80 intravisit::walk_local(self, local);
83 fn visit_body(&mut self, body: &'tcx Body<'tcx>) {
84 for param in body.params {
85 if let (None, Some(ty)) = (self.found_arg_pattern, self.node_matches_type(param.hir_id))
87 self.found_arg_pattern = Some(&*param.pat);
88 self.found_ty = Some(ty);
91 intravisit::walk_body(self, body);
94 fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
95 if self.node_matches_type(expr.hir_id).is_some() {
97 ExprKind::Closure(..) => self.found_closure = Some(&expr.kind),
98 ExprKind::MethodCall(..) => self.found_method_call = Some(&expr),
102 intravisit::walk_expr(self, expr);
106 /// Suggest giving an appropriate return type to a closure expression.
107 fn closure_return_type_suggestion(
109 err: &mut DiagnosticBuilder<'_>,
110 output: &FunctionRetTy<'_>,
115 parent_name: Option<String>,
116 parent_descr: Option<&str>,
118 let (arrow, post) = match output {
119 FunctionRetTy::DefaultReturn(_) => ("-> ", " "),
122 let suggestion = match body.value.kind {
123 ExprKind::Block(..) => vec![(output.span(), format!("{}{}{}", arrow, ret, post))],
125 (output.span(), format!("{}{}{}{{ ", arrow, ret, post)),
126 (body.value.span.shrink_to_hi(), " }".to_string()),
129 err.multipart_suggestion(
130 "give this closure an explicit return type without `_` placeholders",
132 Applicability::HasPlaceholders,
134 err.span_label(span, InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr));
137 /// Given a closure signature, return a `String` containing a list of all its argument types.
138 fn closure_args(fn_sig: &ty::PolyFnSig<'_>) -> String {
144 .map(|args| args.tuple_fields().map(|arg| arg.to_string()).collect::<Vec<_>>().join(", "))
148 pub enum TypeAnnotationNeeded {
154 impl Into<errors::DiagnosticId> for TypeAnnotationNeeded {
155 fn into(self) -> errors::DiagnosticId {
156 syntax::diagnostic_used!(E0282);
157 syntax::diagnostic_used!(E0283);
158 syntax::diagnostic_used!(E0284);
159 errors::DiagnosticId::Error(match self {
160 Self::E0282 => "E0282".to_string(),
161 Self::E0283 => "E0283".to_string(),
162 Self::E0284 => "E0284".to_string(),
167 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
168 pub fn extract_type_name(
171 highlight: Option<ty::print::RegionHighlightMode>,
172 ) -> (String, Option<Span>, Cow<'static, str>, Option<String>, Option<&'static str>) {
173 if let ty::Infer(ty::TyVar(ty_vid)) = ty.kind {
174 let ty_vars = self.type_variables.borrow();
175 let var_origin = ty_vars.var_origin(ty_vid);
176 if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind {
177 let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id));
178 let (parent_name, parent_desc) = if let Some(parent_def_id) = parent_def_id {
179 let parent_name = self
181 .def_key(parent_def_id)
185 .map(|parent_symbol| parent_symbol.to_string());
187 let type_parent_desc = self
189 .def_kind(parent_def_id)
190 .map(|parent_def_kind| parent_def_kind.descr(parent_def_id));
192 (parent_name, type_parent_desc)
197 if name != kw::SelfUpper {
200 Some(var_origin.span),
201 "type parameter".into(),
209 let mut s = String::new();
210 let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
211 if let Some(highlight) = highlight {
212 printer.region_highlight_mode = highlight;
214 let _ = ty.print(printer);
215 (s, None, ty.prefix_string(), None, None)
218 pub fn need_type_info_err(
220 body_id: Option<hir::BodyId>,
223 error_code: TypeAnnotationNeeded,
224 ) -> DiagnosticBuilder<'tcx> {
225 let ty = self.resolve_vars_if_possible(&ty);
226 let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None);
228 let mut local_visitor = FindLocalByTypeVisitor::new(&self, ty, &self.tcx.hir());
229 let ty_to_string = |ty: Ty<'tcx>| -> String {
230 let mut s = String::new();
231 let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
232 let ty_vars = self.type_variables.borrow();
233 let getter = move |ty_vid| {
234 let var_origin = ty_vars.var_origin(ty_vid);
235 if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = var_origin.kind {
236 return Some(name.to_string());
240 printer.name_resolver = Some(Box::new(&getter));
241 let _ = ty.print(printer);
245 if let Some(body_id) = body_id {
246 let expr = self.tcx.hir().expect_expr(body_id.hir_id);
247 local_visitor.visit_expr(expr);
249 let err_span = if let Some(pattern) = local_visitor.found_arg_pattern {
251 } else if let Some(span) = name_sp {
252 // `span` here lets us point at `sum` instead of the entire right hand side expr:
253 // error[E0282]: type annotations needed
256 // 3 | let _ = x.sum() as f64;
257 // | ^^^ cannot infer type for `S`
259 } else if let Some(ExprKind::MethodCall(_, call_span, _)) =
260 local_visitor.found_method_call.map(|e| &e.kind)
262 // Point at the call instead of the whole expression:
263 // error[E0284]: type annotations needed
266 // 2 | vec![Ok(2)].into_iter().collect()?;
267 // | ^^^^^^^ cannot infer type
269 // = note: cannot resolve `<_ as std::ops::Try>::Ok == _`
270 if span.contains(*call_span) { *call_span } else { span }
275 let is_named_and_not_impl_trait = |ty: Ty<'_>| {
276 &ty.to_string() != "_" &&
277 // FIXME: Remove this check after `impl_trait_in_bindings` is stabilized. #63527
278 (!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings)
281 let ty_msg = match local_visitor.found_ty {
282 Some(ty::TyS { kind: ty::Closure(def_id, substs), .. }) => {
283 let fn_sig = substs.as_closure().sig(*def_id, self.tcx);
284 let args = closure_args(&fn_sig);
285 let ret = fn_sig.output().skip_binder().to_string();
286 format!(" for the closure `fn({}) -> {}`", args, ret)
288 Some(ty) if is_named_and_not_impl_trait(ty) => {
289 let ty = ty_to_string(ty);
290 format!(" for `{}`", ty)
295 // When `name` corresponds to a type argument, show the path of the full type we're
296 // trying to infer. In the following example, `ty_msg` contains
297 // " in `std::result::Result<i32, E>`":
299 // error[E0282]: type annotations needed for `std::result::Result<i32, E>`
302 // L | let b = Ok(4);
303 // | - ^^ cannot infer type for `E` in `std::result::Result<i32, E>`
305 // | consider giving `b` the explicit type `std::result::Result<i32, E>`, where
306 // | the type parameter `E` is specified
308 let error_code = error_code.into();
309 let mut err = self.tcx.sess.struct_span_err_with_code(
311 &format!("type annotations needed{}", ty_msg),
315 let suffix = match local_visitor.found_ty {
316 Some(ty::TyS { kind: ty::Closure(def_id, substs), .. }) => {
317 let fn_sig = substs.as_closure().sig(*def_id, self.tcx);
318 let ret = fn_sig.output().skip_binder().to_string();
320 if let Some(ExprKind::Closure(_, decl, body_id, ..)) = local_visitor.found_closure {
321 if let Some(body) = self.tcx.hir().krate().bodies.get(body_id) {
322 closure_return_type_suggestion(
333 // We don't want to give the other suggestions when the problem is the
334 // closure return type.
339 // This shouldn't be reachable, but just in case we leave a reasonable fallback.
340 let args = closure_args(&fn_sig);
341 // This suggestion is incomplete, as the user will get further type inference
342 // errors due to the `_` placeholders and the introduction of `Box`, but it does
343 // nudge them in the right direction.
344 format!("a boxed closure type like `Box<dyn Fn({}) -> {}>`", args, ret)
346 Some(ty) if is_named_and_not_impl_trait(ty) && name == "_" => {
347 let ty = ty_to_string(ty);
348 format!("the explicit type `{}`, with the type parameters specified", ty)
350 Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != name => {
351 let ty = ty_to_string(ty);
353 "the explicit type `{}`, where the type parameter `{}` is specified",
357 _ => "a type".to_string(),
360 if let Some(pattern) = local_visitor.found_arg_pattern {
361 // We don't want to show the default label for closures.
363 // So, before clearing, the output would look something like this:
366 // - ^^^^ cannot infer type for `[_; 0]`
368 // consider giving this closure parameter a type
371 // After clearing, it looks something like this:
374 // ^ consider giving this closure parameter the type `[_; 0]`
375 // with the type parameter `_` specified
379 format!("consider giving this closure parameter {}", suffix),
381 } else if let Some(pattern) = local_visitor.found_local_pattern {
382 let msg = if let Some(simple_ident) = pattern.simple_ident() {
383 match pattern.span.desugaring_kind() {
384 None => format!("consider giving `{}` {}", simple_ident, suffix),
385 Some(DesugaringKind::ForLoop) => {
386 "the element type for this iterator is not specified".to_string()
388 _ => format!("this needs {}", suffix),
391 format!("consider giving this pattern {}", suffix)
393 err.span_label(pattern.span, msg);
394 } else if let Some(e) = local_visitor.found_method_call {
395 if let ExprKind::MethodCall(segment, ..) = &e.kind {
396 // Suggest specifiying type params or point out the return type of the call:
398 // error[E0282]: type annotations needed
399 // --> $DIR/type-annotations-needed-expr.rs:2:39
401 // LL | let _ = x.into_iter().sum() as f64;
404 // | cannot infer type for `S`
405 // | help: consider specifying the type argument in
406 // | the method call: `sum::<S>`
408 // = note: type must be known at this point
412 // error[E0282]: type annotations needed
413 // --> $DIR/issue-65611.rs:59:20
415 // LL | let x = buffer.last().unwrap().0.clone();
418 // | | cannot infer type for `T`
419 // | this method call resolves to `std::option::Option<&T>`
421 // = note: type must be known at this point
422 self.annotate_method_call(segment, e, &mut err);
425 // Instead of the following:
426 // error[E0282]: type annotations needed
429 // 3 | let _ = x.sum() as f64;
430 // | --^^^--------- cannot infer type for `S`
432 // = note: type must be known at this point
434 // error[E0282]: type annotations needed
437 // 3 | let _ = x.sum() as f64;
438 // | ^^^ cannot infer type for `S`
440 // = note: type must be known at this point
441 let span = name_sp.unwrap_or(err_span);
446 .any(|span_label| span_label.label.is_some() && span_label.span == span)
447 && local_visitor.found_arg_pattern.is_none()
449 // Avoid multiple labels pointing at `span`.
452 InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr),
459 /// If the `FnSig` for the method call can be found and type arguments are identified as
460 /// needed, suggest annotating the call, otherwise point out the resulting type of the call.
461 fn annotate_method_call(
463 segment: &hir::PathSegment<'_>,
465 err: &mut DiagnosticBuilder<'_>,
467 if let (Ok(snippet), Some(tables), None) = (
468 self.tcx.sess.source_map().span_to_snippet(segment.ident.span),
469 self.in_progress_tables,
472 let borrow = tables.borrow();
473 if let Some((DefKind::Method, did)) = borrow.type_dependent_def(e.hir_id) {
474 let generics = self.tcx.generics_of(did);
475 if !generics.params.is_empty() {
479 "consider specifying the type argument{} in the method call",
480 if generics.params.len() > 1 { "s" } else { "" },
488 .map(|p| p.name.to_string())
489 .collect::<Vec<String>>()
492 Applicability::HasPlaceholders,
495 let sig = self.tcx.fn_sig(did);
496 let bound_output = sig.output();
497 let output = bound_output.skip_binder();
498 err.span_label(e.span, &format!("this method call resolves to `{:?}`", output));
499 let kind = &output.kind;
500 if let ty::Projection(proj) | ty::UnnormalizedProjection(proj) = kind {
501 if let Some(span) = self.tcx.hir().span_if_local(proj.item_def_id) {
502 err.span_label(span, &format!("`{:?}` defined here", output));
510 pub fn need_type_info_err_in_generator(
512 kind: hir::GeneratorKind,
515 ) -> DiagnosticBuilder<'tcx> {
516 let ty = self.resolve_vars_if_possible(&ty);
517 let (name, _, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None);
519 let mut err = struct_span_err!(
523 "type inside {} must be known in this context",
526 err.span_label(span, InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr));
533 parent_name: Option<String>,
534 parent_descr: Option<&str>,
535 ) -> Cow<'static, str> {
536 if type_name == "_" {
537 "cannot infer type".into()
539 let parent_desc = if let Some(parent_name) = parent_name {
540 let parent_type_descr = if let Some(parent_descr) = parent_descr {
541 format!(" the {}", parent_descr)
546 format!(" declared on{} `{}`", parent_type_descr, parent_name)
551 format!("cannot infer type for {} `{}`{}", descr, type_name, parent_desc).into()