]>
Commit | Line | Data |
---|---|---|
f2b60f7d | 1 | use crate::errors::{ |
781aab86 | 2 | AmbiguousImpl, AmbiguousReturn, AnnotationRequired, InferenceBadError, |
f2b60f7d FG |
3 | SourceKindMultiSuggestion, SourceKindSubdiag, |
4 | }; | |
2b03887a | 5 | use crate::infer::error_reporting::TypeErrCtxt; |
e8be2606 | 6 | use crate::infer::type_variable::TypeVariableOrigin; |
923072b8 | 7 | use crate::infer::InferCtxt; |
c620b35d | 8 | use rustc_errors::{codes::*, Diag, IntoDiagArg}; |
dfeec247 | 9 | use rustc_hir as hir; |
923072b8 FG |
10 | use rustc_hir::def::Res; |
11 | use rustc_hir::def::{CtorOf, DefKind, Namespace}; | |
353b0b11 | 12 | use rustc_hir::def_id::{DefId, LocalDefId}; |
5099ac24 | 13 | use rustc_hir::intravisit::{self, Visitor}; |
e8be2606 | 14 | use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, LetStmt, LocalSource}; |
5099ac24 | 15 | use rustc_middle::hir::nested_filter; |
e8be2606 | 16 | use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableValue}; |
487cf647 | 17 | use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; |
923072b8 | 18 | use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer}; |
e8be2606 FG |
19 | use rustc_middle::ty::{ |
20 | self, GenericArg, GenericArgKind, GenericArgsRef, InferConst, IsSuggestable, Ty, TyCtxt, | |
21 | TypeFoldable, TypeFolder, TypeSuperFoldable, TypeckResults, | |
22 | }; | |
23 | use rustc_span::symbol::{sym, Ident}; | |
24 | use rustc_span::{BytePos, Span, DUMMY_SP}; | |
60c5eb7d | 25 | use std::borrow::Cow; |
923072b8 | 26 | use std::iter; |
e8be2606 | 27 | use std::path::PathBuf; |
041b39d2 | 28 | |
60c5eb7d | 29 | pub enum TypeAnnotationNeeded { |
f9f354fc | 30 | /// ```compile_fail,E0282 |
ed00b5ec | 31 | /// let x; |
f9f354fc | 32 | /// ``` |
60c5eb7d | 33 | E0282, |
f9f354fc | 34 | /// An implementation cannot be chosen unambiguously because of lack of information. |
49aad941 | 35 | /// ```compile_fail,E0790 |
f9f354fc XL |
36 | /// let _ = Default::default(); |
37 | /// ``` | |
60c5eb7d | 38 | E0283, |
f9f354fc XL |
39 | /// ```compile_fail,E0284 |
40 | /// let mut d: u64 = 2; | |
41 | /// d = d % 1u32.into(); | |
42 | /// ``` | |
60c5eb7d XL |
43 | E0284, |
44 | } | |
45 | ||
c0240ec0 FG |
46 | impl Into<ErrCode> for TypeAnnotationNeeded { |
47 | fn into(self) -> ErrCode { | |
dfeec247 | 48 | match self { |
c0240ec0 FG |
49 | Self::E0282 => E0282, |
50 | Self::E0283 => E0283, | |
51 | Self::E0284 => E0284, | |
dfeec247 | 52 | } |
60c5eb7d XL |
53 | } |
54 | } | |
55 | ||
1b1a35ee XL |
56 | /// Information about a constant or a type containing inference variables. |
57 | pub struct InferenceDiagnosticsData { | |
58 | pub name: String, | |
59 | pub span: Option<Span>, | |
5869c6ff XL |
60 | pub kind: UnderspecifiedArgKind, |
61 | pub parent: Option<InferenceDiagnosticsParentData>, | |
62 | } | |
63 | ||
64 | /// Data on the parent definition where a generic argument was declared. | |
65 | pub struct InferenceDiagnosticsParentData { | |
923072b8 FG |
66 | prefix: &'static str, |
67 | name: String, | |
5869c6ff XL |
68 | } |
69 | ||
f2b60f7d | 70 | #[derive(Clone)] |
5869c6ff XL |
71 | pub enum UnderspecifiedArgKind { |
72 | Type { prefix: Cow<'static, str> }, | |
73 | Const { is_parameter: bool }, | |
74 | } | |
75 | ||
76 | impl InferenceDiagnosticsData { | |
f2b60f7d FG |
77 | fn can_add_more_info(&self) -> bool { |
78 | !(self.name == "_" && matches!(self.kind, UnderspecifiedArgKind::Type { .. })) | |
5869c6ff | 79 | } |
923072b8 | 80 | |
f2b60f7d | 81 | fn where_x_is_kind(&self, in_type: Ty<'_>) -> &'static str { |
9c376795 FG |
82 | if in_type.is_ty_or_numeric_infer() { |
83 | "" | |
923072b8 FG |
84 | } else if self.name == "_" { |
85 | // FIXME: Consider specializing this message if there is a single `_` | |
86 | // in the type. | |
f2b60f7d | 87 | "underscore" |
923072b8 | 88 | } else { |
f2b60f7d FG |
89 | "has_name" |
90 | } | |
91 | } | |
92 | ||
93 | /// Generate a label for a generic argument which can't be inferred. When not | |
94 | /// much is known about the argument, `use_diag` may be used to describe the | |
95 | /// labeled value. | |
96 | fn make_bad_error(&self, span: Span) -> InferenceBadError<'_> { | |
97 | let has_parent = self.parent.is_some(); | |
98 | let bad_kind = if self.can_add_more_info() { "more_info" } else { "other" }; | |
99 | let (parent_prefix, parent_name) = self | |
100 | .parent | |
101 | .as_ref() | |
102 | .map(|parent| (parent.prefix, parent.name.clone())) | |
103 | .unwrap_or_default(); | |
104 | InferenceBadError { | |
105 | span, | |
106 | bad_kind, | |
107 | prefix_kind: self.kind.clone(), | |
108 | prefix: self.kind.try_get_prefix().unwrap_or_default(), | |
109 | name: self.name.clone(), | |
110 | has_parent, | |
111 | parent_prefix, | |
112 | parent_name, | |
923072b8 FG |
113 | } |
114 | } | |
5869c6ff XL |
115 | } |
116 | ||
117 | impl InferenceDiagnosticsParentData { | |
923072b8 FG |
118 | fn for_parent_def_id( |
119 | tcx: TyCtxt<'_>, | |
120 | parent_def_id: DefId, | |
121 | ) -> Option<InferenceDiagnosticsParentData> { | |
5869c6ff XL |
122 | let parent_name = |
123 | tcx.def_key(parent_def_id).disambiguated_data.data.get_opt_name()?.to_string(); | |
124 | ||
125 | Some(InferenceDiagnosticsParentData { | |
9ffffee4 | 126 | prefix: tcx.def_descr(parent_def_id), |
5869c6ff XL |
127 | name: parent_name, |
128 | }) | |
129 | } | |
923072b8 FG |
130 | |
131 | fn for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<InferenceDiagnosticsParentData> { | |
132 | Self::for_parent_def_id(tcx, tcx.parent(def_id)) | |
133 | } | |
f2b60f7d | 134 | } |
923072b8 | 135 | |
c620b35d FG |
136 | impl IntoDiagArg for UnderspecifiedArgKind { |
137 | fn into_diag_arg(self) -> rustc_errors::DiagArgValue { | |
f2b60f7d FG |
138 | let kind = match self { |
139 | Self::Type { .. } => "type", | |
140 | Self::Const { is_parameter: true } => "const_with_param", | |
141 | Self::Const { is_parameter: false } => "const", | |
142 | }; | |
c620b35d | 143 | rustc_errors::DiagArgValue::Str(kind.into()) |
923072b8 | 144 | } |
5869c6ff XL |
145 | } |
146 | ||
147 | impl UnderspecifiedArgKind { | |
f2b60f7d | 148 | fn try_get_prefix(&self) -> Option<&str> { |
5869c6ff | 149 | match self { |
f2b60f7d FG |
150 | Self::Type { prefix } => Some(prefix.as_ref()), |
151 | Self::Const { .. } => None, | |
5869c6ff XL |
152 | } |
153 | } | |
1b1a35ee XL |
154 | } |
155 | ||
e8be2606 FG |
156 | struct ClosureEraser<'tcx> { |
157 | tcx: TyCtxt<'tcx>, | |
158 | } | |
159 | ||
160 | impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ClosureEraser<'tcx> { | |
161 | fn interner(&self) -> TyCtxt<'tcx> { | |
162 | self.tcx | |
163 | } | |
164 | ||
165 | fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { | |
166 | match ty.kind() { | |
167 | ty::Closure(_, args) => { | |
168 | let closure_sig = args.as_closure().sig(); | |
169 | Ty::new_fn_ptr( | |
170 | self.tcx, | |
171 | self.tcx.signature_unclosure(closure_sig, hir::Unsafety::Normal), | |
172 | ) | |
173 | } | |
174 | _ => ty.super_fold_with(self), | |
175 | } | |
176 | } | |
177 | } | |
178 | ||
2b03887a | 179 | fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinter<'a, 'tcx> { |
923072b8 FG |
180 | let mut printer = FmtPrinter::new(infcx.tcx, ns); |
181 | let ty_getter = move |ty_vid| { | |
182 | if infcx.probe_ty_var(ty_vid).is_ok() { | |
183 | warn!("resolved ty var in error message"); | |
184 | } | |
9ffffee4 FG |
185 | |
186 | let mut infcx_inner = infcx.inner.borrow_mut(); | |
187 | let ty_vars = infcx_inner.type_variables(); | |
188 | let var_origin = ty_vars.var_origin(ty_vid); | |
e8be2606 FG |
189 | if let Some(def_id) = var_origin.param_def_id |
190 | // The `Self` param of a trait has the def-id of the trait, | |
191 | // since it's a synthetic parameter. | |
192 | && infcx.tcx.def_kind(def_id) == DefKind::TyParam | |
193 | && let name = infcx.tcx.item_name(def_id) | |
ed00b5ec | 194 | && !var_origin.span.from_expansion() |
923072b8 | 195 | { |
add651ee FG |
196 | let generics = infcx.tcx.generics_of(infcx.tcx.parent(def_id)); |
197 | let idx = generics.param_def_id_to_index(infcx.tcx, def_id).unwrap(); | |
198 | let generic_param_def = generics.param_at(idx as usize, infcx.tcx); | |
ed00b5ec | 199 | if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param_def.kind { |
add651ee FG |
200 | None |
201 | } else { | |
202 | Some(name) | |
203 | } | |
923072b8 FG |
204 | } else { |
205 | None | |
206 | } | |
207 | }; | |
208 | printer.ty_infer_name_resolver = Some(Box::new(ty_getter)); | |
c0240ec0 FG |
209 | let const_getter = move |ct_vid| match infcx |
210 | .inner | |
211 | .borrow_mut() | |
212 | .const_unification_table() | |
213 | .probe_value(ct_vid) | |
214 | { | |
215 | ConstVariableValue::Known { value: _ } => { | |
923072b8 | 216 | warn!("resolved const var in error message"); |
923072b8 FG |
217 | None |
218 | } | |
c0240ec0 | 219 | ConstVariableValue::Unknown { origin, universe: _ } => { |
e8be2606 FG |
220 | if let Some(def_id) = origin.param_def_id { |
221 | Some(infcx.tcx.item_name(def_id)) | |
c0240ec0 FG |
222 | } else { |
223 | None | |
224 | } | |
225 | } | |
923072b8 FG |
226 | }; |
227 | printer.const_infer_name_resolver = Some(Box::new(const_getter)); | |
228 | printer | |
229 | } | |
230 | ||
9c376795 FG |
231 | fn ty_to_string<'tcx>( |
232 | infcx: &InferCtxt<'tcx>, | |
233 | ty: Ty<'tcx>, | |
234 | called_method_def_id: Option<DefId>, | |
235 | ) -> String { | |
ed00b5ec | 236 | let mut printer = fmt_printer(infcx, Namespace::TypeNS); |
923072b8 | 237 | let ty = infcx.resolve_vars_if_possible(ty); |
e8be2606 FG |
238 | // We use `fn` ptr syntax for closures, but this only works when the closure |
239 | // does not capture anything. | |
240 | let ty = ty.fold_with(&mut ClosureEraser { tcx: infcx.tcx }); | |
241 | ||
9c376795 | 242 | match (ty.kind(), called_method_def_id) { |
923072b8 FG |
243 | // We don't want the regular output for `fn`s because it includes its path in |
244 | // invalid pseudo-syntax, we want the `fn`-pointer output instead. | |
ed00b5ec FG |
245 | (ty::FnDef(..), _) => { |
246 | ty.fn_sig(infcx.tcx).print(&mut printer).unwrap(); | |
247 | printer.into_buffer() | |
248 | } | |
9c376795 FG |
249 | (_, Some(def_id)) |
250 | if ty.is_ty_or_numeric_infer() | |
251 | && infcx.tcx.get_diagnostic_item(sym::iterator_collect_fn) == Some(def_id) => | |
252 | { | |
253 | "Vec<_>".to_string() | |
254 | } | |
255 | _ if ty.is_ty_or_numeric_infer() => "/* Type */".to_string(), | |
ed00b5ec FG |
256 | _ => { |
257 | ty.print(&mut printer).unwrap(); | |
258 | printer.into_buffer() | |
259 | } | |
923072b8 FG |
260 | } |
261 | } | |
262 | ||
263 | /// We don't want to directly use `ty_to_string` for closures as their type isn't really | |
f2b60f7d | 264 | /// something users are familiar with. Directly printing the `fn_sig` of closures also |
923072b8 | 265 | /// doesn't work as they actually use the "rust-call" API. |
2b03887a | 266 | fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String { |
4b012472 FG |
267 | let ty::Closure(_, args) = ty.kind() else { |
268 | bug!("cannot convert non-closure to fn str in `closure_as_fn_str`") | |
269 | }; | |
add651ee | 270 | let fn_sig = args.as_closure().sig(); |
923072b8 FG |
271 | let args = fn_sig |
272 | .inputs() | |
273 | .skip_binder() | |
274 | .iter() | |
275 | .next() | |
276 | .map(|args| { | |
277 | args.tuple_fields() | |
278 | .iter() | |
9c376795 | 279 | .map(|arg| ty_to_string(infcx, arg, None)) |
923072b8 FG |
280 | .collect::<Vec<_>>() |
281 | .join(", ") | |
282 | }) | |
283 | .unwrap_or_default(); | |
284 | let ret = if fn_sig.output().skip_binder().is_unit() { | |
285 | String::new() | |
286 | } else { | |
9c376795 | 287 | format!(" -> {}", ty_to_string(infcx, fn_sig.output().skip_binder(), None)) |
923072b8 | 288 | }; |
add651ee | 289 | format!("fn({args}){ret}") |
923072b8 FG |
290 | } |
291 | ||
2b03887a | 292 | impl<'tcx> InferCtxt<'tcx> { |
1b1a35ee XL |
293 | /// Extracts data used by diagnostic for either types or constants |
294 | /// which were stuck during inference. | |
295 | pub fn extract_inference_diagnostics_data( | |
532ac7d7 | 296 | &self, |
1b1a35ee | 297 | arg: GenericArg<'tcx>, |
5099ac24 | 298 | highlight: Option<ty::print::RegionHighlightMode<'tcx>>, |
1b1a35ee XL |
299 | ) -> InferenceDiagnosticsData { |
300 | match arg.unpack() { | |
301 | GenericArgKind::Type(ty) => { | |
302 | if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() { | |
303 | let mut inner = self.inner.borrow_mut(); | |
304 | let ty_vars = &inner.type_variables(); | |
305 | let var_origin = ty_vars.var_origin(ty_vid); | |
e8be2606 FG |
306 | if let Some(def_id) = var_origin.param_def_id |
307 | // The `Self` param of a trait has the def-id of the trait, | |
308 | // since it's a synthetic parameter. | |
309 | && self.tcx.def_kind(def_id) == DefKind::TyParam | |
310 | && !var_origin.span.from_expansion() | |
1b1a35ee | 311 | { |
e8be2606 FG |
312 | return InferenceDiagnosticsData { |
313 | name: self.tcx.item_name(def_id).to_string(), | |
314 | span: Some(var_origin.span), | |
315 | kind: UnderspecifiedArgKind::Type { prefix: "type parameter".into() }, | |
316 | parent: InferenceDiagnosticsParentData::for_def_id(self.tcx, def_id), | |
317 | }; | |
1b1a35ee XL |
318 | } |
319 | } | |
dfeec247 | 320 | |
5e7ed085 | 321 | let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS); |
1b1a35ee XL |
322 | if let Some(highlight) = highlight { |
323 | printer.region_highlight_mode = highlight; | |
324 | } | |
ed00b5ec | 325 | ty.print(&mut printer).unwrap(); |
1b1a35ee | 326 | InferenceDiagnosticsData { |
ed00b5ec | 327 | name: printer.into_buffer(), |
1b1a35ee | 328 | span: None, |
6a06907d | 329 | kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string(self.tcx) }, |
5869c6ff | 330 | parent: None, |
60c5eb7d | 331 | } |
041b39d2 | 332 | } |
1b1a35ee | 333 | GenericArgKind::Const(ct) => { |
923072b8 FG |
334 | if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.kind() { |
335 | let origin = | |
c0240ec0 FG |
336 | match self.inner.borrow_mut().const_unification_table().probe_value(vid) { |
337 | ConstVariableValue::Known { value } => { | |
338 | bug!("resolved infer var: {vid:?} {value}") | |
339 | } | |
340 | ConstVariableValue::Unknown { origin, universe: _ } => origin, | |
341 | }; | |
e8be2606 | 342 | if let Some(def_id) = origin.param_def_id { |
923072b8 | 343 | return InferenceDiagnosticsData { |
e8be2606 | 344 | name: self.tcx.item_name(def_id).to_string(), |
1b1a35ee | 345 | span: Some(origin.span), |
923072b8 FG |
346 | kind: UnderspecifiedArgKind::Const { is_parameter: true }, |
347 | parent: InferenceDiagnosticsParentData::for_def_id(self.tcx, def_id), | |
348 | }; | |
1b1a35ee | 349 | } |
923072b8 FG |
350 | |
351 | debug_assert!(!origin.span.is_dummy()); | |
352 | let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::ValueNS); | |
353 | if let Some(highlight) = highlight { | |
354 | printer.region_highlight_mode = highlight; | |
1b1a35ee | 355 | } |
ed00b5ec | 356 | ct.print(&mut printer).unwrap(); |
923072b8 | 357 | InferenceDiagnosticsData { |
ed00b5ec | 358 | name: printer.into_buffer(), |
923072b8 FG |
359 | span: Some(origin.span), |
360 | kind: UnderspecifiedArgKind::Const { is_parameter: false }, | |
361 | parent: None, | |
362 | } | |
363 | } else { | |
364 | // If we end up here the `FindInferSourceVisitor` | |
365 | // won't work, as its expected argument isn't an inference variable. | |
366 | // | |
367 | // FIXME: Ideally we should look into the generic constant | |
368 | // to figure out which inference var is actually unresolved so that | |
369 | // this path is unreachable. | |
370 | let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::ValueNS); | |
371 | if let Some(highlight) = highlight { | |
372 | printer.region_highlight_mode = highlight; | |
373 | } | |
ed00b5ec | 374 | ct.print(&mut printer).unwrap(); |
923072b8 | 375 | InferenceDiagnosticsData { |
ed00b5ec | 376 | name: printer.into_buffer(), |
923072b8 FG |
377 | span: None, |
378 | kind: UnderspecifiedArgKind::Const { is_parameter: false }, | |
379 | parent: None, | |
1b1a35ee | 380 | } |
1b1a35ee XL |
381 | } |
382 | } | |
383 | GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), | |
532ac7d7 | 384 | } |
041b39d2 XL |
385 | } |
386 | ||
2b03887a | 387 | /// Used as a fallback in [TypeErrCtxt::emit_inference_failure_err] |
923072b8 FG |
388 | /// in case we weren't able to get a better error. |
389 | fn bad_inference_failure_err( | |
390 | &self, | |
391 | span: Span, | |
392 | arg_data: InferenceDiagnosticsData, | |
393 | error_code: TypeAnnotationNeeded, | |
c620b35d | 394 | ) -> Diag<'tcx> { |
f2b60f7d FG |
395 | let source_kind = "other"; |
396 | let source_name = ""; | |
397 | let failure_span = None; | |
398 | let infer_subdiags = Vec::new(); | |
399 | let multi_suggestions = Vec::new(); | |
400 | let bad_label = Some(arg_data.make_bad_error(span)); | |
401 | match error_code { | |
c0240ec0 | 402 | TypeAnnotationNeeded::E0282 => self.dcx().create_err(AnnotationRequired { |
f2b60f7d FG |
403 | span, |
404 | source_kind, | |
405 | source_name, | |
406 | failure_span, | |
407 | infer_subdiags, | |
408 | multi_suggestions, | |
409 | bad_label, | |
e8be2606 FG |
410 | was_written: None, |
411 | path: Default::default(), | |
c0240ec0 FG |
412 | }), |
413 | TypeAnnotationNeeded::E0283 => self.dcx().create_err(AmbiguousImpl { | |
f2b60f7d FG |
414 | span, |
415 | source_kind, | |
416 | source_name, | |
417 | failure_span, | |
418 | infer_subdiags, | |
419 | multi_suggestions, | |
420 | bad_label, | |
e8be2606 FG |
421 | was_written: None, |
422 | path: Default::default(), | |
c0240ec0 FG |
423 | }), |
424 | TypeAnnotationNeeded::E0284 => self.dcx().create_err(AmbiguousReturn { | |
f2b60f7d FG |
425 | span, |
426 | source_kind, | |
427 | source_name, | |
428 | failure_span, | |
429 | infer_subdiags, | |
430 | multi_suggestions, | |
431 | bad_label, | |
e8be2606 FG |
432 | was_written: None, |
433 | path: Default::default(), | |
c0240ec0 | 434 | }), |
f2b60f7d | 435 | } |
923072b8 | 436 | } |
2b03887a | 437 | } |
923072b8 | 438 | |
2b03887a | 439 | impl<'tcx> TypeErrCtxt<'_, 'tcx> { |
9c376795 | 440 | #[instrument(level = "debug", skip(self, error_code))] |
1b1a35ee | 441 | pub fn emit_inference_failure_err( |
48663c56 | 442 | &self, |
353b0b11 | 443 | body_def_id: LocalDefId, |
064997fb | 444 | failure_span: Span, |
1b1a35ee | 445 | arg: GenericArg<'tcx>, |
60c5eb7d | 446 | error_code: TypeAnnotationNeeded, |
064997fb | 447 | should_label_span: bool, |
c620b35d | 448 | ) -> Diag<'tcx> { |
fc512014 | 449 | let arg = self.resolve_vars_if_possible(arg); |
1b1a35ee | 450 | let arg_data = self.extract_inference_diagnostics_data(arg, None); |
041b39d2 | 451 | |
2b03887a | 452 | let Some(typeck_results) = &self.typeck_results else { |
923072b8 FG |
453 | // If we don't have any typeck results we're outside |
454 | // of a body, so we won't be able to get better info | |
455 | // here. | |
064997fb | 456 | return self.bad_inference_failure_err(failure_span, arg_data, error_code); |
041b39d2 XL |
457 | }; |
458 | ||
4b012472 | 459 | let mut local_visitor = FindInferSourceVisitor::new(self, typeck_results, arg); |
353b0b11 FG |
460 | if let Some(body_id) = self.tcx.hir().maybe_body_owned_by( |
461 | self.tcx.typeck_root_def_id(body_def_id.to_def_id()).expect_local(), | |
462 | ) { | |
463 | let expr = self.tcx.hir().body(body_id).value; | |
041b39d2 XL |
464 | local_visitor.visit_expr(expr); |
465 | } | |
e1599b0c | 466 | |
923072b8 | 467 | let Some(InferSource { span, kind }) = local_visitor.infer_source else { |
add651ee | 468 | return self.bad_inference_failure_err(failure_span, arg_data, error_code); |
e1599b0c | 469 | }; |
041b39d2 | 470 | |
e8be2606 | 471 | let (source_kind, name, path) = kind.ty_localized_msg(self); |
f2b60f7d FG |
472 | let failure_span = if should_label_span && !failure_span.overlaps(span) { |
473 | Some(failure_span) | |
474 | } else { | |
475 | None | |
476 | }; | |
064997fb | 477 | |
f2b60f7d FG |
478 | let mut infer_subdiags = Vec::new(); |
479 | let mut multi_suggestions = Vec::new(); | |
923072b8 | 480 | match kind { |
9c376795 | 481 | InferSourceKind::LetBinding { insert_span, pattern_name, ty, def_id } => { |
f2b60f7d FG |
482 | infer_subdiags.push(SourceKindSubdiag::LetLike { |
483 | span: insert_span, | |
484 | name: pattern_name.map(|name| name.to_string()).unwrap_or_else(String::new), | |
485 | x_kind: arg_data.where_x_is_kind(ty), | |
486 | prefix_kind: arg_data.kind.clone(), | |
487 | prefix: arg_data.kind.try_get_prefix().unwrap_or_default(), | |
488 | arg_name: arg_data.name, | |
489 | kind: if pattern_name.is_some() { "with_pattern" } else { "other" }, | |
9c376795 | 490 | type_name: ty_to_string(self, ty, def_id), |
f2b60f7d | 491 | }); |
e1599b0c | 492 | } |
923072b8 | 493 | InferSourceKind::ClosureArg { insert_span, ty } => { |
f2b60f7d FG |
494 | infer_subdiags.push(SourceKindSubdiag::LetLike { |
495 | span: insert_span, | |
496 | name: String::new(), | |
497 | x_kind: arg_data.where_x_is_kind(ty), | |
498 | prefix_kind: arg_data.kind.clone(), | |
499 | prefix: arg_data.kind.try_get_prefix().unwrap_or_default(), | |
500 | arg_name: arg_data.name, | |
501 | kind: "closure", | |
9c376795 | 502 | type_name: ty_to_string(self, ty, None), |
f2b60f7d | 503 | }); |
dc9dc135 | 504 | } |
923072b8 FG |
505 | InferSourceKind::GenericArg { |
506 | insert_span, | |
507 | argument_index, | |
508 | generics_def_id, | |
509 | def_id: _, | |
510 | generic_args, | |
2b03887a | 511 | have_turbofish, |
923072b8 FG |
512 | } => { |
513 | let generics = self.tcx.generics_of(generics_def_id); | |
514 | let is_type = matches!(arg.unpack(), GenericArgKind::Type(_)); | |
515 | ||
f2b60f7d | 516 | let (parent_exists, parent_prefix, parent_name) = |
923072b8 | 517 | InferenceDiagnosticsParentData::for_parent_def_id(self.tcx, generics_def_id) |
f2b60f7d FG |
518 | .map_or((false, String::new(), String::new()), |parent| { |
519 | (true, parent.prefix.to_string(), parent.name) | |
520 | }); | |
923072b8 | 521 | |
f2b60f7d FG |
522 | infer_subdiags.push(SourceKindSubdiag::GenericLabel { |
523 | span, | |
524 | is_type, | |
525 | param_name: generics.params[argument_index].name.to_string(), | |
526 | parent_exists, | |
527 | parent_prefix, | |
528 | parent_name, | |
529 | }); | |
923072b8 | 530 | |
c620b35d | 531 | let args = if self.tcx.get_diagnostic_item(sym::iterator_collect_fn) |
9c376795 FG |
532 | == Some(generics_def_id) |
533 | { | |
534 | "Vec<_>".to_string() | |
535 | } else { | |
ed00b5ec FG |
536 | let mut printer = fmt_printer(self, Namespace::TypeNS); |
537 | printer | |
9c376795 FG |
538 | .comma_sep(generic_args.iter().copied().map(|arg| { |
539 | if arg.is_suggestable(self.tcx, true) { | |
540 | return arg; | |
541 | } | |
064997fb | 542 | |
9c376795 FG |
543 | match arg.unpack() { |
544 | GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), | |
545 | GenericArgKind::Type(_) => self | |
546 | .next_ty_var(TypeVariableOrigin { | |
e8be2606 FG |
547 | span: DUMMY_SP, |
548 | param_def_id: None, | |
9c376795 FG |
549 | }) |
550 | .into(), | |
551 | GenericArgKind::Const(arg) => self | |
552 | .next_const_var( | |
553 | arg.ty(), | |
e8be2606 | 554 | ConstVariableOrigin { span: DUMMY_SP, param_def_id: None }, |
9c376795 FG |
555 | ) |
556 | .into(), | |
557 | } | |
558 | })) | |
ed00b5ec FG |
559 | .unwrap(); |
560 | printer.into_buffer() | |
9c376795 | 561 | }; |
064997fb | 562 | |
2b03887a FG |
563 | if !have_turbofish { |
564 | infer_subdiags.push(SourceKindSubdiag::GenericSuggestion { | |
565 | span: insert_span, | |
566 | arg_count: generic_args.len(), | |
567 | args, | |
568 | }); | |
569 | } | |
dc9dc135 | 570 | } |
add651ee | 571 | InferSourceKind::FullyQualifiedMethodCall { receiver, successor, args, def_id } => { |
e8be2606 FG |
572 | let placeholder = Some( |
573 | self.next_ty_var(TypeVariableOrigin { span: DUMMY_SP, param_def_id: None }), | |
574 | ); | |
575 | if let Some(args) = args.make_suggestable(self.infcx.tcx, true, placeholder) { | |
576 | let mut printer = fmt_printer(self, Namespace::ValueNS); | |
577 | printer.print_def_path(def_id, args).unwrap(); | |
578 | let def_path = printer.into_buffer(); | |
579 | ||
580 | // We only care about whether we have to add `&` or `&mut ` for now. | |
581 | // This is the case if the last adjustment is a borrow and the | |
582 | // first adjustment was not a builtin deref. | |
583 | let adjustment = match typeck_results.expr_adjustments(receiver) { | |
584 | [ | |
585 | Adjustment { kind: Adjust::Deref(None), target: _ }, | |
586 | .., | |
587 | Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), target: _ }, | |
588 | ] => "", | |
589 | [ | |
590 | .., | |
591 | Adjustment { | |
592 | kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)), | |
593 | target: _, | |
594 | }, | |
595 | ] => hir::Mutability::from(*mut_).ref_prefix_str(), | |
596 | _ => "", | |
597 | }; | |
dc9dc135 | 598 | |
e8be2606 FG |
599 | multi_suggestions.push(SourceKindMultiSuggestion::new_fully_qualified( |
600 | receiver.span, | |
601 | def_path, | |
602 | adjustment, | |
603 | successor, | |
604 | )); | |
605 | } | |
60c5eb7d | 606 | } |
923072b8 | 607 | InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => { |
e8be2606 FG |
608 | let placeholder = Some( |
609 | self.next_ty_var(TypeVariableOrigin { span: DUMMY_SP, param_def_id: None }), | |
610 | ); | |
611 | if let Some(ty) = ty.make_suggestable(self.infcx.tcx, true, placeholder) { | |
612 | let ty_info = ty_to_string(self, ty, None); | |
613 | multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return( | |
614 | ty_info, | |
615 | data, | |
616 | should_wrap_expr, | |
617 | )); | |
618 | } | |
f2b60f7d FG |
619 | } |
620 | } | |
621 | match error_code { | |
c0240ec0 | 622 | TypeAnnotationNeeded::E0282 => self.dcx().create_err(AnnotationRequired { |
f2b60f7d FG |
623 | span, |
624 | source_kind, | |
625 | source_name: &name, | |
626 | failure_span, | |
627 | infer_subdiags, | |
628 | multi_suggestions, | |
629 | bad_label: None, | |
e8be2606 FG |
630 | was_written: path.as_ref().map(|_| ()), |
631 | path: path.unwrap_or_default(), | |
c0240ec0 FG |
632 | }), |
633 | TypeAnnotationNeeded::E0283 => self.dcx().create_err(AmbiguousImpl { | |
f2b60f7d FG |
634 | span, |
635 | source_kind, | |
636 | source_name: &name, | |
637 | failure_span, | |
638 | infer_subdiags, | |
639 | multi_suggestions, | |
640 | bad_label: None, | |
e8be2606 FG |
641 | was_written: path.as_ref().map(|_| ()), |
642 | path: path.unwrap_or_default(), | |
c0240ec0 FG |
643 | }), |
644 | TypeAnnotationNeeded::E0284 => self.dcx().create_err(AmbiguousReturn { | |
f2b60f7d FG |
645 | span, |
646 | source_kind, | |
647 | source_name: &name, | |
648 | failure_span, | |
649 | infer_subdiags, | |
650 | multi_suggestions, | |
651 | bad_label: None, | |
e8be2606 FG |
652 | was_written: path.as_ref().map(|_| ()), |
653 | path: path.unwrap_or_default(), | |
c0240ec0 | 654 | }), |
041b39d2 | 655 | } |
041b39d2 | 656 | } |
2b03887a | 657 | } |
48663c56 | 658 | |
923072b8 FG |
659 | #[derive(Debug)] |
660 | struct InferSource<'tcx> { | |
661 | span: Span, | |
662 | kind: InferSourceKind<'tcx>, | |
a2a8927a XL |
663 | } |
664 | ||
923072b8 FG |
665 | #[derive(Debug)] |
666 | enum InferSourceKind<'tcx> { | |
667 | LetBinding { | |
668 | insert_span: Span, | |
669 | pattern_name: Option<Ident>, | |
670 | ty: Ty<'tcx>, | |
9c376795 | 671 | def_id: Option<DefId>, |
923072b8 FG |
672 | }, |
673 | ClosureArg { | |
674 | insert_span: Span, | |
675 | ty: Ty<'tcx>, | |
676 | }, | |
677 | GenericArg { | |
678 | insert_span: Span, | |
679 | argument_index: usize, | |
680 | generics_def_id: DefId, | |
681 | def_id: DefId, | |
682 | generic_args: &'tcx [GenericArg<'tcx>], | |
2b03887a | 683 | have_turbofish: bool, |
923072b8 FG |
684 | }, |
685 | FullyQualifiedMethodCall { | |
686 | receiver: &'tcx Expr<'tcx>, | |
687 | /// If the method has other arguments, this is ", " and the start of the first argument, | |
688 | /// while for methods without arguments this is ")" and the end of the method call. | |
689 | successor: (&'static str, BytePos), | |
add651ee | 690 | args: GenericArgsRef<'tcx>, |
923072b8 FG |
691 | def_id: DefId, |
692 | }, | |
693 | ClosureReturn { | |
694 | ty: Ty<'tcx>, | |
695 | data: &'tcx FnRetTy<'tcx>, | |
696 | should_wrap_expr: Option<Span>, | |
697 | }, | |
698 | } | |
a2a8927a | 699 | |
064997fb FG |
700 | impl<'tcx> InferSource<'tcx> { |
701 | fn from_expansion(&self) -> bool { | |
702 | let source_from_expansion = match self.kind { | |
703 | InferSourceKind::LetBinding { insert_span, .. } | |
704 | | InferSourceKind::ClosureArg { insert_span, .. } | |
705 | | InferSourceKind::GenericArg { insert_span, .. } => insert_span.from_expansion(), | |
706 | InferSourceKind::FullyQualifiedMethodCall { receiver, .. } => { | |
707 | receiver.span.from_expansion() | |
708 | } | |
709 | InferSourceKind::ClosureReturn { data, should_wrap_expr, .. } => { | |
49aad941 | 710 | data.span().from_expansion() || should_wrap_expr.is_some_and(Span::from_expansion) |
064997fb FG |
711 | } |
712 | }; | |
713 | source_from_expansion || self.span.from_expansion() | |
714 | } | |
715 | } | |
716 | ||
923072b8 | 717 | impl<'tcx> InferSourceKind<'tcx> { |
e8be2606 FG |
718 | fn ty_localized_msg(&self, infcx: &InferCtxt<'tcx>) -> (&'static str, String, Option<PathBuf>) { |
719 | let mut path = None; | |
923072b8 FG |
720 | match *self { |
721 | InferSourceKind::LetBinding { ty, .. } | |
722 | | InferSourceKind::ClosureArg { ty, .. } | |
723 | | InferSourceKind::ClosureReturn { ty, .. } => { | |
724 | if ty.is_closure() { | |
e8be2606 | 725 | ("closure", closure_as_fn_str(infcx, ty), path) |
9c376795 | 726 | } else if !ty.is_ty_or_numeric_infer() { |
e8be2606 | 727 | ("normal", infcx.tcx.short_ty_string(ty, &mut path), path) |
923072b8 | 728 | } else { |
e8be2606 | 729 | ("other", String::new(), path) |
923072b8 FG |
730 | } |
731 | } | |
732 | // FIXME: We should be able to add some additional info here. | |
733 | InferSourceKind::GenericArg { .. } | |
e8be2606 | 734 | | InferSourceKind::FullyQualifiedMethodCall { .. } => ("other", String::new(), path), |
a2a8927a XL |
735 | } |
736 | } | |
737 | } | |
738 | ||
064997fb | 739 | #[derive(Debug)] |
923072b8 FG |
740 | struct InsertableGenericArgs<'tcx> { |
741 | insert_span: Span, | |
add651ee | 742 | args: GenericArgsRef<'tcx>, |
923072b8 FG |
743 | generics_def_id: DefId, |
744 | def_id: DefId, | |
2b03887a | 745 | have_turbofish: bool, |
923072b8 FG |
746 | } |
747 | ||
748 | /// A visitor which searches for the "best" spot to use in the inference error. | |
749 | /// | |
750 | /// For this it walks over the hir body and tries to check all places where | |
751 | /// inference variables could be bound. | |
752 | /// | |
753 | /// While doing so, the currently best spot is stored in `infer_source`. | |
754 | /// For details on how we rank spots, see [Self::source_cost] | |
755 | struct FindInferSourceVisitor<'a, 'tcx> { | |
c620b35d | 756 | tecx: &'a TypeErrCtxt<'a, 'tcx>, |
923072b8 FG |
757 | typeck_results: &'a TypeckResults<'tcx>, |
758 | ||
759 | target: GenericArg<'tcx>, | |
760 | ||
761 | attempt: usize, | |
762 | infer_source_cost: usize, | |
763 | infer_source: Option<InferSource<'tcx>>, | |
764 | } | |
765 | ||
766 | impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { | |
767 | fn new( | |
c620b35d | 768 | tecx: &'a TypeErrCtxt<'a, 'tcx>, |
923072b8 FG |
769 | typeck_results: &'a TypeckResults<'tcx>, |
770 | target: GenericArg<'tcx>, | |
771 | ) -> Self { | |
772 | FindInferSourceVisitor { | |
c620b35d | 773 | tecx, |
923072b8 FG |
774 | typeck_results, |
775 | ||
776 | target, | |
777 | ||
778 | attempt: 0, | |
779 | infer_source_cost: usize::MAX, | |
780 | infer_source: None, | |
781 | } | |
a2a8927a | 782 | } |
923072b8 FG |
783 | |
784 | /// Computes cost for the given source. | |
785 | /// | |
786 | /// Sources with a small cost are prefer and should result | |
787 | /// in a clearer and idiomatic suggestion. | |
788 | fn source_cost(&self, source: &InferSource<'tcx>) -> usize { | |
064997fb FG |
789 | #[derive(Clone, Copy)] |
790 | struct CostCtxt<'tcx> { | |
791 | tcx: TyCtxt<'tcx>, | |
923072b8 | 792 | } |
064997fb FG |
793 | impl<'tcx> CostCtxt<'tcx> { |
794 | fn arg_cost(self, arg: GenericArg<'tcx>) -> usize { | |
795 | match arg.unpack() { | |
796 | GenericArgKind::Lifetime(_) => 0, // erased | |
797 | GenericArgKind::Type(ty) => self.ty_cost(ty), | |
798 | GenericArgKind::Const(_) => 3, // some non-zero value | |
799 | } | |
800 | } | |
801 | fn ty_cost(self, ty: Ty<'tcx>) -> usize { | |
802 | match *ty.kind() { | |
803 | ty::Closure(..) => 1000, | |
804 | ty::FnDef(..) => 150, | |
805 | ty::FnPtr(..) => 30, | |
add651ee | 806 | ty::Adt(def, args) => { |
064997fb FG |
807 | 5 + self |
808 | .tcx | |
809 | .generics_of(def.did()) | |
add651ee | 810 | .own_args_no_defaults(self.tcx, args) |
064997fb FG |
811 | .iter() |
812 | .map(|&arg| self.arg_cost(arg)) | |
813 | .sum::<usize>() | |
814 | } | |
815 | ty::Tuple(args) => 5 + args.iter().map(|arg| self.ty_cost(arg)).sum::<usize>(), | |
816 | ty::Ref(_, ty, _) => 2 + self.ty_cost(ty), | |
817 | ty::Infer(..) => 0, | |
818 | _ => 1, | |
819 | } | |
923072b8 FG |
820 | } |
821 | } | |
822 | ||
823 | // The sources are listed in order of preference here. | |
c620b35d | 824 | let tcx = self.tecx.tcx; |
064997fb | 825 | let ctx = CostCtxt { tcx }; |
9ffffee4 | 826 | match source.kind { |
064997fb FG |
827 | InferSourceKind::LetBinding { ty, .. } => ctx.ty_cost(ty), |
828 | InferSourceKind::ClosureArg { ty, .. } => ctx.ty_cost(ty), | |
923072b8 FG |
829 | InferSourceKind::GenericArg { def_id, generic_args, .. } => { |
830 | let variant_cost = match tcx.def_kind(def_id) { | |
064997fb FG |
831 | // `None::<u32>` and friends are ugly. |
832 | DefKind::Variant | DefKind::Ctor(CtorOf::Variant, _) => 15, | |
833 | _ => 10, | |
a2a8927a | 834 | }; |
064997fb | 835 | variant_cost + generic_args.iter().map(|&arg| ctx.arg_cost(arg)).sum::<usize>() |
923072b8 | 836 | } |
add651ee FG |
837 | InferSourceKind::FullyQualifiedMethodCall { args, .. } => { |
838 | 20 + args.iter().map(|arg| ctx.arg_cost(arg)).sum::<usize>() | |
923072b8 FG |
839 | } |
840 | InferSourceKind::ClosureReturn { ty, should_wrap_expr, .. } => { | |
064997fb | 841 | 30 + ctx.ty_cost(ty) + if should_wrap_expr.is_some() { 10 } else { 0 } |
923072b8 | 842 | } |
9ffffee4 | 843 | } |
923072b8 FG |
844 | } |
845 | ||
846 | /// Uses `fn source_cost` to determine whether this inference source is preferable to | |
847 | /// previous sources. We generally prefer earlier sources. | |
848 | #[instrument(level = "debug", skip(self))] | |
9c376795 | 849 | fn update_infer_source(&mut self, mut new_source: InferSource<'tcx>) { |
9ffffee4 FG |
850 | if new_source.from_expansion() { |
851 | return; | |
852 | } | |
853 | ||
923072b8 | 854 | let cost = self.source_cost(&new_source) + self.attempt; |
064997fb | 855 | debug!(?cost); |
923072b8 | 856 | self.attempt += 1; |
ed00b5ec FG |
857 | if let Some(InferSource { kind: InferSourceKind::GenericArg { def_id: did, .. }, .. }) = |
858 | self.infer_source | |
859 | && let InferSourceKind::LetBinding { ref ty, ref mut def_id, .. } = new_source.kind | |
9c376795 FG |
860 | && ty.is_ty_or_numeric_infer() |
861 | { | |
862 | // Customize the output so we talk about `let x: Vec<_> = iter.collect();` instead of | |
863 | // `let x: _ = iter.collect();`, as this is a very common case. | |
864 | *def_id = Some(did); | |
865 | } | |
9ffffee4 | 866 | |
923072b8 FG |
867 | if cost < self.infer_source_cost { |
868 | self.infer_source_cost = cost; | |
869 | self.infer_source = Some(new_source); | |
870 | } | |
871 | } | |
872 | ||
add651ee FG |
873 | fn node_args_opt(&self, hir_id: HirId) -> Option<GenericArgsRef<'tcx>> { |
874 | let args = self.typeck_results.node_args_opt(hir_id); | |
c620b35d | 875 | self.tecx.resolve_vars_if_possible(args) |
064997fb FG |
876 | } |
877 | ||
923072b8 FG |
878 | fn opt_node_type(&self, hir_id: HirId) -> Option<Ty<'tcx>> { |
879 | let ty = self.typeck_results.node_type_opt(hir_id); | |
c620b35d | 880 | self.tecx.resolve_vars_if_possible(ty) |
923072b8 FG |
881 | } |
882 | ||
883 | // Check whether this generic argument is the inference variable we | |
884 | // are looking for. | |
885 | fn generic_arg_is_target(&self, arg: GenericArg<'tcx>) -> bool { | |
886 | if arg == self.target { | |
887 | return true; | |
888 | } | |
889 | ||
890 | match (arg.unpack(), self.target.unpack()) { | |
891 | (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => { | |
892 | use ty::{Infer, TyVar}; | |
893 | match (inner_ty.kind(), target_ty.kind()) { | |
894 | (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => { | |
c620b35d | 895 | self.tecx.sub_relations.borrow_mut().unified(self.tecx, a_vid, b_vid) |
923072b8 FG |
896 | } |
897 | _ => false, | |
a2a8927a XL |
898 | } |
899 | } | |
923072b8 FG |
900 | (GenericArgKind::Const(inner_ct), GenericArgKind::Const(target_ct)) => { |
901 | use ty::InferConst::*; | |
902 | match (inner_ct.kind(), target_ct.kind()) { | |
c620b35d FG |
903 | (ty::ConstKind::Infer(Var(a_vid)), ty::ConstKind::Infer(Var(b_vid))) => { |
904 | self.tecx.inner.borrow_mut().const_unification_table().unioned(a_vid, b_vid) | |
905 | } | |
923072b8 | 906 | _ => false, |
a2a8927a XL |
907 | } |
908 | } | |
923072b8 FG |
909 | _ => false, |
910 | } | |
911 | } | |
912 | ||
913 | /// Does this generic argument contain our target inference variable | |
914 | /// in a way which can be written by the user. | |
915 | fn generic_arg_contains_target(&self, arg: GenericArg<'tcx>) -> bool { | |
916 | let mut walker = arg.walk(); | |
917 | while let Some(inner) = walker.next() { | |
918 | if self.generic_arg_is_target(inner) { | |
919 | return true; | |
920 | } | |
921 | match inner.unpack() { | |
922 | GenericArgKind::Lifetime(_) => {} | |
923 | GenericArgKind::Type(ty) => { | |
9c376795 FG |
924 | if matches!( |
925 | ty.kind(), | |
c620b35d FG |
926 | ty::Alias(ty::Opaque, ..) |
927 | | ty::Closure(..) | |
928 | | ty::CoroutineClosure(..) | |
929 | | ty::Coroutine(..) | |
9c376795 | 930 | ) { |
923072b8 FG |
931 | // Opaque types can't be named by the user right now. |
932 | // | |
ed00b5ec | 933 | // Both the generic arguments of closures and coroutines can |
923072b8 FG |
934 | // also not be named. We may want to only look into the closure |
935 | // signature in case it has no captures, as that can be represented | |
936 | // using `fn(T) -> R`. | |
937 | ||
938 | // FIXME(type_alias_impl_trait): These opaque types | |
939 | // can actually be named, so it would make sense to | |
940 | // adjust this case and add a test for it. | |
941 | walker.skip_current_subtree(); | |
942 | } | |
943 | } | |
944 | GenericArgKind::Const(ct) => { | |
945 | if matches!(ct.kind(), ty::ConstKind::Unevaluated(..)) { | |
946 | // You can't write the generic arguments for | |
947 | // unevaluated constants. | |
948 | walker.skip_current_subtree(); | |
949 | } | |
950 | } | |
951 | } | |
952 | } | |
953 | false | |
954 | } | |
955 | ||
add651ee | 956 | fn expr_inferred_arg_iter( |
923072b8 FG |
957 | &self, |
958 | expr: &'tcx hir::Expr<'tcx>, | |
959 | ) -> Box<dyn Iterator<Item = InsertableGenericArgs<'tcx>> + 'a> { | |
c620b35d | 960 | let tcx = self.tecx.tcx; |
923072b8 FG |
961 | match expr.kind { |
962 | hir::ExprKind::Path(ref path) => { | |
add651ee FG |
963 | if let Some(args) = self.node_args_opt(expr.hir_id) { |
964 | return self.path_inferred_arg_iter(expr.hir_id, args, path); | |
923072b8 FG |
965 | } |
966 | } | |
064997fb FG |
967 | // FIXME(#98711): Ideally we would also deal with type relative |
968 | // paths here, even if that is quite rare. | |
969 | // | |
970 | // See the `need_type_info/expr-struct-type-relative-gat.rs` test | |
971 | // for an example where that would be needed. | |
972 | // | |
973 | // However, the `type_dependent_def_id` for `Self::Output` in an | |
974 | // impl is currently the `DefId` of `Output` in the trait definition | |
975 | // which makes this somewhat difficult and prevents us from just | |
add651ee | 976 | // using `self.path_inferred_arg_iter` here. |
2b03887a FG |
977 | hir::ExprKind::Struct(&hir::QPath::Resolved(_self_ty, path), _, _) |
978 | // FIXME(TaKO8Ki): Ideally we should support this. For that | |
979 | // we have to map back from the self type to the | |
980 | // type alias though. That's difficult. | |
981 | // | |
982 | // See the `need_type_info/issue-103053.rs` test for | |
983 | // a example. | |
781aab86 | 984 | if !matches!(path.res, Res::Def(DefKind::TyAlias, _)) => { |
2b03887a | 985 | if let Some(ty) = self.opt_node_type(expr.hir_id) |
add651ee | 986 | && let ty::Adt(_, args) = ty.kind() |
2b03887a | 987 | { |
add651ee | 988 | return Box::new(self.resolved_path_inferred_arg_iter(path, args)); |
923072b8 FG |
989 | } |
990 | } | |
f2b60f7d | 991 | hir::ExprKind::MethodCall(segment, ..) => { |
923072b8 FG |
992 | if let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) { |
993 | let generics = tcx.generics_of(def_id); | |
994 | let insertable: Option<_> = try { | |
995 | if generics.has_impl_trait() { | |
996 | None? | |
997 | } | |
add651ee | 998 | let args = self.node_args_opt(expr.hir_id)?; |
f2b60f7d | 999 | let span = tcx.hir().span(segment.hir_id); |
923072b8 FG |
1000 | let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi()); |
1001 | InsertableGenericArgs { | |
1002 | insert_span, | |
add651ee | 1003 | args, |
923072b8 FG |
1004 | generics_def_id: def_id, |
1005 | def_id, | |
2b03887a | 1006 | have_turbofish: false, |
923072b8 FG |
1007 | } |
1008 | }; | |
1009 | return Box::new(insertable.into_iter()); | |
1010 | } | |
1011 | } | |
1012 | _ => {} | |
1013 | } | |
1014 | ||
1015 | Box::new(iter::empty()) | |
1016 | } | |
1017 | ||
add651ee | 1018 | fn resolved_path_inferred_arg_iter( |
923072b8 FG |
1019 | &self, |
1020 | path: &'tcx hir::Path<'tcx>, | |
add651ee | 1021 | args: GenericArgsRef<'tcx>, |
923072b8 | 1022 | ) -> impl Iterator<Item = InsertableGenericArgs<'tcx>> + 'a { |
c620b35d | 1023 | let tcx = self.tecx.tcx; |
2b03887a | 1024 | let have_turbofish = path.segments.iter().any(|segment| { |
49aad941 | 1025 | segment.args.is_some_and(|args| args.args.iter().any(|arg| arg.is_ty_or_const())) |
2b03887a | 1026 | }); |
923072b8 FG |
1027 | // The last segment of a path often has `Res::Err` and the |
1028 | // correct `Res` is the one of the whole path. | |
1029 | // | |
1030 | // FIXME: We deal with that one separately for now, | |
1031 | // would be good to remove this special case. | |
1032 | let last_segment_using_path_data: Option<_> = try { | |
1033 | let generics_def_id = tcx.res_generics_def_id(path.res)?; | |
1034 | let generics = tcx.generics_of(generics_def_id); | |
1035 | if generics.has_impl_trait() { | |
e8be2606 | 1036 | do yeet (); |
923072b8 FG |
1037 | } |
1038 | let insert_span = | |
1039 | path.segments.last().unwrap().ident.span.shrink_to_hi().with_hi(path.span.hi()); | |
1040 | InsertableGenericArgs { | |
1041 | insert_span, | |
add651ee | 1042 | args, |
923072b8 FG |
1043 | generics_def_id, |
1044 | def_id: path.res.def_id(), | |
2b03887a | 1045 | have_turbofish, |
5099ac24 | 1046 | } |
a2a8927a | 1047 | }; |
923072b8 FG |
1048 | |
1049 | path.segments | |
1050 | .iter() | |
1051 | .filter_map(move |segment| { | |
f2b60f7d | 1052 | let res = segment.res; |
923072b8 FG |
1053 | let generics_def_id = tcx.res_generics_def_id(res)?; |
1054 | let generics = tcx.generics_of(generics_def_id); | |
1055 | if generics.has_impl_trait() { | |
1056 | return None; | |
1057 | } | |
f2b60f7d | 1058 | let span = tcx.hir().span(segment.hir_id); |
923072b8 FG |
1059 | let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi()); |
1060 | Some(InsertableGenericArgs { | |
1061 | insert_span, | |
add651ee | 1062 | args, |
923072b8 FG |
1063 | generics_def_id, |
1064 | def_id: res.def_id(), | |
2b03887a | 1065 | have_turbofish, |
923072b8 FG |
1066 | }) |
1067 | }) | |
1068 | .chain(last_segment_using_path_data) | |
1069 | } | |
1070 | ||
add651ee | 1071 | fn path_inferred_arg_iter( |
923072b8 FG |
1072 | &self, |
1073 | hir_id: HirId, | |
add651ee | 1074 | args: GenericArgsRef<'tcx>, |
923072b8 FG |
1075 | qpath: &'tcx hir::QPath<'tcx>, |
1076 | ) -> Box<dyn Iterator<Item = InsertableGenericArgs<'tcx>> + 'a> { | |
c620b35d | 1077 | let tcx = self.tecx.tcx; |
923072b8 FG |
1078 | match qpath { |
1079 | hir::QPath::Resolved(_self_ty, path) => { | |
add651ee | 1080 | Box::new(self.resolved_path_inferred_arg_iter(path, args)) |
923072b8 FG |
1081 | } |
1082 | hir::QPath::TypeRelative(ty, segment) => { | |
1083 | let Some(def_id) = self.typeck_results.type_dependent_def_id(hir_id) else { | |
1084 | return Box::new(iter::empty()); | |
1085 | }; | |
1086 | ||
1087 | let generics = tcx.generics_of(def_id); | |
1088 | let segment: Option<_> = try { | |
1089 | if !segment.infer_args || generics.has_impl_trait() { | |
e8be2606 | 1090 | do yeet (); |
923072b8 | 1091 | } |
f2b60f7d | 1092 | let span = tcx.hir().span(segment.hir_id); |
923072b8 | 1093 | let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi()); |
2b03887a FG |
1094 | InsertableGenericArgs { |
1095 | insert_span, | |
add651ee | 1096 | args, |
2b03887a FG |
1097 | generics_def_id: def_id, |
1098 | def_id, | |
1099 | have_turbofish: false, | |
1100 | } | |
923072b8 FG |
1101 | }; |
1102 | ||
1103 | let parent_def_id = generics.parent.unwrap(); | |
9ffffee4 | 1104 | if let DefKind::Impl { .. } = tcx.def_kind(parent_def_id) { |
add651ee | 1105 | let parent_ty = tcx.type_of(parent_def_id).instantiate(tcx, args); |
923072b8 FG |
1106 | match (parent_ty.kind(), &ty.kind) { |
1107 | ( | |
add651ee | 1108 | ty::Adt(def, args), |
923072b8 FG |
1109 | hir::TyKind::Path(hir::QPath::Resolved(_self_ty, path)), |
1110 | ) => { | |
1111 | if tcx.res_generics_def_id(path.res) != Some(def.did()) { | |
1112 | match path.res { | |
781aab86 | 1113 | Res::Def(DefKind::TyAlias, _) => { |
923072b8 FG |
1114 | // FIXME: Ideally we should support this. For that |
1115 | // we have to map back from the self type to the | |
1116 | // type alias though. That's difficult. | |
1117 | // | |
1118 | // See the `need_type_info/type-alias.rs` test for | |
1119 | // some examples. | |
1120 | } | |
1121 | // There cannot be inference variables in the self type, | |
1122 | // so there's nothing for us to do here. | |
2b03887a | 1123 | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => {} |
923072b8 | 1124 | _ => warn!( |
add651ee FG |
1125 | "unexpected path: def={:?} args={:?} path={:?}", |
1126 | def, args, path, | |
923072b8 FG |
1127 | ), |
1128 | } | |
1129 | } else { | |
1130 | return Box::new( | |
add651ee | 1131 | self.resolved_path_inferred_arg_iter(path, args).chain(segment), |
923072b8 FG |
1132 | ); |
1133 | } | |
1134 | } | |
1135 | _ => (), | |
1136 | } | |
1137 | } | |
1138 | ||
1139 | Box::new(segment.into_iter()) | |
1140 | } | |
4b012472 | 1141 | hir::QPath::LangItem(_, _) => Box::new(iter::empty()), |
923072b8 | 1142 | } |
a2a8927a XL |
1143 | } |
1144 | } | |
1145 | ||
923072b8 FG |
1146 | impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { |
1147 | type NestedFilter = nested_filter::OnlyBodies; | |
1148 | ||
1149 | fn nested_visit_map(&mut self) -> Self::Map { | |
c620b35d | 1150 | self.tecx.tcx.hir() |
a2a8927a | 1151 | } |
923072b8 | 1152 | |
e8be2606 | 1153 | fn visit_local(&mut self, local: &'tcx LetStmt<'tcx>) { |
923072b8 FG |
1154 | intravisit::walk_local(self, local); |
1155 | ||
1156 | if let Some(ty) = self.opt_node_type(local.hir_id) { | |
1157 | if self.generic_arg_contains_target(ty.into()) { | |
1158 | match local.source { | |
1159 | LocalSource::Normal if local.ty.is_none() => { | |
1160 | self.update_infer_source(InferSource { | |
1161 | span: local.pat.span, | |
1162 | kind: InferSourceKind::LetBinding { | |
1163 | insert_span: local.pat.span.shrink_to_hi(), | |
1164 | pattern_name: local.pat.simple_ident(), | |
1165 | ty, | |
9c376795 | 1166 | def_id: None, |
923072b8 FG |
1167 | }, |
1168 | }) | |
1169 | } | |
1170 | _ => {} | |
1171 | } | |
1172 | } | |
a2a8927a XL |
1173 | } |
1174 | } | |
04454e1e | 1175 | |
923072b8 FG |
1176 | /// For closures, we first visit the parameters and then the content, |
1177 | /// as we prefer those. | |
1178 | fn visit_body(&mut self, body: &'tcx Body<'tcx>) { | |
1179 | for param in body.params { | |
1180 | debug!( | |
1181 | "param: span {:?}, ty_span {:?}, pat.span {:?}", | |
1182 | param.span, param.ty_span, param.pat.span | |
1183 | ); | |
1184 | if param.ty_span != param.pat.span { | |
1185 | debug!("skipping param: has explicit type"); | |
1186 | continue; | |
1187 | } | |
04454e1e | 1188 | |
add651ee | 1189 | let Some(param_ty) = self.opt_node_type(param.hir_id) else { continue }; |
923072b8 FG |
1190 | |
1191 | if self.generic_arg_contains_target(param_ty.into()) { | |
1192 | self.update_infer_source(InferSource { | |
1193 | span: param.pat.span, | |
1194 | kind: InferSourceKind::ClosureArg { | |
1195 | insert_span: param.pat.span.shrink_to_hi(), | |
1196 | ty: param_ty, | |
1197 | }, | |
1198 | }) | |
1199 | } | |
1200 | } | |
1201 | intravisit::walk_body(self, body); | |
04454e1e | 1202 | } |
923072b8 | 1203 | |
064997fb | 1204 | #[instrument(level = "debug", skip(self))] |
923072b8 | 1205 | fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { |
c620b35d | 1206 | let tcx = self.tecx.tcx; |
923072b8 FG |
1207 | match expr.kind { |
1208 | // When encountering `func(arg)` first look into `arg` and then `func`, | |
1209 | // as `arg` is "more specific". | |
1210 | ExprKind::Call(func, args) => { | |
1211 | for arg in args { | |
1212 | self.visit_expr(arg); | |
1213 | } | |
1214 | self.visit_expr(func); | |
1215 | } | |
1216 | _ => intravisit::walk_expr(self, expr), | |
1217 | } | |
1218 | ||
add651ee | 1219 | for args in self.expr_inferred_arg_iter(expr) { |
064997fb | 1220 | debug!(?args); |
2b03887a FG |
1221 | let InsertableGenericArgs { |
1222 | insert_span, | |
add651ee | 1223 | args, |
2b03887a FG |
1224 | generics_def_id, |
1225 | def_id, | |
1226 | have_turbofish, | |
1227 | } = args; | |
923072b8 | 1228 | let generics = tcx.generics_of(generics_def_id); |
353b0b11 | 1229 | if let Some(mut argument_index) = generics |
add651ee | 1230 | .own_args(args) |
064997fb FG |
1231 | .iter() |
1232 | .position(|&arg| self.generic_arg_contains_target(arg)) | |
923072b8 | 1233 | { |
353b0b11 FG |
1234 | if generics.parent.is_none() && generics.has_self { |
1235 | argument_index += 1; | |
1236 | } | |
c620b35d | 1237 | let args = self.tecx.resolve_vars_if_possible(args); |
add651ee FG |
1238 | let generic_args = |
1239 | &generics.own_args_no_defaults(tcx, args)[generics.own_counts().lifetimes..]; | |
923072b8 | 1240 | let span = match expr.kind { |
f2b60f7d | 1241 | ExprKind::MethodCall(path, ..) => path.ident.span, |
923072b8 FG |
1242 | _ => expr.span, |
1243 | }; | |
1244 | ||
1245 | self.update_infer_source(InferSource { | |
1246 | span, | |
1247 | kind: InferSourceKind::GenericArg { | |
1248 | insert_span, | |
1249 | argument_index, | |
1250 | generics_def_id, | |
1251 | def_id, | |
1252 | generic_args, | |
2b03887a | 1253 | have_turbofish, |
923072b8 FG |
1254 | }, |
1255 | }); | |
1256 | } | |
1257 | } | |
1258 | ||
1259 | if let Some(node_ty) = self.opt_node_type(expr.hir_id) { | |
1260 | if let ( | |
064997fb | 1261 | &ExprKind::Closure(&Closure { fn_decl, body, fn_decl_span, .. }), |
add651ee | 1262 | ty::Closure(_, args), |
923072b8 FG |
1263 | ) = (&expr.kind, node_ty.kind()) |
1264 | { | |
add651ee | 1265 | let output = args.as_closure().sig().output().skip_binder(); |
923072b8 | 1266 | if self.generic_arg_contains_target(output.into()) { |
c620b35d | 1267 | let body = self.tecx.tcx.hir().body(body); |
923072b8 FG |
1268 | let should_wrap_expr = if matches!(body.value.kind, ExprKind::Block(..)) { |
1269 | None | |
1270 | } else { | |
1271 | Some(body.value.span.shrink_to_hi()) | |
1272 | }; | |
1273 | self.update_infer_source(InferSource { | |
1274 | span: fn_decl_span, | |
1275 | kind: InferSourceKind::ClosureReturn { | |
1276 | ty: output, | |
1277 | data: &fn_decl.output, | |
1278 | should_wrap_expr, | |
1279 | }, | |
1280 | }) | |
1281 | } | |
1282 | } | |
1283 | } | |
1284 | ||
1285 | let has_impl_trait = |def_id| { | |
1286 | iter::successors(Some(tcx.generics_of(def_id)), |generics| { | |
1287 | generics.parent.map(|def_id| tcx.generics_of(def_id)) | |
1288 | }) | |
1289 | .any(|generics| generics.has_impl_trait()) | |
1290 | }; | |
add651ee FG |
1291 | if let ExprKind::MethodCall(path, receiver, method_args, span) = expr.kind |
1292 | && let Some(args) = self.node_args_opt(expr.hir_id) | |
1293 | && args.iter().any(|arg| self.generic_arg_contains_target(arg)) | |
923072b8 | 1294 | && let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) |
c620b35d | 1295 | && self.tecx.tcx.trait_of_item(def_id).is_some() |
923072b8 FG |
1296 | && !has_impl_trait(def_id) |
1297 | { | |
1298 | let successor = | |
add651ee | 1299 | method_args.get(0).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo())); |
c620b35d | 1300 | let args = self.tecx.resolve_vars_if_possible(args); |
923072b8 FG |
1301 | self.update_infer_source(InferSource { |
1302 | span: path.ident.span, | |
1303 | kind: InferSourceKind::FullyQualifiedMethodCall { | |
f2b60f7d | 1304 | receiver, |
923072b8 | 1305 | successor, |
add651ee | 1306 | args, |
923072b8 | 1307 | def_id, |
ed00b5ec | 1308 | }, |
923072b8 | 1309 | }) |
04454e1e FG |
1310 | } |
1311 | } | |
1312 | } |