2 AmbigousImpl, AmbigousReturn, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator,
3 SourceKindMultiSuggestion, SourceKindSubdiag,
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};
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, sym, Ident};
24 use rustc_span::{BytePos, Span};
28 pub enum TypeAnnotationNeeded {
29 /// ```compile_fail,E0282
30 /// let x = "hello".chars().rev().collect();
33 /// An implementation cannot be chosen unambiguously because of lack of information.
34 /// ```compile_fail,E0283
35 /// let _ = Default::default();
38 /// ```compile_fail,E0284
39 /// let mut d: u64 = 2;
40 /// d = d % 1u32.into();
45 impl Into<rustc_errors::DiagnosticId> for TypeAnnotationNeeded {
46 fn into(self) -> rustc_errors::DiagnosticId {
48 Self::E0282 => rustc_errors::error_code!(E0282),
49 Self::E0283 => rustc_errors::error_code!(E0283),
50 Self::E0284 => rustc_errors::error_code!(E0284),
55 /// Information about a constant or a type containing inference variables.
56 pub struct InferenceDiagnosticsData {
58 pub span: Option<Span>,
59 pub kind: UnderspecifiedArgKind,
60 pub parent: Option<InferenceDiagnosticsParentData>,
63 /// Data on the parent definition where a generic argument was declared.
64 pub struct InferenceDiagnosticsParentData {
70 pub enum UnderspecifiedArgKind {
71 Type { prefix: Cow<'static, str> },
72 Const { is_parameter: bool },
75 impl InferenceDiagnosticsData {
76 fn can_add_more_info(&self) -> bool {
77 !(self.name == "_" && matches!(self.kind, UnderspecifiedArgKind::Type { .. }))
80 fn where_x_is_kind(&self, in_type: Ty<'_>) -> &'static str {
81 if in_type.is_ty_infer() {
83 } else if self.name == "_" {
84 // FIXME: Consider specializing this message if there is a single `_`
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
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
101 .map(|parent| (parent.prefix, parent.name.clone()))
102 .unwrap_or_default();
106 prefix_kind: self.kind.clone(),
107 prefix: self.kind.try_get_prefix().unwrap_or_default(),
108 name: self.name.clone(),
116 impl InferenceDiagnosticsParentData {
117 fn for_parent_def_id(
119 parent_def_id: DefId,
120 ) -> Option<InferenceDiagnosticsParentData> {
122 tcx.def_key(parent_def_id).disambiguated_data.data.get_opt_name()?.to_string();
124 Some(InferenceDiagnosticsParentData {
125 prefix: tcx.def_kind(parent_def_id).descr(parent_def_id),
130 fn for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<InferenceDiagnosticsParentData> {
131 Self::for_parent_def_id(tcx, tcx.parent(def_id))
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",
142 rustc_errors::DiagnosticArgValue::Str(kind.into())
146 impl UnderspecifiedArgKind {
147 fn try_get_prefix(&self) -> Option<&str> {
149 Self::Type { prefix } => Some(prefix.as_ref()),
150 Self::Const { .. } => None,
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");
161 if let TypeVariableOriginKind::TypeParameterDefinition(name, _) =
162 infcx.inner.borrow_mut().type_variables().var_origin(ty_vid).kind
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");
174 if let ConstVariableOriginKind::ConstParameterDefinition(name, _) =
175 infcx.inner.borrow_mut().const_unification_table().probe_value(ct_vid).origin.kind
182 printer.const_infer_name_resolver = Some(Box::new(const_getter));
186 fn ty_to_string<'tcx>(
187 infcx: &InferCtxt<'tcx>,
189 called_method_def_id: Option<DefId>,
191 let printer = fmt_printer(infcx, Namespace::TypeNS);
192 let ty = infcx.resolve_vars_if_possible(ty);
193 match (ty.kind(), called_method_def_id) {
194 // We don't want the regular output for `fn`s because it includes its path in
195 // invalid pseudo-syntax, we want the `fn`-pointer output instead.
196 (ty::FnDef(..), _) => ty.fn_sig(infcx.tcx).print(printer).unwrap().into_buffer(),
199 && infcx.tcx.get_diagnostic_item(sym::iterator_collect_fn) == Some(def_id) =>
203 _ if ty.is_ty_infer() => "/* Type */".to_string(),
204 // FIXME: The same thing for closures, but this only works when the closure
205 // does not capture anything.
207 // We do have to hide the `extern "rust-call"` ABI in that case though,
208 // which is too much of a bother for now.
209 _ => ty.print(printer).unwrap().into_buffer(),
213 /// We don't want to directly use `ty_to_string` for closures as their type isn't really
214 /// something users are familiar with. Directly printing the `fn_sig` of closures also
215 /// doesn't work as they actually use the "rust-call" API.
216 fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String {
217 let ty::Closure(_, substs) = ty.kind() else { unreachable!() };
218 let fn_sig = substs.as_closure().sig();
227 .map(|arg| ty_to_string(infcx, arg, None))
231 .unwrap_or_default();
232 let ret = if fn_sig.output().skip_binder().is_unit() {
235 format!(" -> {}", ty_to_string(infcx, fn_sig.output().skip_binder(), None))
237 format!("fn({}){}", args, ret)
240 impl<'tcx> InferCtxt<'tcx> {
241 /// Extracts data used by diagnostic for either types or constants
242 /// which were stuck during inference.
243 pub fn extract_inference_diagnostics_data(
245 arg: GenericArg<'tcx>,
246 highlight: Option<ty::print::RegionHighlightMode<'tcx>>,
247 ) -> InferenceDiagnosticsData {
249 GenericArgKind::Type(ty) => {
250 if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() {
251 let mut inner = self.inner.borrow_mut();
252 let ty_vars = &inner.type_variables();
253 let var_origin = ty_vars.var_origin(ty_vid);
254 if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) =
257 if name != kw::SelfUpper {
258 return InferenceDiagnosticsData {
259 name: name.to_string(),
260 span: Some(var_origin.span),
261 kind: UnderspecifiedArgKind::Type {
262 prefix: "type parameter".into(),
264 parent: def_id.and_then(|def_id| {
265 InferenceDiagnosticsParentData::for_def_id(self.tcx, def_id)
272 let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
273 if let Some(highlight) = highlight {
274 printer.region_highlight_mode = highlight;
276 InferenceDiagnosticsData {
277 name: ty.print(printer).unwrap().into_buffer(),
279 kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string(self.tcx) },
283 GenericArgKind::Const(ct) => {
284 if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.kind() {
286 self.inner.borrow_mut().const_unification_table().probe_value(vid).origin;
287 if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
290 return InferenceDiagnosticsData {
291 name: name.to_string(),
292 span: Some(origin.span),
293 kind: UnderspecifiedArgKind::Const { is_parameter: true },
294 parent: InferenceDiagnosticsParentData::for_def_id(self.tcx, def_id),
298 debug_assert!(!origin.span.is_dummy());
299 let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::ValueNS);
300 if let Some(highlight) = highlight {
301 printer.region_highlight_mode = highlight;
303 InferenceDiagnosticsData {
304 name: ct.print(printer).unwrap().into_buffer(),
305 span: Some(origin.span),
306 kind: UnderspecifiedArgKind::Const { is_parameter: false },
310 // If we end up here the `FindInferSourceVisitor`
311 // won't work, as its expected argument isn't an inference variable.
313 // FIXME: Ideally we should look into the generic constant
314 // to figure out which inference var is actually unresolved so that
315 // this path is unreachable.
316 let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::ValueNS);
317 if let Some(highlight) = highlight {
318 printer.region_highlight_mode = highlight;
320 InferenceDiagnosticsData {
321 name: ct.print(printer).unwrap().into_buffer(),
323 kind: UnderspecifiedArgKind::Const { is_parameter: false },
328 GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
332 /// Used as a fallback in [TypeErrCtxt::emit_inference_failure_err]
333 /// in case we weren't able to get a better error.
334 fn bad_inference_failure_err(
337 arg_data: InferenceDiagnosticsData,
338 error_code: TypeAnnotationNeeded,
339 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
340 let source_kind = "other";
341 let source_name = "";
342 let failure_span = None;
343 let infer_subdiags = Vec::new();
344 let multi_suggestions = Vec::new();
345 let bad_label = Some(arg_data.make_bad_error(span));
347 TypeAnnotationNeeded::E0282 => AnnotationRequired {
356 .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
357 TypeAnnotationNeeded::E0283 => AmbigousImpl {
366 .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
367 TypeAnnotationNeeded::E0284 => AmbigousReturn {
376 .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
381 impl<'tcx> TypeErrCtxt<'_, 'tcx> {
382 #[instrument(level = "debug", skip(self, error_code))]
383 pub fn emit_inference_failure_err(
385 body_id: Option<hir::BodyId>,
387 arg: GenericArg<'tcx>,
388 error_code: TypeAnnotationNeeded,
389 should_label_span: bool,
390 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
391 let arg = self.resolve_vars_if_possible(arg);
392 let arg_data = self.extract_inference_diagnostics_data(arg, None);
394 let Some(typeck_results) = &self.typeck_results else {
395 // If we don't have any typeck results we're outside
396 // of a body, so we won't be able to get better info
398 return self.bad_inference_failure_err(failure_span, arg_data, error_code);
401 let mut local_visitor = FindInferSourceVisitor::new(&self, typeck_results, arg);
402 if let Some(body_id) = body_id {
403 let expr = self.tcx.hir().expect_expr(body_id.hir_id);
404 local_visitor.visit_expr(expr);
407 let Some(InferSource { span, kind }) = local_visitor.infer_source else {
408 return self.bad_inference_failure_err(failure_span, arg_data, error_code)
411 let (source_kind, name) = kind.ty_localized_msg(self);
412 let failure_span = if should_label_span && !failure_span.overlaps(span) {
418 let mut infer_subdiags = Vec::new();
419 let mut multi_suggestions = Vec::new();
421 InferSourceKind::LetBinding { insert_span, pattern_name, ty, def_id } => {
422 infer_subdiags.push(SourceKindSubdiag::LetLike {
424 name: pattern_name.map(|name| name.to_string()).unwrap_or_else(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: if pattern_name.is_some() { "with_pattern" } else { "other" },
430 type_name: ty_to_string(self, ty, def_id),
433 InferSourceKind::ClosureArg { insert_span, ty } => {
434 infer_subdiags.push(SourceKindSubdiag::LetLike {
437 x_kind: arg_data.where_x_is_kind(ty),
438 prefix_kind: arg_data.kind.clone(),
439 prefix: arg_data.kind.try_get_prefix().unwrap_or_default(),
440 arg_name: arg_data.name,
442 type_name: ty_to_string(self, ty, None),
445 InferSourceKind::GenericArg {
453 let generics = self.tcx.generics_of(generics_def_id);
454 let is_type = matches!(arg.unpack(), GenericArgKind::Type(_));
456 let (parent_exists, parent_prefix, parent_name) =
457 InferenceDiagnosticsParentData::for_parent_def_id(self.tcx, generics_def_id)
458 .map_or((false, String::new(), String::new()), |parent| {
459 (true, parent.prefix.to_string(), parent.name)
462 infer_subdiags.push(SourceKindSubdiag::GenericLabel {
465 param_name: generics.params[argument_index].name.to_string(),
471 let args = if self.infcx.tcx.get_diagnostic_item(sym::iterator_collect_fn)
472 == Some(generics_def_id)
476 fmt_printer(self, Namespace::TypeNS)
477 .comma_sep(generic_args.iter().copied().map(|arg| {
478 if arg.is_suggestable(self.tcx, true) {
483 GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
484 GenericArgKind::Type(_) => self
485 .next_ty_var(TypeVariableOrigin {
486 span: rustc_span::DUMMY_SP,
487 kind: TypeVariableOriginKind::MiscVariable,
490 GenericArgKind::Const(arg) => self
493 ConstVariableOrigin {
494 span: rustc_span::DUMMY_SP,
495 kind: ConstVariableOriginKind::MiscVariable,
506 infer_subdiags.push(SourceKindSubdiag::GenericSuggestion {
508 arg_count: generic_args.len(),
513 InferSourceKind::FullyQualifiedMethodCall { receiver, successor, substs, def_id } => {
514 let printer = fmt_printer(self, Namespace::ValueNS);
515 let def_path = printer.print_def_path(def_id, substs).unwrap().into_buffer();
517 // We only care about whether we have to add `&` or `&mut ` for now.
518 // This is the case if the last adjustment is a borrow and the
519 // first adjustment was not a builtin deref.
520 let adjustment = match typeck_results.expr_adjustments(receiver) {
522 Adjustment { kind: Adjust::Deref(None), target: _ },
524 Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), target: _ },
528 Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)), target: _ },
529 ] => hir::Mutability::from(*mut_).ref_prefix_str(),
533 multi_suggestions.push(SourceKindMultiSuggestion::new_fully_qualified(
540 InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => {
541 let ty_info = ty_to_string(self, ty, None);
542 multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return(
550 TypeAnnotationNeeded::E0282 => AnnotationRequired {
559 .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
560 TypeAnnotationNeeded::E0283 => AmbigousImpl {
569 .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
570 TypeAnnotationNeeded::E0284 => AmbigousReturn {
579 .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
584 impl<'tcx> InferCtxt<'tcx> {
585 pub fn need_type_info_err_in_generator(
587 kind: hir::GeneratorKind,
590 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
591 let ty = self.resolve_vars_if_possible(ty);
592 let data = self.extract_inference_diagnostics_data(ty.into(), None);
594 NeedTypeInfoInGenerator {
595 bad_label: data.make_bad_error(span),
597 generator_kind: GeneratorKindAsDiagArg(kind),
599 .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
603 pub struct GeneratorKindAsDiagArg(pub hir::GeneratorKind);
605 impl IntoDiagnosticArg for GeneratorKindAsDiagArg {
606 fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
607 let kind = match self.0 {
608 hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) => "async_block",
609 hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure) => "async_closure",
610 hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn) => "async_fn",
611 hir::GeneratorKind::Gen => "generator",
613 rustc_errors::DiagnosticArgValue::Str(kind.into())
618 struct InferSource<'tcx> {
620 kind: InferSourceKind<'tcx>,
624 enum InferSourceKind<'tcx> {
627 pattern_name: Option<Ident>,
629 def_id: Option<DefId>,
637 argument_index: usize,
638 generics_def_id: DefId,
640 generic_args: &'tcx [GenericArg<'tcx>],
641 have_turbofish: bool,
643 FullyQualifiedMethodCall {
644 receiver: &'tcx Expr<'tcx>,
645 /// If the method has other arguments, this is ", " and the start of the first argument,
646 /// while for methods without arguments this is ")" and the end of the method call.
647 successor: (&'static str, BytePos),
648 substs: SubstsRef<'tcx>,
653 data: &'tcx FnRetTy<'tcx>,
654 should_wrap_expr: Option<Span>,
658 impl<'tcx> InferSource<'tcx> {
659 fn from_expansion(&self) -> bool {
660 let source_from_expansion = match self.kind {
661 InferSourceKind::LetBinding { insert_span, .. }
662 | InferSourceKind::ClosureArg { insert_span, .. }
663 | InferSourceKind::GenericArg { insert_span, .. } => insert_span.from_expansion(),
664 InferSourceKind::FullyQualifiedMethodCall { receiver, .. } => {
665 receiver.span.from_expansion()
667 InferSourceKind::ClosureReturn { data, should_wrap_expr, .. } => {
668 data.span().from_expansion() || should_wrap_expr.map_or(false, Span::from_expansion)
671 source_from_expansion || self.span.from_expansion()
675 impl<'tcx> InferSourceKind<'tcx> {
676 fn ty_localized_msg(&self, infcx: &InferCtxt<'tcx>) -> (&'static str, String) {
678 InferSourceKind::LetBinding { ty, .. }
679 | InferSourceKind::ClosureArg { ty, .. }
680 | InferSourceKind::ClosureReturn { ty, .. } => {
682 ("closure", closure_as_fn_str(infcx, ty))
683 } else if !ty.is_ty_infer() {
684 ("normal", ty_to_string(infcx, ty, None))
686 ("other", String::new())
689 // FIXME: We should be able to add some additional info here.
690 InferSourceKind::GenericArg { .. }
691 | InferSourceKind::FullyQualifiedMethodCall { .. } => ("other", String::new()),
697 struct InsertableGenericArgs<'tcx> {
699 substs: SubstsRef<'tcx>,
700 generics_def_id: DefId,
702 have_turbofish: bool,
705 /// A visitor which searches for the "best" spot to use in the inference error.
707 /// For this it walks over the hir body and tries to check all places where
708 /// inference variables could be bound.
710 /// While doing so, the currently best spot is stored in `infer_source`.
711 /// For details on how we rank spots, see [Self::source_cost]
712 struct FindInferSourceVisitor<'a, 'tcx> {
713 infcx: &'a InferCtxt<'tcx>,
714 typeck_results: &'a TypeckResults<'tcx>,
716 target: GenericArg<'tcx>,
719 infer_source_cost: usize,
720 infer_source: Option<InferSource<'tcx>>,
723 impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
725 infcx: &'a InferCtxt<'tcx>,
726 typeck_results: &'a TypeckResults<'tcx>,
727 target: GenericArg<'tcx>,
729 FindInferSourceVisitor {
736 infer_source_cost: usize::MAX,
741 /// Computes cost for the given source.
743 /// Sources with a small cost are prefer and should result
744 /// in a clearer and idiomatic suggestion.
745 fn source_cost(&self, source: &InferSource<'tcx>) -> usize {
746 #[derive(Clone, Copy)]
747 struct CostCtxt<'tcx> {
750 impl<'tcx> CostCtxt<'tcx> {
751 fn arg_cost(self, arg: GenericArg<'tcx>) -> usize {
753 GenericArgKind::Lifetime(_) => 0, // erased
754 GenericArgKind::Type(ty) => self.ty_cost(ty),
755 GenericArgKind::Const(_) => 3, // some non-zero value
758 fn ty_cost(self, ty: Ty<'tcx>) -> usize {
760 ty::Closure(..) => 1000,
761 ty::FnDef(..) => 150,
763 ty::Adt(def, substs) => {
766 .generics_of(def.did())
767 .own_substs_no_defaults(self.tcx, substs)
769 .map(|&arg| self.arg_cost(arg))
772 ty::Tuple(args) => 5 + args.iter().map(|arg| self.ty_cost(arg)).sum::<usize>(),
773 ty::Ref(_, ty, _) => 2 + self.ty_cost(ty),
780 // The sources are listed in order of preference here.
781 let tcx = self.infcx.tcx;
782 let ctx = CostCtxt { tcx };
783 let base_cost = match source.kind {
784 InferSourceKind::LetBinding { ty, .. } => ctx.ty_cost(ty),
785 InferSourceKind::ClosureArg { ty, .. } => ctx.ty_cost(ty),
786 InferSourceKind::GenericArg { def_id, generic_args, .. } => {
787 let variant_cost = match tcx.def_kind(def_id) {
788 // `None::<u32>` and friends are ugly.
789 DefKind::Variant | DefKind::Ctor(CtorOf::Variant, _) => 15,
792 variant_cost + generic_args.iter().map(|&arg| ctx.arg_cost(arg)).sum::<usize>()
794 InferSourceKind::FullyQualifiedMethodCall { substs, .. } => {
795 20 + substs.iter().map(|arg| ctx.arg_cost(arg)).sum::<usize>()
797 InferSourceKind::ClosureReturn { ty, should_wrap_expr, .. } => {
798 30 + ctx.ty_cost(ty) + if should_wrap_expr.is_some() { 10 } else { 0 }
802 let suggestion_may_apply = if source.from_expansion() { 10000 } else { 0 };
804 base_cost + suggestion_may_apply
807 /// Uses `fn source_cost` to determine whether this inference source is preferable to
808 /// previous sources. We generally prefer earlier sources.
809 #[instrument(level = "debug", skip(self))]
810 fn update_infer_source(&mut self, mut new_source: InferSource<'tcx>) {
811 let cost = self.source_cost(&new_source) + self.attempt;
814 if let Some(InferSource { kind: InferSourceKind::GenericArg { def_id: did, ..}, .. }) = self.infer_source
815 && let InferSourceKind::LetBinding { ref ty, ref mut def_id, ..} = new_source.kind
818 // Customize the output so we talk about `let x: Vec<_> = iter.collect();` instead of
819 // `let x: _ = iter.collect();`, as this is a very common case.
822 if cost < self.infer_source_cost {
823 self.infer_source_cost = cost;
824 self.infer_source = Some(new_source);
828 fn node_substs_opt(&self, hir_id: HirId) -> Option<SubstsRef<'tcx>> {
829 let substs = self.typeck_results.node_substs_opt(hir_id);
830 self.infcx.resolve_vars_if_possible(substs)
833 fn opt_node_type(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
834 let ty = self.typeck_results.node_type_opt(hir_id);
835 self.infcx.resolve_vars_if_possible(ty)
838 // Check whether this generic argument is the inference variable we
840 fn generic_arg_is_target(&self, arg: GenericArg<'tcx>) -> bool {
841 if arg == self.target {
845 match (arg.unpack(), self.target.unpack()) {
846 (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {
847 use ty::{Infer, TyVar};
848 match (inner_ty.kind(), target_ty.kind()) {
849 (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => {
850 self.infcx.inner.borrow_mut().type_variables().sub_unified(a_vid, b_vid)
855 (GenericArgKind::Const(inner_ct), GenericArgKind::Const(target_ct)) => {
856 use ty::InferConst::*;
857 match (inner_ct.kind(), target_ct.kind()) {
858 (ty::ConstKind::Infer(Var(a_vid)), ty::ConstKind::Infer(Var(b_vid))) => self
862 .const_unification_table()
863 .unioned(a_vid, b_vid),
871 /// Does this generic argument contain our target inference variable
872 /// in a way which can be written by the user.
873 fn generic_arg_contains_target(&self, arg: GenericArg<'tcx>) -> bool {
874 let mut walker = arg.walk();
875 while let Some(inner) = walker.next() {
876 if self.generic_arg_is_target(inner) {
879 match inner.unpack() {
880 GenericArgKind::Lifetime(_) => {}
881 GenericArgKind::Type(ty) => {
884 ty::Alias(ty::Opaque, ..) | ty::Closure(..) | ty::Generator(..)
886 // Opaque types can't be named by the user right now.
888 // Both the generic arguments of closures and generators can
889 // also not be named. We may want to only look into the closure
890 // signature in case it has no captures, as that can be represented
891 // using `fn(T) -> R`.
893 // FIXME(type_alias_impl_trait): These opaque types
894 // can actually be named, so it would make sense to
895 // adjust this case and add a test for it.
896 walker.skip_current_subtree();
899 GenericArgKind::Const(ct) => {
900 if matches!(ct.kind(), ty::ConstKind::Unevaluated(..)) {
901 // You can't write the generic arguments for
902 // unevaluated constants.
903 walker.skip_current_subtree();
911 fn expr_inferred_subst_iter(
913 expr: &'tcx hir::Expr<'tcx>,
914 ) -> Box<dyn Iterator<Item = InsertableGenericArgs<'tcx>> + 'a> {
915 let tcx = self.infcx.tcx;
917 hir::ExprKind::Path(ref path) => {
918 if let Some(substs) = self.node_substs_opt(expr.hir_id) {
919 return self.path_inferred_subst_iter(expr.hir_id, substs, path);
922 // FIXME(#98711): Ideally we would also deal with type relative
923 // paths here, even if that is quite rare.
925 // See the `need_type_info/expr-struct-type-relative-gat.rs` test
926 // for an example where that would be needed.
928 // However, the `type_dependent_def_id` for `Self::Output` in an
929 // impl is currently the `DefId` of `Output` in the trait definition
930 // which makes this somewhat difficult and prevents us from just
931 // using `self.path_inferred_subst_iter` here.
932 hir::ExprKind::Struct(&hir::QPath::Resolved(_self_ty, path), _, _)
933 // FIXME(TaKO8Ki): Ideally we should support this. For that
934 // we have to map back from the self type to the
935 // type alias though. That's difficult.
937 // See the `need_type_info/issue-103053.rs` test for
939 if !matches!(path.res, Res::Def(DefKind::TyAlias, _)) => {
940 if let Some(ty) = self.opt_node_type(expr.hir_id)
941 && let ty::Adt(_, substs) = ty.kind()
943 return Box::new(self.resolved_path_inferred_subst_iter(path, substs));
946 hir::ExprKind::MethodCall(segment, ..) => {
947 if let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) {
948 let generics = tcx.generics_of(def_id);
949 let insertable: Option<_> = try {
950 if generics.has_impl_trait() {
953 let substs = self.node_substs_opt(expr.hir_id)?;
954 let span = tcx.hir().span(segment.hir_id);
955 let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
956 InsertableGenericArgs {
959 generics_def_id: def_id,
961 have_turbofish: false,
964 return Box::new(insertable.into_iter());
970 Box::new(iter::empty())
973 fn resolved_path_inferred_subst_iter(
975 path: &'tcx hir::Path<'tcx>,
976 substs: SubstsRef<'tcx>,
977 ) -> impl Iterator<Item = InsertableGenericArgs<'tcx>> + 'a {
978 let tcx = self.infcx.tcx;
979 let have_turbofish = path.segments.iter().any(|segment| {
980 segment.args.map_or(false, |args| args.args.iter().any(|arg| arg.is_ty_or_const()))
982 // The last segment of a path often has `Res::Err` and the
983 // correct `Res` is the one of the whole path.
985 // FIXME: We deal with that one separately for now,
986 // would be good to remove this special case.
987 let last_segment_using_path_data: Option<_> = try {
988 let generics_def_id = tcx.res_generics_def_id(path.res)?;
989 let generics = tcx.generics_of(generics_def_id);
990 if generics.has_impl_trait() {
994 path.segments.last().unwrap().ident.span.shrink_to_hi().with_hi(path.span.hi());
995 InsertableGenericArgs {
999 def_id: path.res.def_id(),
1006 .filter_map(move |segment| {
1007 let res = segment.res;
1008 let generics_def_id = tcx.res_generics_def_id(res)?;
1009 let generics = tcx.generics_of(generics_def_id);
1010 if generics.has_impl_trait() {
1013 let span = tcx.hir().span(segment.hir_id);
1014 let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
1015 Some(InsertableGenericArgs {
1019 def_id: res.def_id(),
1023 .chain(last_segment_using_path_data)
1026 fn path_inferred_subst_iter(
1029 substs: SubstsRef<'tcx>,
1030 qpath: &'tcx hir::QPath<'tcx>,
1031 ) -> Box<dyn Iterator<Item = InsertableGenericArgs<'tcx>> + 'a> {
1032 let tcx = self.infcx.tcx;
1034 hir::QPath::Resolved(_self_ty, path) => {
1035 Box::new(self.resolved_path_inferred_subst_iter(path, substs))
1037 hir::QPath::TypeRelative(ty, segment) => {
1038 let Some(def_id) = self.typeck_results.type_dependent_def_id(hir_id) else {
1039 return Box::new(iter::empty());
1042 let generics = tcx.generics_of(def_id);
1043 let segment: Option<_> = try {
1044 if !segment.infer_args || generics.has_impl_trait() {
1047 let span = tcx.hir().span(segment.hir_id);
1048 let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
1049 InsertableGenericArgs {
1052 generics_def_id: def_id,
1054 have_turbofish: false,
1058 let parent_def_id = generics.parent.unwrap();
1059 if tcx.def_kind(parent_def_id) == DefKind::Impl {
1060 let parent_ty = tcx.bound_type_of(parent_def_id).subst(tcx, substs);
1061 match (parent_ty.kind(), &ty.kind) {
1063 ty::Adt(def, substs),
1064 hir::TyKind::Path(hir::QPath::Resolved(_self_ty, path)),
1066 if tcx.res_generics_def_id(path.res) != Some(def.did()) {
1068 Res::Def(DefKind::TyAlias, _) => {
1069 // FIXME: Ideally we should support this. For that
1070 // we have to map back from the self type to the
1071 // type alias though. That's difficult.
1073 // See the `need_type_info/type-alias.rs` test for
1076 // There cannot be inference variables in the self type,
1077 // so there's nothing for us to do here.
1078 Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => {}
1080 "unexpected path: def={:?} substs={:?} path={:?}",
1086 self.resolved_path_inferred_subst_iter(path, substs)
1095 Box::new(segment.into_iter())
1097 hir::QPath::LangItem(_, _, _) => Box::new(iter::empty()),
1102 impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
1103 type NestedFilter = nested_filter::OnlyBodies;
1105 fn nested_visit_map(&mut self) -> Self::Map {
1106 self.infcx.tcx.hir()
1109 fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
1110 intravisit::walk_local(self, local);
1112 if let Some(ty) = self.opt_node_type(local.hir_id) {
1113 if self.generic_arg_contains_target(ty.into()) {
1114 match local.source {
1115 LocalSource::Normal if local.ty.is_none() => {
1116 self.update_infer_source(InferSource {
1117 span: local.pat.span,
1118 kind: InferSourceKind::LetBinding {
1119 insert_span: local.pat.span.shrink_to_hi(),
1120 pattern_name: local.pat.simple_ident(),
1132 /// For closures, we first visit the parameters and then the content,
1133 /// as we prefer those.
1134 fn visit_body(&mut self, body: &'tcx Body<'tcx>) {
1135 for param in body.params {
1137 "param: span {:?}, ty_span {:?}, pat.span {:?}",
1138 param.span, param.ty_span, param.pat.span
1140 if param.ty_span != param.pat.span {
1141 debug!("skipping param: has explicit type");
1145 let Some(param_ty) = self.opt_node_type(param.hir_id) else {
1149 if self.generic_arg_contains_target(param_ty.into()) {
1150 self.update_infer_source(InferSource {
1151 span: param.pat.span,
1152 kind: InferSourceKind::ClosureArg {
1153 insert_span: param.pat.span.shrink_to_hi(),
1159 intravisit::walk_body(self, body);
1162 #[instrument(level = "debug", skip(self))]
1163 fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
1164 let tcx = self.infcx.tcx;
1166 // When encountering `func(arg)` first look into `arg` and then `func`,
1167 // as `arg` is "more specific".
1168 ExprKind::Call(func, args) => {
1170 self.visit_expr(arg);
1172 self.visit_expr(func);
1174 _ => intravisit::walk_expr(self, expr),
1177 for args in self.expr_inferred_subst_iter(expr) {
1179 let InsertableGenericArgs {
1186 let generics = tcx.generics_of(generics_def_id);
1187 if let Some(argument_index) = generics
1190 .position(|&arg| self.generic_arg_contains_target(arg))
1192 let substs = self.infcx.resolve_vars_if_possible(substs);
1193 let generic_args = &generics.own_substs_no_defaults(tcx, substs)
1194 [generics.own_counts().lifetimes..];
1195 let span = match expr.kind {
1196 ExprKind::MethodCall(path, ..) => path.ident.span,
1200 self.update_infer_source(InferSource {
1202 kind: InferSourceKind::GenericArg {
1214 if let Some(node_ty) = self.opt_node_type(expr.hir_id) {
1216 &ExprKind::Closure(&Closure { fn_decl, body, fn_decl_span, .. }),
1217 ty::Closure(_, substs),
1218 ) = (&expr.kind, node_ty.kind())
1220 let output = substs.as_closure().sig().output().skip_binder();
1221 if self.generic_arg_contains_target(output.into()) {
1222 let body = self.infcx.tcx.hir().body(body);
1223 let should_wrap_expr = if matches!(body.value.kind, ExprKind::Block(..)) {
1226 Some(body.value.span.shrink_to_hi())
1228 self.update_infer_source(InferSource {
1230 kind: InferSourceKind::ClosureReturn {
1232 data: &fn_decl.output,
1240 let has_impl_trait = |def_id| {
1241 iter::successors(Some(tcx.generics_of(def_id)), |generics| {
1242 generics.parent.map(|def_id| tcx.generics_of(def_id))
1244 .any(|generics| generics.has_impl_trait())
1246 if let ExprKind::MethodCall(path, receiver, args, span) = expr.kind
1247 && let Some(substs) = self.node_substs_opt(expr.hir_id)
1248 && substs.iter().any(|arg| self.generic_arg_contains_target(arg))
1249 && let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id)
1250 && self.infcx.tcx.trait_of_item(def_id).is_some()
1251 && !has_impl_trait(def_id)
1254 args.get(0).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo()));
1255 let substs = self.infcx.resolve_vars_if_possible(substs);
1256 self.update_infer_source(InferSource {
1257 span: path.ident.span,
1258 kind: InferSourceKind::FullyQualifiedMethodCall {