]>
Commit | Line | Data |
---|---|---|
dc9dc135 | 1 | use crate::infer::type_variable::TypeVariableOriginKind; |
dfeec247 | 2 | use crate::infer::InferCtxt; |
ba9703b0 | 3 | use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; |
dfeec247 XL |
4 | use rustc_hir as hir; |
5 | use rustc_hir::def::{DefKind, Namespace}; | |
6 | use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; | |
74b04a01 | 7 | use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat}; |
ba9703b0 XL |
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}; | |
dfeec247 XL |
12 | use rustc_span::source_map::DesugaringKind; |
13 | use rustc_span::symbol::kw; | |
14 | use rustc_span::Span; | |
60c5eb7d XL |
15 | use std::borrow::Cow; |
16 | ||
ba9703b0 | 17 | struct FindHirNodeVisitor<'a, 'tcx> { |
dc9dc135 | 18 | infcx: &'a InferCtxt<'a, 'tcx>, |
ba9703b0 | 19 | target: GenericArg<'tcx>, |
f9f354fc | 20 | target_span: Span, |
ba9703b0 | 21 | found_node_ty: Option<Ty<'tcx>>, |
dfeec247 XL |
22 | found_local_pattern: Option<&'tcx Pat<'tcx>>, |
23 | found_arg_pattern: Option<&'tcx Pat<'tcx>>, | |
ba9703b0 | 24 | found_closure: Option<&'tcx Expr<'tcx>>, |
dfeec247 | 25 | found_method_call: Option<&'tcx Expr<'tcx>>, |
f9f354fc | 26 | found_exact_method_call: Option<&'tcx Expr<'tcx>>, |
041b39d2 XL |
27 | } |
28 | ||
ba9703b0 | 29 | impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> { |
f9f354fc | 30 | fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>, target_span: Span) -> Self { |
e1599b0c XL |
31 | Self { |
32 | infcx, | |
ba9703b0 | 33 | target, |
f9f354fc | 34 | target_span, |
ba9703b0 | 35 | found_node_ty: None, |
e1599b0c XL |
36 | found_local_pattern: None, |
37 | found_arg_pattern: None, | |
e1599b0c | 38 | found_closure: None, |
60c5eb7d | 39 | found_method_call: None, |
f9f354fc | 40 | found_exact_method_call: None, |
e1599b0c XL |
41 | } |
42 | } | |
43 | ||
ba9703b0 | 44 | fn node_ty_contains_target(&mut self, hir_id: HirId) -> Option<Ty<'tcx>> { |
dfeec247 XL |
45 | let ty_opt = |
46 | self.infcx.in_progress_tables.and_then(|tables| tables.borrow().node_type_opt(hir_id)); | |
041b39d2 XL |
47 | match ty_opt { |
48 | Some(ty) => { | |
dc9dc135 | 49 | let ty = self.infcx.resolve_vars_if_possible(&ty); |
ba9703b0 XL |
50 | if ty.walk().any(|inner| { |
51 | inner == self.target | |
52 | || match (inner.unpack(), self.target.unpack()) { | |
53 | (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => { | |
54 | match (&inner_ty.kind, &target_ty.kind) { | |
55 | ( | |
56 | &ty::Infer(ty::TyVar(a_vid)), | |
57 | &ty::Infer(ty::TyVar(b_vid)), | |
58 | ) => self | |
59 | .infcx | |
60 | .inner | |
61 | .borrow_mut() | |
f9f354fc | 62 | .type_variables() |
ba9703b0 XL |
63 | .sub_unified(a_vid, b_vid), |
64 | _ => false, | |
65 | } | |
66 | } | |
dfeec247 | 67 | _ => false, |
041b39d2 | 68 | } |
dc9dc135 XL |
69 | }) { |
70 | Some(ty) | |
71 | } else { | |
72 | None | |
73 | } | |
041b39d2 | 74 | } |
dc9dc135 | 75 | None => None, |
041b39d2 XL |
76 | } |
77 | } | |
78 | } | |
79 | ||
ba9703b0 | 80 | impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> { |
dfeec247 XL |
81 | type Map = Map<'tcx>; |
82 | ||
ba9703b0 XL |
83 | fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { |
84 | NestedVisitorMap::OnlyBodies(self.infcx.tcx.hir()) | |
041b39d2 XL |
85 | } |
86 | ||
dfeec247 | 87 | fn visit_local(&mut self, local: &'tcx Local<'tcx>) { |
ba9703b0 XL |
88 | if let (None, Some(ty)) = |
89 | (self.found_local_pattern, self.node_ty_contains_target(local.hir_id)) | |
90 | { | |
f035d41b XL |
91 | // FIXME: There's a trade-off here - we can either check that our target span |
92 | // is contained in `local.span` or not. If we choose to check containment | |
93 | // we can avoid some spurious suggestions (see #72690), but we lose | |
94 | // the ability to report on things like: | |
95 | // | |
96 | // ``` | |
97 | // let x = vec![]; | |
98 | // ``` | |
99 | // | |
100 | // because the target span will be in the macro expansion of `vec![]`. | |
101 | // At present we choose not to check containment. | |
041b39d2 | 102 | self.found_local_pattern = Some(&*local.pat); |
ba9703b0 | 103 | self.found_node_ty = Some(ty); |
041b39d2 XL |
104 | } |
105 | intravisit::walk_local(self, local); | |
106 | } | |
107 | ||
dfeec247 XL |
108 | fn visit_body(&mut self, body: &'tcx Body<'tcx>) { |
109 | for param in body.params { | |
ba9703b0 XL |
110 | if let (None, Some(ty)) = |
111 | (self.found_arg_pattern, self.node_ty_contains_target(param.hir_id)) | |
dfeec247 | 112 | { |
f035d41b XL |
113 | if self.target_span.contains(param.pat.span) { |
114 | self.found_arg_pattern = Some(&*param.pat); | |
115 | self.found_node_ty = Some(ty); | |
116 | } | |
041b39d2 XL |
117 | } |
118 | } | |
119 | intravisit::walk_body(self, body); | |
120 | } | |
e1599b0c | 121 | |
dfeec247 | 122 | fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { |
f035d41b | 123 | if let ExprKind::MethodCall(_, call_span, exprs, _) = expr.kind { |
f9f354fc XL |
124 | if call_span == self.target_span |
125 | && Some(self.target) | |
126 | == self.infcx.in_progress_tables.and_then(|tables| { | |
127 | tables.borrow().node_type_opt(exprs.first().unwrap().hir_id).map(Into::into) | |
128 | }) | |
129 | { | |
130 | self.found_exact_method_call = Some(&expr); | |
131 | return; | |
132 | } | |
133 | } | |
ba9703b0 | 134 | if self.node_ty_contains_target(expr.hir_id).is_some() { |
60c5eb7d | 135 | match expr.kind { |
ba9703b0 | 136 | ExprKind::Closure(..) => self.found_closure = Some(&expr), |
60c5eb7d XL |
137 | ExprKind::MethodCall(..) => self.found_method_call = Some(&expr), |
138 | _ => {} | |
139 | } | |
e1599b0c XL |
140 | } |
141 | intravisit::walk_expr(self, expr); | |
142 | } | |
143 | } | |
144 | ||
145 | /// Suggest giving an appropriate return type to a closure expression. | |
146 | fn closure_return_type_suggestion( | |
147 | span: Span, | |
148 | err: &mut DiagnosticBuilder<'_>, | |
74b04a01 | 149 | output: &FnRetTy<'_>, |
dfeec247 | 150 | body: &Body<'_>, |
60c5eb7d | 151 | descr: &str, |
e1599b0c XL |
152 | name: &str, |
153 | ret: &str, | |
dfeec247 XL |
154 | parent_name: Option<String>, |
155 | parent_descr: Option<&str>, | |
e1599b0c XL |
156 | ) { |
157 | let (arrow, post) = match output { | |
74b04a01 | 158 | FnRetTy::DefaultReturn(_) => ("-> ", " "), |
e1599b0c XL |
159 | _ => ("", ""), |
160 | }; | |
e74abb32 | 161 | let suggestion = match body.value.kind { |
dfeec247 XL |
162 | ExprKind::Block(..) => vec![(output.span(), format!("{}{}{}", arrow, ret, post))], |
163 | _ => vec![ | |
164 | (output.span(), format!("{}{}{}{{ ", arrow, ret, post)), | |
165 | (body.value.span.shrink_to_hi(), " }".to_string()), | |
166 | ], | |
e1599b0c XL |
167 | }; |
168 | err.multipart_suggestion( | |
169 | "give this closure an explicit return type without `_` placeholders", | |
170 | suggestion, | |
171 | Applicability::HasPlaceholders, | |
172 | ); | |
dfeec247 | 173 | err.span_label(span, InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr)); |
e1599b0c XL |
174 | } |
175 | ||
176 | /// Given a closure signature, return a `String` containing a list of all its argument types. | |
177 | fn closure_args(fn_sig: &ty::PolyFnSig<'_>) -> String { | |
dfeec247 XL |
178 | fn_sig |
179 | .inputs() | |
e1599b0c XL |
180 | .skip_binder() |
181 | .iter() | |
182 | .next() | |
dfeec247 | 183 | .map(|args| args.tuple_fields().map(|arg| arg.to_string()).collect::<Vec<_>>().join(", ")) |
e1599b0c | 184 | .unwrap_or_default() |
041b39d2 XL |
185 | } |
186 | ||
60c5eb7d | 187 | pub enum TypeAnnotationNeeded { |
f9f354fc XL |
188 | /// ```compile_fail,E0282 |
189 | /// let x = "hello".chars().rev().collect(); | |
190 | /// ``` | |
60c5eb7d | 191 | E0282, |
f9f354fc XL |
192 | /// An implementation cannot be chosen unambiguously because of lack of information. |
193 | /// ```compile_fail,E0283 | |
194 | /// let _ = Default::default(); | |
195 | /// ``` | |
60c5eb7d | 196 | E0283, |
f9f354fc XL |
197 | /// ```compile_fail,E0284 |
198 | /// let mut d: u64 = 2; | |
199 | /// d = d % 1u32.into(); | |
200 | /// ``` | |
60c5eb7d XL |
201 | E0284, |
202 | } | |
203 | ||
dfeec247 XL |
204 | impl Into<rustc_errors::DiagnosticId> for TypeAnnotationNeeded { |
205 | fn into(self) -> rustc_errors::DiagnosticId { | |
206 | match self { | |
207 | Self::E0282 => rustc_errors::error_code!(E0282), | |
208 | Self::E0283 => rustc_errors::error_code!(E0283), | |
209 | Self::E0284 => rustc_errors::error_code!(E0284), | |
210 | } | |
60c5eb7d XL |
211 | } |
212 | } | |
213 | ||
dc9dc135 | 214 | impl<'a, 'tcx> InferCtxt<'a, 'tcx> { |
532ac7d7 XL |
215 | pub fn extract_type_name( |
216 | &self, | |
48663c56 | 217 | ty: Ty<'tcx>, |
532ac7d7 | 218 | highlight: Option<ty::print::RegionHighlightMode>, |
dfeec247 | 219 | ) -> (String, Option<Span>, Cow<'static, str>, Option<String>, Option<&'static str>) { |
e74abb32 | 220 | if let ty::Infer(ty::TyVar(ty_vid)) = ty.kind { |
f9f354fc XL |
221 | let mut inner = self.inner.borrow_mut(); |
222 | let ty_vars = &inner.type_variables(); | |
e1599b0c | 223 | let var_origin = ty_vars.var_origin(ty_vid); |
dfeec247 XL |
224 | if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind { |
225 | let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id)); | |
226 | let (parent_name, parent_desc) = if let Some(parent_def_id) = parent_def_id { | |
227 | let parent_name = self | |
228 | .tcx | |
229 | .def_key(parent_def_id) | |
230 | .disambiguated_data | |
231 | .data | |
232 | .get_opt_name() | |
233 | .map(|parent_symbol| parent_symbol.to_string()); | |
234 | ||
f9f354fc | 235 | (parent_name, Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id))) |
dfeec247 XL |
236 | } else { |
237 | (None, None) | |
238 | }; | |
239 | ||
60c5eb7d XL |
240 | if name != kw::SelfUpper { |
241 | return ( | |
242 | name.to_string(), | |
243 | Some(var_origin.span), | |
244 | "type parameter".into(), | |
dfeec247 XL |
245 | parent_name, |
246 | parent_desc, | |
60c5eb7d XL |
247 | ); |
248 | } | |
041b39d2 | 249 | } |
041b39d2 | 250 | } |
532ac7d7 XL |
251 | |
252 | let mut s = String::new(); | |
253 | let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); | |
254 | if let Some(highlight) = highlight { | |
255 | printer.region_highlight_mode = highlight; | |
256 | } | |
257 | let _ = ty.print(printer); | |
dfeec247 | 258 | (s, None, ty.prefix_string(), None, None) |
041b39d2 XL |
259 | } |
260 | ||
ba9703b0 | 261 | // FIXME(eddyb) generalize all of this to handle `ty::Const` inference variables as well. |
48663c56 XL |
262 | pub fn need_type_info_err( |
263 | &self, | |
264 | body_id: Option<hir::BodyId>, | |
265 | span: Span, | |
dc9dc135 | 266 | ty: Ty<'tcx>, |
60c5eb7d | 267 | error_code: TypeAnnotationNeeded, |
dc9dc135 XL |
268 | ) -> DiagnosticBuilder<'tcx> { |
269 | let ty = self.resolve_vars_if_possible(&ty); | |
dfeec247 | 270 | let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None); |
041b39d2 | 271 | |
f9f354fc | 272 | let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into(), span); |
dc9dc135 XL |
273 | let ty_to_string = |ty: Ty<'tcx>| -> String { |
274 | let mut s = String::new(); | |
275 | let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); | |
f9f354fc XL |
276 | let mut inner = self.inner.borrow_mut(); |
277 | let ty_vars = inner.type_variables(); | |
dc9dc135 | 278 | let getter = move |ty_vid| { |
60c5eb7d | 279 | let var_origin = ty_vars.var_origin(ty_vid); |
dfeec247 | 280 | if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = var_origin.kind { |
dc9dc135 XL |
281 | return Some(name.to_string()); |
282 | } | |
283 | None | |
284 | }; | |
285 | printer.name_resolver = Some(Box::new(&getter)); | |
f9f354fc XL |
286 | let _ = if let ty::FnDef(..) = ty.kind { |
287 | // We don't want the regular output for `fn`s because it includes its path in | |
288 | // invalid pseudo-syntax, we want the `fn`-pointer output instead. | |
289 | ty.fn_sig(self.tcx).print(printer) | |
290 | } else { | |
291 | ty.print(printer) | |
292 | }; | |
dc9dc135 | 293 | s |
041b39d2 XL |
294 | }; |
295 | ||
296 | if let Some(body_id) = body_id { | |
dc9dc135 | 297 | let expr = self.tcx.hir().expect_expr(body_id.hir_id); |
041b39d2 XL |
298 | local_visitor.visit_expr(expr); |
299 | } | |
e1599b0c XL |
300 | let err_span = if let Some(pattern) = local_visitor.found_arg_pattern { |
301 | pattern.span | |
302 | } else if let Some(span) = name_sp { | |
303 | // `span` here lets us point at `sum` instead of the entire right hand side expr: | |
304 | // error[E0282]: type annotations needed | |
305 | // --> file2.rs:3:15 | |
306 | // | | |
307 | // 3 | let _ = x.sum() as f64; | |
308 | // | ^^^ cannot infer type for `S` | |
309 | span | |
f035d41b | 310 | } else if let Some(ExprKind::MethodCall(_, call_span, _, _)) = |
dfeec247 XL |
311 | local_visitor.found_method_call.map(|e| &e.kind) |
312 | { | |
60c5eb7d XL |
313 | // Point at the call instead of the whole expression: |
314 | // error[E0284]: type annotations needed | |
315 | // --> file.rs:2:5 | |
316 | // | | |
317 | // 2 | vec![Ok(2)].into_iter().collect()?; | |
318 | // | ^^^^^^^ cannot infer type | |
319 | // | | |
320 | // = note: cannot resolve `<_ as std::ops::Try>::Ok == _` | |
dfeec247 | 321 | if span.contains(*call_span) { *call_span } else { span } |
e1599b0c XL |
322 | } else { |
323 | span | |
324 | }; | |
325 | ||
326 | let is_named_and_not_impl_trait = |ty: Ty<'_>| { | |
327 | &ty.to_string() != "_" && | |
328 | // FIXME: Remove this check after `impl_trait_in_bindings` is stabilized. #63527 | |
329 | (!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings) | |
330 | }; | |
331 | ||
f9f354fc XL |
332 | let ty_msg = match (local_visitor.found_node_ty, local_visitor.found_exact_method_call) { |
333 | (_, Some(_)) => String::new(), | |
334 | (Some(ty::TyS { kind: ty::Closure(_, substs), .. }), _) => { | |
ba9703b0 | 335 | let fn_sig = substs.as_closure().sig(); |
e1599b0c XL |
336 | let args = closure_args(&fn_sig); |
337 | let ret = fn_sig.output().skip_binder().to_string(); | |
338 | format!(" for the closure `fn({}) -> {}`", args, ret) | |
339 | } | |
f9f354fc | 340 | (Some(ty), _) if is_named_and_not_impl_trait(ty) => { |
e1599b0c XL |
341 | let ty = ty_to_string(ty); |
342 | format!(" for `{}`", ty) | |
343 | } | |
344 | _ => String::new(), | |
345 | }; | |
041b39d2 | 346 | |
dc9dc135 XL |
347 | // When `name` corresponds to a type argument, show the path of the full type we're |
348 | // trying to infer. In the following example, `ty_msg` contains | |
349 | // " in `std::result::Result<i32, E>`": | |
350 | // ``` | |
351 | // error[E0282]: type annotations needed for `std::result::Result<i32, E>` | |
352 | // --> file.rs:L:CC | |
353 | // | | |
354 | // L | let b = Ok(4); | |
355 | // | - ^^ cannot infer type for `E` in `std::result::Result<i32, E>` | |
356 | // | | | |
357 | // | consider giving `b` the explicit type `std::result::Result<i32, E>`, where | |
358 | // | the type parameter `E` is specified | |
359 | // ``` | |
60c5eb7d XL |
360 | let error_code = error_code.into(); |
361 | let mut err = self.tcx.sess.struct_span_err_with_code( | |
e1599b0c | 362 | err_span, |
60c5eb7d XL |
363 | &format!("type annotations needed{}", ty_msg), |
364 | error_code, | |
e1599b0c XL |
365 | ); |
366 | ||
ba9703b0 XL |
367 | let suffix = match local_visitor.found_node_ty { |
368 | Some(ty::TyS { kind: ty::Closure(_, substs), .. }) => { | |
369 | let fn_sig = substs.as_closure().sig(); | |
e1599b0c XL |
370 | let ret = fn_sig.output().skip_binder().to_string(); |
371 | ||
ba9703b0 XL |
372 | let closure_decl_and_body_id = |
373 | local_visitor.found_closure.and_then(|closure| match &closure.kind { | |
374 | ExprKind::Closure(_, decl, body_id, ..) => Some((decl, *body_id)), | |
375 | _ => None, | |
376 | }); | |
377 | ||
378 | if let Some((decl, body_id)) = closure_decl_and_body_id { | |
379 | closure_return_type_suggestion( | |
380 | span, | |
381 | &mut err, | |
382 | &decl.output, | |
383 | self.tcx.hir().body(body_id), | |
384 | &descr, | |
385 | &name, | |
386 | &ret, | |
387 | parent_name, | |
388 | parent_descr, | |
389 | ); | |
390 | // We don't want to give the other suggestions when the problem is the | |
391 | // closure return type. | |
392 | return err; | |
e1599b0c XL |
393 | } |
394 | ||
395 | // This shouldn't be reachable, but just in case we leave a reasonable fallback. | |
396 | let args = closure_args(&fn_sig); | |
397 | // This suggestion is incomplete, as the user will get further type inference | |
398 | // errors due to the `_` placeholders and the introduction of `Box`, but it does | |
399 | // nudge them in the right direction. | |
400 | format!("a boxed closure type like `Box<dyn Fn({}) -> {}>`", args, ret) | |
401 | } | |
402 | Some(ty) if is_named_and_not_impl_trait(ty) && name == "_" => { | |
dc9dc135 | 403 | let ty = ty_to_string(ty); |
e1599b0c | 404 | format!("the explicit type `{}`, with the type parameters specified", ty) |
dc9dc135 | 405 | } |
e1599b0c | 406 | Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != name => { |
dc9dc135 | 407 | let ty = ty_to_string(ty); |
e1599b0c XL |
408 | format!( |
409 | "the explicit type `{}`, where the type parameter `{}` is specified", | |
dfeec247 | 410 | ty, name, |
e1599b0c | 411 | ) |
dc9dc135 | 412 | } |
e1599b0c | 413 | _ => "a type".to_string(), |
dc9dc135 | 414 | }; |
dc9dc135 | 415 | |
f9f354fc XL |
416 | if let Some(e) = local_visitor.found_exact_method_call { |
417 | if let ExprKind::MethodCall(segment, ..) = &e.kind { | |
418 | // Suggest specifying type params or point out the return type of the call: | |
419 | // | |
420 | // error[E0282]: type annotations needed | |
421 | // --> $DIR/type-annotations-needed-expr.rs:2:39 | |
422 | // | | |
423 | // LL | let _ = x.into_iter().sum() as f64; | |
424 | // | ^^^ | |
425 | // | | | |
426 | // | cannot infer type for `S` | |
427 | // | help: consider specifying the type argument in | |
428 | // | the method call: `sum::<S>` | |
429 | // | | |
430 | // = note: type must be known at this point | |
431 | // | |
432 | // or | |
433 | // | |
434 | // error[E0282]: type annotations needed | |
435 | // --> $DIR/issue-65611.rs:59:20 | |
436 | // | | |
437 | // LL | let x = buffer.last().unwrap().0.clone(); | |
438 | // | -------^^^^-- | |
439 | // | | | | |
440 | // | | cannot infer type for `T` | |
441 | // | this method call resolves to `std::option::Option<&T>` | |
442 | // | | |
443 | // = note: type must be known at this point | |
444 | self.annotate_method_call(segment, e, &mut err); | |
445 | } | |
446 | } else if let Some(pattern) = local_visitor.found_arg_pattern { | |
041b39d2 XL |
447 | // We don't want to show the default label for closures. |
448 | // | |
449 | // So, before clearing, the output would look something like this: | |
450 | // ``` | |
451 | // let x = |_| { }; | |
452 | // - ^^^^ cannot infer type for `[_; 0]` | |
453 | // | | |
454 | // consider giving this closure parameter a type | |
455 | // ``` | |
456 | // | |
457 | // After clearing, it looks something like this: | |
458 | // ``` | |
459 | // let x = |_| { }; | |
dc9dc135 XL |
460 | // ^ consider giving this closure parameter the type `[_; 0]` |
461 | // with the type parameter `_` specified | |
041b39d2 | 462 | // ``` |
e1599b0c | 463 | err.span_label( |
dc9dc135 XL |
464 | pattern.span, |
465 | format!("consider giving this closure parameter {}", suffix), | |
e1599b0c | 466 | ); |
ff7c6d11 | 467 | } else if let Some(pattern) = local_visitor.found_local_pattern { |
e1599b0c | 468 | let msg = if let Some(simple_ident) = pattern.simple_ident() { |
416331ca | 469 | match pattern.span.desugaring_kind() { |
dfeec247 | 470 | None => format!("consider giving `{}` {}", simple_ident, suffix), |
f035d41b | 471 | Some(DesugaringKind::ForLoop(_)) => { |
e1599b0c XL |
472 | "the element type for this iterator is not specified".to_string() |
473 | } | |
474 | _ => format!("this needs {}", suffix), | |
8faf50e0 | 475 | } |
041b39d2 | 476 | } else { |
e1599b0c XL |
477 | format!("consider giving this pattern {}", suffix) |
478 | }; | |
479 | err.span_label(pattern.span, msg); | |
60c5eb7d XL |
480 | } else if let Some(e) = local_visitor.found_method_call { |
481 | if let ExprKind::MethodCall(segment, ..) = &e.kind { | |
74b04a01 | 482 | // Suggest specifying type params or point out the return type of the call: |
60c5eb7d XL |
483 | // |
484 | // error[E0282]: type annotations needed | |
485 | // --> $DIR/type-annotations-needed-expr.rs:2:39 | |
486 | // | | |
487 | // LL | let _ = x.into_iter().sum() as f64; | |
488 | // | ^^^ | |
489 | // | | | |
490 | // | cannot infer type for `S` | |
491 | // | help: consider specifying the type argument in | |
492 | // | the method call: `sum::<S>` | |
493 | // | | |
494 | // = note: type must be known at this point | |
495 | // | |
496 | // or | |
497 | // | |
498 | // error[E0282]: type annotations needed | |
499 | // --> $DIR/issue-65611.rs:59:20 | |
500 | // | | |
501 | // LL | let x = buffer.last().unwrap().0.clone(); | |
502 | // | -------^^^^-- | |
503 | // | | | | |
504 | // | | cannot infer type for `T` | |
505 | // | this method call resolves to `std::option::Option<&T>` | |
506 | // | | |
507 | // = note: type must be known at this point | |
508 | self.annotate_method_call(segment, e, &mut err); | |
509 | } | |
e1599b0c XL |
510 | } |
511 | // Instead of the following: | |
512 | // error[E0282]: type annotations needed | |
513 | // --> file2.rs:3:15 | |
514 | // | | |
515 | // 3 | let _ = x.sum() as f64; | |
516 | // | --^^^--------- cannot infer type for `S` | |
517 | // | | |
518 | // = note: type must be known at this point | |
519 | // We want: | |
520 | // error[E0282]: type annotations needed | |
521 | // --> file2.rs:3:15 | |
522 | // | | |
523 | // 3 | let _ = x.sum() as f64; | |
524 | // | ^^^ cannot infer type for `S` | |
525 | // | | |
526 | // = note: type must be known at this point | |
60c5eb7d | 527 | let span = name_sp.unwrap_or(err_span); |
dfeec247 XL |
528 | if !err |
529 | .span | |
530 | .span_labels() | |
531 | .iter() | |
532 | .any(|span_label| span_label.label.is_some() && span_label.span == span) | |
533 | && local_visitor.found_arg_pattern.is_none() | |
534 | { | |
535 | // Avoid multiple labels pointing at `span`. | |
536 | err.span_label( | |
537 | span, | |
538 | InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr), | |
539 | ); | |
041b39d2 XL |
540 | } |
541 | ||
94b46f34 | 542 | err |
041b39d2 | 543 | } |
48663c56 | 544 | |
f9f354fc XL |
545 | // FIXME(const_generics): We should either try and merge this with `need_type_info_err` |
546 | // or improve the errors created here. | |
547 | // | |
548 | // Unlike for type inference variables, we don't yet store the origin of const inference variables. | |
549 | // This is needed for to get a more relevant error span. | |
550 | pub fn need_type_info_err_const( | |
551 | &self, | |
552 | body_id: Option<hir::BodyId>, | |
553 | span: Span, | |
554 | ct: &'tcx ty::Const<'tcx>, | |
555 | error_code: TypeAnnotationNeeded, | |
556 | ) -> DiagnosticBuilder<'tcx> { | |
557 | let mut local_visitor = FindHirNodeVisitor::new(&self, ct.into(), span); | |
558 | if let Some(body_id) = body_id { | |
559 | let expr = self.tcx.hir().expect_expr(body_id.hir_id); | |
560 | local_visitor.visit_expr(expr); | |
561 | } | |
562 | ||
563 | let error_code = error_code.into(); | |
564 | let mut err = self.tcx.sess.struct_span_err_with_code( | |
565 | local_visitor.target_span, | |
f035d41b | 566 | "type annotations needed", |
f9f354fc XL |
567 | error_code, |
568 | ); | |
569 | ||
570 | err.note("unable to infer the value of a const parameter"); | |
571 | ||
572 | err | |
573 | } | |
574 | ||
60c5eb7d XL |
575 | /// If the `FnSig` for the method call can be found and type arguments are identified as |
576 | /// needed, suggest annotating the call, otherwise point out the resulting type of the call. | |
577 | fn annotate_method_call( | |
578 | &self, | |
dfeec247 XL |
579 | segment: &hir::PathSegment<'_>, |
580 | e: &Expr<'_>, | |
60c5eb7d XL |
581 | err: &mut DiagnosticBuilder<'_>, |
582 | ) { | |
ba9703b0 | 583 | if let (Some(tables), None) = (self.in_progress_tables, &segment.args) { |
60c5eb7d | 584 | let borrow = tables.borrow(); |
ba9703b0 | 585 | if let Some((DefKind::AssocFn, did)) = borrow.type_dependent_def(e.hir_id) { |
60c5eb7d XL |
586 | let generics = self.tcx.generics_of(did); |
587 | if !generics.params.is_empty() { | |
ba9703b0 XL |
588 | err.span_suggestion_verbose( |
589 | segment.ident.span.shrink_to_hi(), | |
60c5eb7d XL |
590 | &format!( |
591 | "consider specifying the type argument{} in the method call", | |
ba9703b0 | 592 | pluralize!(generics.params.len()), |
dfeec247 XL |
593 | ), |
594 | format!( | |
ba9703b0 | 595 | "::<{}>", |
dfeec247 XL |
596 | generics |
597 | .params | |
598 | .iter() | |
599 | .map(|p| p.name.to_string()) | |
600 | .collect::<Vec<String>>() | |
601 | .join(", ") | |
60c5eb7d | 602 | ), |
60c5eb7d XL |
603 | Applicability::HasPlaceholders, |
604 | ); | |
605 | } else { | |
606 | let sig = self.tcx.fn_sig(did); | |
607 | let bound_output = sig.output(); | |
608 | let output = bound_output.skip_binder(); | |
609 | err.span_label(e.span, &format!("this method call resolves to `{:?}`", output)); | |
610 | let kind = &output.kind; | |
f9f354fc | 611 | if let ty::Projection(proj) = kind { |
60c5eb7d XL |
612 | if let Some(span) = self.tcx.hir().span_if_local(proj.item_def_id) { |
613 | err.span_label(span, &format!("`{:?}` defined here", output)); | |
614 | } | |
615 | } | |
616 | } | |
617 | } | |
618 | } | |
619 | } | |
620 | ||
48663c56 XL |
621 | pub fn need_type_info_err_in_generator( |
622 | &self, | |
dc9dc135 | 623 | kind: hir::GeneratorKind, |
48663c56 | 624 | span: Span, |
dc9dc135 XL |
625 | ty: Ty<'tcx>, |
626 | ) -> DiagnosticBuilder<'tcx> { | |
627 | let ty = self.resolve_vars_if_possible(&ty); | |
dfeec247 XL |
628 | let (name, _, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None); |
629 | ||
dc9dc135 | 630 | let mut err = struct_span_err!( |
dfeec247 XL |
631 | self.tcx.sess, |
632 | span, | |
633 | E0698, | |
634 | "type inside {} must be known in this context", | |
635 | kind, | |
dc9dc135 | 636 | ); |
dfeec247 | 637 | err.span_label(span, InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr)); |
48663c56 XL |
638 | err |
639 | } | |
640 | ||
dfeec247 XL |
641 | fn missing_type_msg( |
642 | type_name: &str, | |
643 | descr: &str, | |
644 | parent_name: Option<String>, | |
645 | parent_descr: Option<&str>, | |
646 | ) -> Cow<'static, str> { | |
48663c56 | 647 | if type_name == "_" { |
60c5eb7d | 648 | "cannot infer type".into() |
48663c56 | 649 | } else { |
dfeec247 XL |
650 | let parent_desc = if let Some(parent_name) = parent_name { |
651 | let parent_type_descr = if let Some(parent_descr) = parent_descr { | |
652 | format!(" the {}", parent_descr) | |
653 | } else { | |
654 | "".into() | |
655 | }; | |
656 | ||
657 | format!(" declared on{} `{}`", parent_type_descr, parent_name) | |
658 | } else { | |
659 | "".to_string() | |
660 | }; | |
661 | ||
662 | format!("cannot infer type for {} `{}`{}", descr, type_name, parent_desc).into() | |
48663c56 XL |
663 | } |
664 | } | |
041b39d2 | 665 | } |