]>
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}; | |
5869c6ff | 6 | use rustc_hir::def_id::DefId; |
dfeec247 | 7 | use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; |
74b04a01 | 8 | use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat}; |
ba9703b0 | 9 | use rustc_middle::hir::map::Map; |
1b1a35ee | 10 | use rustc_middle::infer::unify_key::ConstVariableOriginKind; |
ba9703b0 XL |
11 | use rustc_middle::ty::print::Print; |
12 | use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; | |
5869c6ff | 13 | use rustc_middle::ty::{self, DefIdTree, InferConst, Ty, TyCtxt}; |
dfeec247 XL |
14 | use rustc_span::source_map::DesugaringKind; |
15 | use rustc_span::symbol::kw; | |
16 | use rustc_span::Span; | |
60c5eb7d XL |
17 | use std::borrow::Cow; |
18 | ||
ba9703b0 | 19 | struct 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 | 32 | impl<'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 | 84 | impl<'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. | |
159 | enum 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 | ||
165 | impl 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. |
216 | fn 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. | |
241 | fn 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 | 251 | pub 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 |
268 | impl 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. |
279 | pub 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. | |
287 | pub struct InferenceDiagnosticsParentData { | |
288 | pub prefix: &'static str, | |
289 | pub name: String, | |
cdc7bbd5 | 290 | pub def_id: DefId, |
5869c6ff XL |
291 | } |
292 | ||
293 | pub enum UnderspecifiedArgKind { | |
294 | Type { prefix: Cow<'static, str> }, | |
295 | Const { is_parameter: bool }, | |
296 | } | |
297 | ||
298 | impl 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 | ||
322 | impl 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 | ||
337 | impl 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 | 347 | impl<'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 | } |