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