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