1 use crate::infer
::type_variable
::{TypeVariableOrigin, TypeVariableOriginKind}
;
2 use crate::infer
::InferCtxt
;
3 use rustc_errors
::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}
;
5 use rustc_hir
::def
::Res
;
6 use rustc_hir
::def
::{CtorOf, DefKind, Namespace}
;
7 use rustc_hir
::def_id
::DefId
;
8 use rustc_hir
::intravisit
::{self, Visitor}
;
9 use rustc_hir
::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource}
;
10 use rustc_middle
::hir
::nested_filter
;
11 use rustc_middle
::infer
::unify_key
::{ConstVariableOrigin, ConstVariableOriginKind}
;
12 use rustc_middle
::ty
::adjustment
::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}
;
13 use rustc_middle
::ty
::print
::{FmtPrinter, PrettyPrinter, Print, Printer}
;
14 use rustc_middle
::ty
::subst
::{GenericArg, GenericArgKind, Subst, SubstsRef}
;
15 use rustc_middle
::ty
::{self, DefIdTree, InferConst}
;
16 use rustc_middle
::ty
::{IsSuggestable, Ty, TyCtxt, TypeckResults}
;
17 use rustc_span
::symbol
::{kw, Ident}
;
18 use rustc_span
::{BytePos, Span}
;
22 pub enum TypeAnnotationNeeded
{
23 /// ```compile_fail,E0282
24 /// let x = "hello".chars().rev().collect();
27 /// An implementation cannot be chosen unambiguously because of lack of information.
28 /// ```compile_fail,E0283
29 /// let _ = Default::default();
32 /// ```compile_fail,E0284
33 /// let mut d: u64 = 2;
34 /// d = d % 1u32.into();
39 impl Into
<rustc_errors
::DiagnosticId
> for TypeAnnotationNeeded
{
40 fn into(self) -> rustc_errors
::DiagnosticId
{
42 Self::E0282
=> rustc_errors
::error_code
!(E0282
),
43 Self::E0283
=> rustc_errors
::error_code
!(E0283
),
44 Self::E0284
=> rustc_errors
::error_code
!(E0284
),
49 /// Information about a constant or a type containing inference variables.
50 pub struct InferenceDiagnosticsData
{
52 pub span
: Option
<Span
>,
53 pub kind
: UnderspecifiedArgKind
,
54 pub parent
: Option
<InferenceDiagnosticsParentData
>,
57 /// Data on the parent definition where a generic argument was declared.
58 pub struct InferenceDiagnosticsParentData
{
63 pub enum UnderspecifiedArgKind
{
64 Type { prefix: Cow<'static, str> }
,
65 Const { is_parameter: bool }
,
68 impl InferenceDiagnosticsData
{
69 /// Generate a label for a generic argument which can't be inferred. When not
70 /// much is known about the argument, `use_diag` may be used to describe the
72 fn cannot_infer_msg(&self) -> String
{
73 if self.name
== "_" && matches
!(self.kind
, UnderspecifiedArgKind
::Type { .. }
) {
74 return "cannot infer type".to_string();
77 let suffix
= match &self.parent
{
78 Some(parent
) => parent
.suffix_string(),
79 None
=> String
::new(),
82 // For example: "cannot infer type for type parameter `T`"
83 format
!("cannot infer {} `{}`{}", self.kind
.prefix_string(), self.name
, suffix
)
86 fn where_x_is_specified(&self, in_type
: Ty
<'_
>) -> String
{
87 if in_type
.is_ty_infer() {
89 } else if self.name
== "_" {
90 // FIXME: Consider specializing this message if there is a single `_`
92 ", where the placeholders `_` are specified".to_string()
94 format
!(", where the {} `{}` is specified", self.kind
.prefix_string(), self.name
)
99 impl InferenceDiagnosticsParentData
{
100 fn for_parent_def_id(
102 parent_def_id
: DefId
,
103 ) -> Option
<InferenceDiagnosticsParentData
> {
105 tcx
.def_key(parent_def_id
).disambiguated_data
.data
.get_opt_name()?
.to_string();
107 Some(InferenceDiagnosticsParentData
{
108 prefix
: tcx
.def_kind(parent_def_id
).descr(parent_def_id
),
113 fn for_def_id(tcx
: TyCtxt
<'_
>, def_id
: DefId
) -> Option
<InferenceDiagnosticsParentData
> {
114 Self::for_parent_def_id(tcx
, tcx
.parent(def_id
))
117 fn suffix_string(&self) -> String
{
118 format
!(" declared on the {} `{}`", self.prefix
, self.name
)
122 impl UnderspecifiedArgKind
{
123 fn prefix_string(&self) -> Cow
<'
static, str> {
125 Self::Type { prefix }
=> format
!("type for {}", prefix
).into(),
126 Self::Const { is_parameter: true }
=> "the value of const parameter".into(),
127 Self::Const { is_parameter: false }
=> "the value of the constant".into(),
132 fn fmt_printer
<'a
, 'tcx
>(infcx
: &'a InferCtxt
<'_
, 'tcx
>, ns
: Namespace
) -> FmtPrinter
<'a
, 'tcx
> {
133 let mut printer
= FmtPrinter
::new(infcx
.tcx
, ns
);
134 let ty_getter
= move |ty_vid
| {
135 if infcx
.probe_ty_var(ty_vid
).is_ok() {
136 warn
!("resolved ty var in error message");
138 if let TypeVariableOriginKind
::TypeParameterDefinition(name
, _
) =
139 infcx
.inner
.borrow_mut().type_variables().var_origin(ty_vid
).kind
146 printer
.ty_infer_name_resolver
= Some(Box
::new(ty_getter
));
147 let const_getter
= move |ct_vid
| {
148 if infcx
.probe_const_var(ct_vid
).is_ok() {
149 warn
!("resolved const var in error message");
151 if let ConstVariableOriginKind
::ConstParameterDefinition(name
, _
) =
152 infcx
.inner
.borrow_mut().const_unification_table().probe_value(ct_vid
).origin
.kind
159 printer
.const_infer_name_resolver
= Some(Box
::new(const_getter
));
163 fn ty_to_string
<'tcx
>(infcx
: &InferCtxt
<'_
, 'tcx
>, ty
: Ty
<'tcx
>) -> String
{
164 let printer
= fmt_printer(infcx
, Namespace
::TypeNS
);
165 let ty
= infcx
.resolve_vars_if_possible(ty
);
167 // We don't want the regular output for `fn`s because it includes its path in
168 // invalid pseudo-syntax, we want the `fn`-pointer output instead.
169 ty
::FnDef(..) => ty
.fn_sig(infcx
.tcx
).print(printer
).unwrap().into_buffer(),
170 // FIXME: The same thing for closures, but this only works when the closure
171 // does not capture anything.
173 // We do have to hide the `extern "rust-call"` ABI in that case though,
174 // which is too much of a bother for now.
175 _
=> ty
.print(printer
).unwrap().into_buffer(),
179 /// We don't want to directly use `ty_to_string` for closures as their type isn't really
180 /// something users are familar with. Directly printing the `fn_sig` of closures also
181 /// doesn't work as they actually use the "rust-call" API.
182 fn closure_as_fn_str
<'tcx
>(infcx
: &InferCtxt
<'_
, 'tcx
>, ty
: Ty
<'tcx
>) -> String
{
183 let ty
::Closure(_
, substs
) = ty
.kind() else { unreachable!() }
;
184 let fn_sig
= substs
.as_closure().sig();
193 .map(|arg
| ty_to_string(infcx
, arg
))
197 .unwrap_or_default();
198 let ret
= if fn_sig
.output().skip_binder().is_unit() {
201 format
!(" -> {}", ty_to_string(infcx
, fn_sig
.output().skip_binder()))
203 format
!("fn({}){}", args
, ret
)
206 impl<'a
, 'tcx
> InferCtxt
<'a
, 'tcx
> {
207 /// Extracts data used by diagnostic for either types or constants
208 /// which were stuck during inference.
209 pub fn extract_inference_diagnostics_data(
211 arg
: GenericArg
<'tcx
>,
212 highlight
: Option
<ty
::print
::RegionHighlightMode
<'tcx
>>,
213 ) -> InferenceDiagnosticsData
{
215 GenericArgKind
::Type(ty
) => {
216 if let ty
::Infer(ty
::TyVar(ty_vid
)) = *ty
.kind() {
217 let mut inner
= self.inner
.borrow_mut();
218 let ty_vars
= &inner
.type_variables();
219 let var_origin
= ty_vars
.var_origin(ty_vid
);
220 if let TypeVariableOriginKind
::TypeParameterDefinition(name
, def_id
) =
223 if name
!= kw
::SelfUpper
{
224 return InferenceDiagnosticsData
{
225 name
: name
.to_string(),
226 span
: Some(var_origin
.span
),
227 kind
: UnderspecifiedArgKind
::Type
{
228 prefix
: "type parameter".into(),
230 parent
: def_id
.and_then(|def_id
| {
231 InferenceDiagnosticsParentData
::for_def_id(self.tcx
, def_id
)
238 let mut printer
= ty
::print
::FmtPrinter
::new(self.tcx
, Namespace
::TypeNS
);
239 if let Some(highlight
) = highlight
{
240 printer
.region_highlight_mode
= highlight
;
242 InferenceDiagnosticsData
{
243 name
: ty
.print(printer
).unwrap().into_buffer(),
245 kind
: UnderspecifiedArgKind
::Type { prefix: ty.prefix_string(self.tcx) }
,
249 GenericArgKind
::Const(ct
) => {
250 if let ty
::ConstKind
::Infer(InferConst
::Var(vid
)) = ct
.kind() {
252 self.inner
.borrow_mut().const_unification_table().probe_value(vid
).origin
;
253 if let ConstVariableOriginKind
::ConstParameterDefinition(name
, def_id
) =
256 return InferenceDiagnosticsData
{
257 name
: name
.to_string(),
258 span
: Some(origin
.span
),
259 kind
: UnderspecifiedArgKind
::Const { is_parameter: true }
,
260 parent
: InferenceDiagnosticsParentData
::for_def_id(self.tcx
, def_id
),
264 debug_assert
!(!origin
.span
.is_dummy());
265 let mut printer
= ty
::print
::FmtPrinter
::new(self.tcx
, Namespace
::ValueNS
);
266 if let Some(highlight
) = highlight
{
267 printer
.region_highlight_mode
= highlight
;
269 InferenceDiagnosticsData
{
270 name
: ct
.print(printer
).unwrap().into_buffer(),
271 span
: Some(origin
.span
),
272 kind
: UnderspecifiedArgKind
::Const { is_parameter: false }
,
276 // If we end up here the `FindInferSourceVisitor`
277 // won't work, as its expected argument isn't an inference variable.
279 // FIXME: Ideally we should look into the generic constant
280 // to figure out which inference var is actually unresolved so that
281 // this path is unreachable.
282 let mut printer
= ty
::print
::FmtPrinter
::new(self.tcx
, Namespace
::ValueNS
);
283 if let Some(highlight
) = highlight
{
284 printer
.region_highlight_mode
= highlight
;
286 InferenceDiagnosticsData
{
287 name
: ct
.print(printer
).unwrap().into_buffer(),
289 kind
: UnderspecifiedArgKind
::Const { is_parameter: false }
,
294 GenericArgKind
::Lifetime(_
) => bug
!("unexpected lifetime"),
298 /// Used as a fallback in [InferCtxt::emit_inference_failure_err]
299 /// in case we weren't able to get a better error.
300 fn bad_inference_failure_err(
303 arg_data
: InferenceDiagnosticsData
,
304 error_code
: TypeAnnotationNeeded
,
305 ) -> DiagnosticBuilder
<'tcx
, ErrorGuaranteed
> {
306 let error_code
= error_code
.into();
308 self.tcx
.sess
.struct_span_err_with_code(span
, "type annotations needed", error_code
);
309 err
.span_label(span
, arg_data
.cannot_infer_msg());
313 pub fn emit_inference_failure_err(
315 body_id
: Option
<hir
::BodyId
>,
317 arg
: GenericArg
<'tcx
>,
318 error_code
: TypeAnnotationNeeded
,
319 should_label_span
: bool
,
320 ) -> DiagnosticBuilder
<'tcx
, ErrorGuaranteed
> {
321 let arg
= self.resolve_vars_if_possible(arg
);
322 let arg_data
= self.extract_inference_diagnostics_data(arg
, None
);
324 let Some(typeck_results
) = self.in_progress_typeck_results
else {
325 // If we don't have any typeck results we're outside
326 // of a body, so we won't be able to get better info
328 return self.bad_inference_failure_err(failure_span
, arg_data
, error_code
);
330 let typeck_results
= typeck_results
.borrow();
331 let typeck_results
= &typeck_results
;
333 let mut local_visitor
= FindInferSourceVisitor
::new(&self, typeck_results
, arg
);
334 if let Some(body_id
) = body_id
{
335 let expr
= self.tcx
.hir().expect_expr(body_id
.hir_id
);
336 local_visitor
.visit_expr(expr
);
339 let Some(InferSource { span, kind }
) = local_visitor
.infer_source
else {
340 return self.bad_inference_failure_err(failure_span
, arg_data
, error_code
)
343 let error_code
= error_code
.into();
344 let mut err
= self.tcx
.sess
.struct_span_err_with_code(
346 &format
!("type annotations needed{}", kind
.ty_msg(self)),
350 if should_label_span
&& !failure_span
.overlaps(span
) {
351 err
.span_label(failure_span
, "type must be known at this point");
355 InferSourceKind
::LetBinding { insert_span, pattern_name, ty }
=> {
356 let suggestion_msg
= if let Some(name
) = pattern_name
{
358 "consider giving `{}` an explicit type{}",
360 arg_data
.where_x_is_specified(ty
)
364 "consider giving this pattern a type{}",
365 arg_data
.where_x_is_specified(ty
)
368 err
.span_suggestion_verbose(
371 format
!(": {}", ty_to_string(self, ty
)),
372 Applicability
::HasPlaceholders
,
375 InferSourceKind
::ClosureArg { insert_span, ty }
=> {
376 err
.span_suggestion_verbose(
379 "consider giving this closure parameter an explicit type{}",
380 arg_data
.where_x_is_specified(ty
)
382 format
!(": {}", ty_to_string(self, ty
)),
383 Applicability
::HasPlaceholders
,
386 InferSourceKind
::GenericArg
{
393 let generics
= self.tcx
.generics_of(generics_def_id
);
394 let is_type
= matches
!(arg
.unpack(), GenericArgKind
::Type(_
));
396 let cannot_infer_msg
= format
!(
397 "cannot infer {} of the {} parameter `{}`{}",
398 if is_type { "type" }
else { "the value" }
,
399 if is_type { "type" }
else { "const" }
,
400 generics
.params
[argument_index
].name
,
401 // We use the `generics_def_id` here, as even when suggesting `None::<T>`,
402 // the type parameter `T` was still declared on the enum, not on the
404 InferenceDiagnosticsParentData
::for_parent_def_id(self.tcx
, generics_def_id
)
405 .map_or(String
::new(), |parent
| parent
.suffix_string()),
408 err
.span_label(span
, cannot_infer_msg
);
410 let args
= fmt_printer(self, Namespace
::TypeNS
)
411 .comma_sep(generic_args
.iter().copied().map(|arg
| {
412 if arg
.is_suggestable(self.tcx
, true) {
417 GenericArgKind
::Lifetime(_
) => bug
!("unexpected lifetime"),
418 GenericArgKind
::Type(_
) => self
419 .next_ty_var(TypeVariableOrigin
{
420 span
: rustc_span
::DUMMY_SP
,
421 kind
: TypeVariableOriginKind
::MiscVariable
,
424 GenericArgKind
::Const(arg
) => self
427 ConstVariableOrigin
{
428 span
: rustc_span
::DUMMY_SP
,
429 kind
: ConstVariableOriginKind
::MiscVariable
,
438 err
.span_suggestion_verbose(
441 "consider specifying the generic argument{}",
442 pluralize
!(generic_args
.len()),
444 format
!("::<{}>", args
),
445 Applicability
::HasPlaceholders
,
448 InferSourceKind
::FullyQualifiedMethodCall { receiver, successor, substs, def_id }
=> {
449 let printer
= fmt_printer(self, Namespace
::ValueNS
);
450 let def_path
= printer
.print_def_path(def_id
, substs
).unwrap().into_buffer();
452 // We only care about whether we have to add `&` or `&mut ` for now.
453 // This is the case if the last adjustment is a borrow and the
454 // first adjustment was not a builtin deref.
455 let adjustment
= match typeck_results
.expr_adjustments(receiver
) {
457 Adjustment { kind: Adjust::Deref(None), target: _ }
,
459 Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), target: _ }
,
463 Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)), target: _ }
,
465 AutoBorrowMutability
::Mut { .. }
=> "&mut ",
466 AutoBorrowMutability
::Not
=> "&",
471 let suggestion
= vec
![
472 (receiver
.span
.shrink_to_lo(), format
!("{def_path}({adjustment}")),
473 (receiver
.span
.shrink_to_hi().with_hi(successor
.1), successor
.0.to_string()),
475 err
.multipart_suggestion_verbose(
476 "try using a fully qualified path to specify the expected types",
478 Applicability
::HasPlaceholders
,
481 InferSourceKind
::ClosureReturn { ty, data, should_wrap_expr }
=> {
482 let ret
= ty_to_string(self, ty
);
483 let (arrow
, post
) = match data
{
484 FnRetTy
::DefaultReturn(_
) => ("-> ", " "),
487 let suggestion
= match should_wrap_expr
{
488 Some(end_span
) => vec
![
489 (data
.span(), format
!("{}{}{}{{ ", arrow
, ret
, post
)),
490 (end_span
, " }".to_string()),
492 None
=> vec
![(data
.span(), format
!("{}{}{}", arrow
, ret
, post
))],
494 err
.multipart_suggestion_verbose(
495 "try giving this closure an explicit return type",
497 Applicability
::HasPlaceholders
,
504 pub fn need_type_info_err_in_generator(
506 kind
: hir
::GeneratorKind
,
509 ) -> DiagnosticBuilder
<'tcx
, ErrorGuaranteed
> {
510 let ty
= self.resolve_vars_if_possible(ty
);
511 let data
= self.extract_inference_diagnostics_data(ty
.into(), None
);
513 let mut err
= struct_span_err
!(
517 "type inside {} must be known in this context",
520 err
.span_label(span
, data
.cannot_infer_msg());
526 struct InferSource
<'tcx
> {
528 kind
: InferSourceKind
<'tcx
>,
532 enum InferSourceKind
<'tcx
> {
535 pattern_name
: Option
<Ident
>,
544 argument_index
: usize,
545 generics_def_id
: DefId
,
547 generic_args
: &'tcx
[GenericArg
<'tcx
>],
549 FullyQualifiedMethodCall
{
550 receiver
: &'tcx Expr
<'tcx
>,
551 /// If the method has other arguments, this is ", " and the start of the first argument,
552 /// while for methods without arguments this is ")" and the end of the method call.
553 successor
: (&'
static str, BytePos
),
554 substs
: SubstsRef
<'tcx
>,
559 data
: &'tcx FnRetTy
<'tcx
>,
560 should_wrap_expr
: Option
<Span
>,
564 impl<'tcx
> InferSource
<'tcx
> {
565 fn from_expansion(&self) -> bool
{
566 let source_from_expansion
= match self.kind
{
567 InferSourceKind
::LetBinding { insert_span, .. }
568 | InferSourceKind
::ClosureArg { insert_span, .. }
569 | InferSourceKind
::GenericArg { insert_span, .. }
=> insert_span
.from_expansion(),
570 InferSourceKind
::FullyQualifiedMethodCall { receiver, .. }
=> {
571 receiver
.span
.from_expansion()
573 InferSourceKind
::ClosureReturn { data, should_wrap_expr, .. }
=> {
574 data
.span().from_expansion() || should_wrap_expr
.map_or(false, Span
::from_expansion
)
577 source_from_expansion
|| self.span
.from_expansion()
581 impl<'tcx
> InferSourceKind
<'tcx
> {
582 fn ty_msg(&self, infcx
: &InferCtxt
<'_
, 'tcx
>) -> String
{
584 InferSourceKind
::LetBinding { ty, .. }
585 | InferSourceKind
::ClosureArg { ty, .. }
586 | InferSourceKind
::ClosureReturn { ty, .. }
=> {
588 format
!(" for the closure `{}`", closure_as_fn_str(infcx
, ty
))
589 } else if !ty
.is_ty_infer() {
590 format
!(" for `{}`", ty_to_string(infcx
, ty
))
595 // FIXME: We should be able to add some additional info here.
596 InferSourceKind
::GenericArg { .. }
597 | InferSourceKind
::FullyQualifiedMethodCall { .. }
=> String
::new(),
603 struct InsertableGenericArgs
<'tcx
> {
605 substs
: SubstsRef
<'tcx
>,
606 generics_def_id
: DefId
,
610 /// A visitor which searches for the "best" spot to use in the inference error.
612 /// For this it walks over the hir body and tries to check all places where
613 /// inference variables could be bound.
615 /// While doing so, the currently best spot is stored in `infer_source`.
616 /// For details on how we rank spots, see [Self::source_cost]
617 struct FindInferSourceVisitor
<'a
, 'tcx
> {
618 infcx
: &'a InferCtxt
<'a
, 'tcx
>,
619 typeck_results
: &'a TypeckResults
<'tcx
>,
621 target
: GenericArg
<'tcx
>,
624 infer_source_cost
: usize,
625 infer_source
: Option
<InferSource
<'tcx
>>,
628 impl<'a
, 'tcx
> FindInferSourceVisitor
<'a
, 'tcx
> {
630 infcx
: &'a InferCtxt
<'a
, 'tcx
>,
631 typeck_results
: &'a TypeckResults
<'tcx
>,
632 target
: GenericArg
<'tcx
>,
634 FindInferSourceVisitor
{
641 infer_source_cost
: usize::MAX
,
646 /// Computes cost for the given source.
648 /// Sources with a small cost are prefer and should result
649 /// in a clearer and idiomatic suggestion.
650 fn source_cost(&self, source
: &InferSource
<'tcx
>) -> usize {
651 #[derive(Clone, Copy)]
652 struct CostCtxt
<'tcx
> {
655 impl<'tcx
> CostCtxt
<'tcx
> {
656 fn arg_cost(self, arg
: GenericArg
<'tcx
>) -> usize {
658 GenericArgKind
::Lifetime(_
) => 0, // erased
659 GenericArgKind
::Type(ty
) => self.ty_cost(ty
),
660 GenericArgKind
::Const(_
) => 3, // some non-zero value
663 fn ty_cost(self, ty
: Ty
<'tcx
>) -> usize {
665 ty
::Closure(..) => 1000,
666 ty
::FnDef(..) => 150,
668 ty
::Adt(def
, substs
) => {
671 .generics_of(def
.did())
672 .own_substs_no_defaults(self.tcx
, substs
)
674 .map(|&arg
| self.arg_cost(arg
))
677 ty
::Tuple(args
) => 5 + args
.iter().map(|arg
| self.ty_cost(arg
)).sum
::<usize>(),
678 ty
::Ref(_
, ty
, _
) => 2 + self.ty_cost(ty
),
685 // The sources are listed in order of preference here.
686 let tcx
= self.infcx
.tcx
;
687 let ctx
= CostCtxt { tcx }
;
688 let base_cost
= match source
.kind
{
689 InferSourceKind
::LetBinding { ty, .. }
=> ctx
.ty_cost(ty
),
690 InferSourceKind
::ClosureArg { ty, .. }
=> ctx
.ty_cost(ty
),
691 InferSourceKind
::GenericArg { def_id, generic_args, .. }
=> {
692 let variant_cost
= match tcx
.def_kind(def_id
) {
693 // `None::<u32>` and friends are ugly.
694 DefKind
::Variant
| DefKind
::Ctor(CtorOf
::Variant
, _
) => 15,
697 variant_cost
+ generic_args
.iter().map(|&arg
| ctx
.arg_cost(arg
)).sum
::<usize>()
699 InferSourceKind
::FullyQualifiedMethodCall { substs, .. }
=> {
700 20 + substs
.iter().map(|arg
| ctx
.arg_cost(arg
)).sum
::<usize>()
702 InferSourceKind
::ClosureReturn { ty, should_wrap_expr, .. }
=> {
703 30 + ctx
.ty_cost(ty
) + if should_wrap_expr
.is_some() { 10 }
else { 0 }
707 let suggestion_may_apply
= if source
.from_expansion() { 10000 }
else { 0 }
;
709 base_cost
+ suggestion_may_apply
712 /// Uses `fn source_cost` to determine whether this inference source is preferable to
713 /// previous sources. We generally prefer earlier sources.
714 #[instrument(level = "debug", skip(self))]
715 fn update_infer_source(&mut self, new_source
: InferSource
<'tcx
>) {
716 let cost
= self.source_cost(&new_source
) + self.attempt
;
719 if cost
< self.infer_source_cost
{
720 self.infer_source_cost
= cost
;
721 self.infer_source
= Some(new_source
);
725 fn node_substs_opt(&self, hir_id
: HirId
) -> Option
<SubstsRef
<'tcx
>> {
726 let substs
= self.typeck_results
.node_substs_opt(hir_id
);
727 self.infcx
.resolve_vars_if_possible(substs
)
730 fn opt_node_type(&self, hir_id
: HirId
) -> Option
<Ty
<'tcx
>> {
731 let ty
= self.typeck_results
.node_type_opt(hir_id
);
732 self.infcx
.resolve_vars_if_possible(ty
)
735 // Check whether this generic argument is the inference variable we
737 fn generic_arg_is_target(&self, arg
: GenericArg
<'tcx
>) -> bool
{
738 if arg
== self.target
{
742 match (arg
.unpack(), self.target
.unpack()) {
743 (GenericArgKind
::Type(inner_ty
), GenericArgKind
::Type(target_ty
)) => {
744 use ty
::{Infer, TyVar}
;
745 match (inner_ty
.kind(), target_ty
.kind()) {
746 (&Infer(TyVar(a_vid
)), &Infer(TyVar(b_vid
))) => {
747 self.infcx
.inner
.borrow_mut().type_variables().sub_unified(a_vid
, b_vid
)
752 (GenericArgKind
::Const(inner_ct
), GenericArgKind
::Const(target_ct
)) => {
753 use ty
::InferConst
::*;
754 match (inner_ct
.kind(), target_ct
.kind()) {
755 (ty
::ConstKind
::Infer(Var(a_vid
)), ty
::ConstKind
::Infer(Var(b_vid
))) => self
759 .const_unification_table()
760 .unioned(a_vid
, b_vid
),
768 /// Does this generic argument contain our target inference variable
769 /// in a way which can be written by the user.
770 fn generic_arg_contains_target(&self, arg
: GenericArg
<'tcx
>) -> bool
{
771 let mut walker
= arg
.walk();
772 while let Some(inner
) = walker
.next() {
773 if self.generic_arg_is_target(inner
) {
776 match inner
.unpack() {
777 GenericArgKind
::Lifetime(_
) => {}
778 GenericArgKind
::Type(ty
) => {
779 if matches
!(ty
.kind(), ty
::Opaque(..) | ty
::Closure(..) | ty
::Generator(..)) {
780 // Opaque types can't be named by the user right now.
782 // Both the generic arguments of closures and generators can
783 // also not be named. We may want to only look into the closure
784 // signature in case it has no captures, as that can be represented
785 // using `fn(T) -> R`.
787 // FIXME(type_alias_impl_trait): These opaque types
788 // can actually be named, so it would make sense to
789 // adjust this case and add a test for it.
790 walker
.skip_current_subtree();
793 GenericArgKind
::Const(ct
) => {
794 if matches
!(ct
.kind(), ty
::ConstKind
::Unevaluated(..)) {
795 // You can't write the generic arguments for
796 // unevaluated constants.
797 walker
.skip_current_subtree();
805 fn expr_inferred_subst_iter(
807 expr
: &'tcx hir
::Expr
<'tcx
>,
808 ) -> Box
<dyn Iterator
<Item
= InsertableGenericArgs
<'tcx
>> + 'a
> {
809 let tcx
= self.infcx
.tcx
;
811 hir
::ExprKind
::Path(ref path
) => {
812 if let Some(substs
) = self.node_substs_opt(expr
.hir_id
) {
813 return self.path_inferred_subst_iter(expr
.hir_id
, substs
, path
);
816 // FIXME(#98711): Ideally we would also deal with type relative
817 // paths here, even if that is quite rare.
819 // See the `need_type_info/expr-struct-type-relative-gat.rs` test
820 // for an example where that would be needed.
822 // However, the `type_dependent_def_id` for `Self::Output` in an
823 // impl is currently the `DefId` of `Output` in the trait definition
824 // which makes this somewhat difficult and prevents us from just
825 // using `self.path_inferred_subst_iter` here.
826 hir
::ExprKind
::Struct(&hir
::QPath
::Resolved(_self_ty
, path
), _
, _
) => {
827 if let Some(ty
) = self.opt_node_type(expr
.hir_id
) {
828 if let ty
::Adt(_
, substs
) = ty
.kind() {
829 return Box
::new(self.resolved_path_inferred_subst_iter(path
, substs
));
833 hir
::ExprKind
::MethodCall(segment
, _
, _
) => {
834 if let Some(def_id
) = self.typeck_results
.type_dependent_def_id(expr
.hir_id
) {
835 let generics
= tcx
.generics_of(def_id
);
836 let insertable
: Option
<_
> = try
{
837 if generics
.has_impl_trait() {
840 let substs
= self.node_substs_opt(expr
.hir_id
)?
;
841 let span
= tcx
.hir().span(segment
.hir_id?
);
842 let insert_span
= segment
.ident
.span
.shrink_to_hi().with_hi(span
.hi());
843 InsertableGenericArgs
{
846 generics_def_id
: def_id
,
850 return Box
::new(insertable
.into_iter());
856 Box
::new(iter
::empty())
859 fn resolved_path_inferred_subst_iter(
861 path
: &'tcx hir
::Path
<'tcx
>,
862 substs
: SubstsRef
<'tcx
>,
863 ) -> impl Iterator
<Item
= InsertableGenericArgs
<'tcx
>> + 'a
{
864 let tcx
= self.infcx
.tcx
;
865 // The last segment of a path often has `Res::Err` and the
866 // correct `Res` is the one of the whole path.
868 // FIXME: We deal with that one separately for now,
869 // would be good to remove this special case.
870 let last_segment_using_path_data
: Option
<_
> = try
{
871 let generics_def_id
= tcx
.res_generics_def_id(path
.res
)?
;
872 let generics
= tcx
.generics_of(generics_def_id
);
873 if generics
.has_impl_trait() {
877 path
.segments
.last().unwrap().ident
.span
.shrink_to_hi().with_hi(path
.span
.hi());
878 InsertableGenericArgs
{
882 def_id
: path
.res
.def_id(),
888 .filter_map(move |segment
| {
889 let res
= segment
.res?
;
890 let generics_def_id
= tcx
.res_generics_def_id(res
)?
;
891 let generics
= tcx
.generics_of(generics_def_id
);
892 if generics
.has_impl_trait() {
895 let span
= tcx
.hir().span(segment
.hir_id?
);
896 let insert_span
= segment
.ident
.span
.shrink_to_hi().with_hi(span
.hi());
897 Some(InsertableGenericArgs
{
901 def_id
: res
.def_id(),
904 .chain(last_segment_using_path_data
)
907 fn path_inferred_subst_iter(
910 substs
: SubstsRef
<'tcx
>,
911 qpath
: &'tcx hir
::QPath
<'tcx
>,
912 ) -> Box
<dyn Iterator
<Item
= InsertableGenericArgs
<'tcx
>> + 'a
> {
913 let tcx
= self.infcx
.tcx
;
915 hir
::QPath
::Resolved(_self_ty
, path
) => {
916 Box
::new(self.resolved_path_inferred_subst_iter(path
, substs
))
918 hir
::QPath
::TypeRelative(ty
, segment
) => {
919 let Some(def_id
) = self.typeck_results
.type_dependent_def_id(hir_id
) else {
920 return Box
::new(iter
::empty());
923 let generics
= tcx
.generics_of(def_id
);
924 let segment
: Option
<_
> = try
{
925 if !segment
.infer_args
|| generics
.has_impl_trait() {
928 let span
= tcx
.hir().span(segment
.hir_id?
);
929 let insert_span
= segment
.ident
.span
.shrink_to_hi().with_hi(span
.hi());
930 InsertableGenericArgs { insert_span, substs, generics_def_id: def_id, def_id }
933 let parent_def_id
= generics
.parent
.unwrap();
934 if tcx
.def_kind(parent_def_id
) == DefKind
::Impl
{
935 let parent_ty
= tcx
.bound_type_of(parent_def_id
).subst(tcx
, substs
);
936 match (parent_ty
.kind(), &ty
.kind
) {
938 ty
::Adt(def
, substs
),
939 hir
::TyKind
::Path(hir
::QPath
::Resolved(_self_ty
, path
)),
941 if tcx
.res_generics_def_id(path
.res
) != Some(def
.did()) {
943 Res
::Def(DefKind
::TyAlias
, _
) => {
944 // FIXME: Ideally we should support this. For that
945 // we have to map back from the self type to the
946 // type alias though. That's difficult.
948 // See the `need_type_info/type-alias.rs` test for
951 // There cannot be inference variables in the self type,
952 // so there's nothing for us to do here.
953 Res
::SelfTy { .. }
=> {}
955 "unexpected path: def={:?} substs={:?} path={:?}",
961 self.resolved_path_inferred_subst_iter(path
, substs
)
970 Box
::new(segment
.into_iter())
972 hir
::QPath
::LangItem(_
, _
, _
) => Box
::new(iter
::empty()),
977 impl<'a
, 'tcx
> Visitor
<'tcx
> for FindInferSourceVisitor
<'a
, 'tcx
> {
978 type NestedFilter
= nested_filter
::OnlyBodies
;
980 fn nested_visit_map(&mut self) -> Self::Map
{
984 fn visit_local(&mut self, local
: &'tcx Local
<'tcx
>) {
985 intravisit
::walk_local(self, local
);
987 if let Some(ty
) = self.opt_node_type(local
.hir_id
) {
988 if self.generic_arg_contains_target(ty
.into()) {
990 LocalSource
::Normal
if local
.ty
.is_none() => {
991 self.update_infer_source(InferSource
{
992 span
: local
.pat
.span
,
993 kind
: InferSourceKind
::LetBinding
{
994 insert_span
: local
.pat
.span
.shrink_to_hi(),
995 pattern_name
: local
.pat
.simple_ident(),
1006 /// For closures, we first visit the parameters and then the content,
1007 /// as we prefer those.
1008 fn visit_body(&mut self, body
: &'tcx Body
<'tcx
>) {
1009 for param
in body
.params
{
1011 "param: span {:?}, ty_span {:?}, pat.span {:?}",
1012 param
.span
, param
.ty_span
, param
.pat
.span
1014 if param
.ty_span
!= param
.pat
.span
{
1015 debug
!("skipping param: has explicit type");
1019 let Some(param_ty
) = self.opt_node_type(param
.hir_id
) else {
1023 if self.generic_arg_contains_target(param_ty
.into()) {
1024 self.update_infer_source(InferSource
{
1025 span
: param
.pat
.span
,
1026 kind
: InferSourceKind
::ClosureArg
{
1027 insert_span
: param
.pat
.span
.shrink_to_hi(),
1033 intravisit
::walk_body(self, body
);
1036 #[instrument(level = "debug", skip(self))]
1037 fn visit_expr(&mut self, expr
: &'tcx Expr
<'tcx
>) {
1038 let tcx
= self.infcx
.tcx
;
1040 // When encountering `func(arg)` first look into `arg` and then `func`,
1041 // as `arg` is "more specific".
1042 ExprKind
::Call(func
, args
) => {
1044 self.visit_expr(arg
);
1046 self.visit_expr(func
);
1048 _
=> intravisit
::walk_expr(self, expr
),
1051 for args
in self.expr_inferred_subst_iter(expr
) {
1053 let InsertableGenericArgs { insert_span, substs, generics_def_id, def_id }
= args
;
1054 let generics
= tcx
.generics_of(generics_def_id
);
1055 if let Some(argument_index
) = generics
1058 .position(|&arg
| self.generic_arg_contains_target(arg
))
1060 let substs
= self.infcx
.resolve_vars_if_possible(substs
);
1061 let generic_args
= &generics
.own_substs_no_defaults(tcx
, substs
)
1062 [generics
.own_counts().lifetimes
..];
1063 let span
= match expr
.kind
{
1064 ExprKind
::MethodCall(path
, _
, _
) => path
.ident
.span
,
1068 self.update_infer_source(InferSource
{
1070 kind
: InferSourceKind
::GenericArg
{
1081 if let Some(node_ty
) = self.opt_node_type(expr
.hir_id
) {
1083 &ExprKind
::Closure(&Closure { fn_decl, body, fn_decl_span, .. }
),
1084 ty
::Closure(_
, substs
),
1085 ) = (&expr
.kind
, node_ty
.kind())
1087 let output
= substs
.as_closure().sig().output().skip_binder();
1088 if self.generic_arg_contains_target(output
.into()) {
1089 let body
= self.infcx
.tcx
.hir().body(body
);
1090 let should_wrap_expr
= if matches
!(body
.value
.kind
, ExprKind
::Block(..)) {
1093 Some(body
.value
.span
.shrink_to_hi())
1095 self.update_infer_source(InferSource
{
1097 kind
: InferSourceKind
::ClosureReturn
{
1099 data
: &fn_decl
.output
,
1107 let has_impl_trait
= |def_id
| {
1108 iter
::successors(Some(tcx
.generics_of(def_id
)), |generics
| {
1109 generics
.parent
.map(|def_id
| tcx
.generics_of(def_id
))
1111 .any(|generics
| generics
.has_impl_trait())
1113 if let ExprKind
::MethodCall(path
, args
, span
) = expr
.kind
1114 && let Some(substs
) = self.node_substs_opt(expr
.hir_id
)
1115 && substs
.iter().any(|arg
| self.generic_arg_contains_target(arg
))
1116 && let Some(def_id
) = self.typeck_results
.type_dependent_def_id(expr
.hir_id
)
1117 && self.infcx
.tcx
.trait_of_item(def_id
).is_some()
1118 && !has_impl_trait(def_id
)
1121 args
.get(1).map_or_else(|| (")", span
.hi()), |arg
| (", ", arg
.span
.lo()));
1122 let substs
= self.infcx
.resolve_vars_if_possible(substs
);
1123 self.update_infer_source(InferSource
{
1124 span
: path
.ident
.span
,
1125 kind
: InferSourceKind
::FullyQualifiedMethodCall
{
1126 receiver
: args
.first().unwrap(),