1 use crate::infer
::type_variable
::TypeVariableOriginKind
;
2 use crate::infer
::InferCtxt
;
3 use rustc_errors
::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}
;
5 use rustc_hir
::def
::{DefKind, Namespace}
;
6 use rustc_hir
::def_id
::DefId
;
7 use rustc_hir
::intravisit
::{self, NestedVisitorMap, Visitor}
;
8 use rustc_hir
::{Body, Expr, ExprKind, FnRetTy, HirId, Local, MatchSource, Pat}
;
9 use rustc_middle
::hir
::map
::Map
;
10 use rustc_middle
::infer
::unify_key
::ConstVariableOriginKind
;
11 use rustc_middle
::ty
::print
::Print
;
12 use rustc_middle
::ty
::subst
::{GenericArg, GenericArgKind}
;
13 use rustc_middle
::ty
::{self, DefIdTree, InferConst, Ty, TyCtxt}
;
14 use rustc_span
::symbol
::kw
;
18 struct FindHirNodeVisitor
<'a
, 'tcx
> {
19 infcx
: &'a InferCtxt
<'a
, 'tcx
>,
20 target
: GenericArg
<'tcx
>,
22 found_node_ty
: Option
<Ty
<'tcx
>>,
23 found_local_pattern
: Option
<&'tcx Pat
<'tcx
>>,
24 found_arg_pattern
: Option
<&'tcx Pat
<'tcx
>>,
25 found_closure
: Option
<&'tcx Expr
<'tcx
>>,
26 found_method_call
: Option
<&'tcx Expr
<'tcx
>>,
27 found_exact_method_call
: Option
<&'tcx Expr
<'tcx
>>,
28 found_for_loop_iter
: Option
<&'tcx Expr
<'tcx
>>,
29 found_use_diagnostic
: Option
<UseDiagnostic
<'tcx
>>,
32 impl<'a
, 'tcx
> FindHirNodeVisitor
<'a
, 'tcx
> {
33 fn new(infcx
: &'a InferCtxt
<'a
, 'tcx
>, target
: GenericArg
<'tcx
>, target_span
: Span
) -> Self {
39 found_local_pattern
: None
,
40 found_arg_pattern
: None
,
42 found_method_call
: None
,
43 found_exact_method_call
: None
,
44 found_for_loop_iter
: None
,
45 found_use_diagnostic
: None
,
49 fn node_type_opt(&self, hir_id
: HirId
) -> Option
<Ty
<'tcx
>> {
50 self.infcx
.in_progress_typeck_results?
.borrow().node_type_opt(hir_id
)
53 fn node_ty_contains_target(&self, hir_id
: HirId
) -> Option
<Ty
<'tcx
>> {
54 self.node_type_opt(hir_id
).map(|ty
| self.infcx
.resolve_vars_if_possible(ty
)).filter(|ty
| {
55 ty
.walk(self.infcx
.tcx
).any(|inner
| {
57 || match (inner
.unpack(), self.target
.unpack()) {
58 (GenericArgKind
::Type(inner_ty
), GenericArgKind
::Type(target_ty
)) => {
59 use ty
::{Infer, TyVar}
;
60 match (inner_ty
.kind(), target_ty
.kind()) {
61 (&Infer(TyVar(a_vid
)), &Infer(TyVar(b_vid
))) => self
66 .sub_unified(a_vid
, b_vid
),
76 /// Determine whether the expression, assumed to be the callee within a `Call`,
77 /// corresponds to the `From::from` emitted in desugaring of the `?` operator.
78 fn is_try_conversion(&self, callee
: &Expr
<'tcx
>) -> bool
{
80 .trait_def_from_hir_fn(callee
.hir_id
)
81 .map_or(false, |def_id
| self.infcx
.is_try_conversion(callee
.span
, def_id
))
85 impl<'a
, 'tcx
> Visitor
<'tcx
> for FindHirNodeVisitor
<'a
, 'tcx
> {
88 fn nested_visit_map(&mut self) -> NestedVisitorMap
<Self::Map
> {
89 NestedVisitorMap
::OnlyBodies(self.infcx
.tcx
.hir())
92 fn visit_local(&mut self, local
: &'tcx Local
<'tcx
>) {
93 if let (None
, Some(ty
)) =
94 (self.found_local_pattern
, self.node_ty_contains_target(local
.hir_id
))
96 self.found_local_pattern
= Some(&*local
.pat
);
97 self.found_node_ty
= Some(ty
);
99 intravisit
::walk_local(self, local
);
102 fn visit_body(&mut self, body
: &'tcx Body
<'tcx
>) {
103 for param
in body
.params
{
104 if let (None
, Some(ty
)) =
105 (self.found_arg_pattern
, self.node_ty_contains_target(param
.hir_id
))
107 self.found_arg_pattern
= Some(&*param
.pat
);
108 self.found_node_ty
= Some(ty
);
111 intravisit
::walk_body(self, body
);
114 fn visit_expr(&mut self, expr
: &'tcx Expr
<'tcx
>) {
115 if let ExprKind
::Match(scrutinee
, [_
, arm
], MatchSource
::ForLoopDesugar
) = expr
.kind
{
116 if let Some(pat
) = arm
.pat
.for_loop_some() {
117 if let Some(ty
) = self.node_ty_contains_target(pat
.hir_id
) {
118 self.found_for_loop_iter
= Some(scrutinee
);
119 self.found_node_ty
= Some(ty
);
124 if let ExprKind
::MethodCall(_
, call_span
, exprs
, _
) = expr
.kind
{
125 if call_span
== self.target_span
127 == self.infcx
.in_progress_typeck_results
.and_then(|typeck_results
| {
130 .node_type_opt(exprs
.first().unwrap().hir_id
)
134 self.found_exact_method_call
= Some(&expr
);
139 // FIXME(const_generics): Currently, any uninferred `const` generics arguments
140 // are handled specially, but instead they should be handled in `annotate_method_call`,
141 // which currently doesn't work because this evaluates to `false` for const arguments.
142 // See https://github.com/rust-lang/rust/pull/77758 for more details.
143 if let Some(ty
) = self.node_ty_contains_target(expr
.hir_id
) {
145 ExprKind
::Closure(..) => self.found_closure
= Some(&expr
),
146 ExprKind
::MethodCall(..) => self.found_method_call
= Some(&expr
),
148 // If the given expression falls within the target span and is a
149 // `From::from(e)` call emitted during desugaring of the `?` operator,
150 // extract the types inferred before and after the call
151 ExprKind
::Call(callee
, [arg
])
152 if self.target_span
.contains(expr
.span
)
153 && self.found_use_diagnostic
.is_none()
154 && self.is_try_conversion(callee
) =>
156 self.found_use_diagnostic
= self.node_type_opt(arg
.hir_id
).map(|pre_ty
| {
157 UseDiagnostic
::TryConversion { pre_ty, post_ty: ty, span: callee.span }
163 intravisit
::walk_expr(self, expr
);
167 /// An observation about the use site of a type to be emitted as an additional
168 /// note in an inference failure error.
169 enum UseDiagnostic
<'tcx
> {
170 /// Records the types inferred before and after `From::from` is called on the
171 /// error value within the desugaring of the `?` operator.
172 TryConversion { pre_ty: Ty<'tcx>, post_ty: Ty<'tcx>, span: Span }
,
175 impl UseDiagnostic
<'_
> {
176 /// Return a descriptor of the value at the use site
177 fn descr(&self) -> &'
static str {
179 Self::TryConversion { .. }
=> "error for `?` operator",
183 /// Return a descriptor of the type at the use site
184 fn type_descr(&self) -> &'
static str {
186 Self::TryConversion { .. }
=> "error type for `?` operator",
190 fn applies_to(&self, span
: Span
) -> bool
{
192 // In some cases the span for an inference failure due to try
193 // conversion contains the antecedent expression as well as the `?`
194 Self::TryConversion { span: s, .. }
=> span
.contains(s
) && span
.hi() == s
.hi(),
198 fn attach_note(&self, err
: &mut DiagnosticBuilder
<'_
>) {
200 Self::TryConversion { pre_ty, post_ty, .. }
=> {
201 let intro
= "`?` implicitly converts the error value";
203 let msg
= match (pre_ty
.is_ty_infer(), post_ty
.is_ty_infer()) {
204 (true, true) => format
!("{} using the `From` trait", intro
),
206 format
!("{} into a type implementing `From<{}>`", intro
, pre_ty
)
209 format
!("{} into `{}` using the `From` trait", intro
, post_ty
)
213 "{} into `{}` using its implementation of `From<{}>`",
214 intro
, post_ty
, pre_ty
225 /// Suggest giving an appropriate return type to a closure expression.
226 fn closure_return_type_suggestion(
227 err
: &mut DiagnosticBuilder
<'_
>,
228 output
: &FnRetTy
<'_
>,
232 let (arrow
, post
) = match output
{
233 FnRetTy
::DefaultReturn(_
) => ("-> ", " "),
236 let suggestion
= match body
.value
.kind
{
237 ExprKind
::Block(..) => vec
![(output
.span(), format
!("{}{}{}", arrow
, ret
, post
))],
239 (output
.span(), format
!("{}{}{}{{ ", arrow
, ret
, post
)),
240 (body
.value
.span
.shrink_to_hi(), " }".to_string()),
243 err
.multipart_suggestion(
244 "give this closure an explicit return type without `_` placeholders",
246 Applicability
::HasPlaceholders
,
250 /// Given a closure signature, return a `String` containing a list of all its argument types.
251 fn closure_args(fn_sig
: &ty
::PolyFnSig
<'_
>) -> String
{
257 .map(|args
| args
.tuple_fields().map(|arg
| arg
.to_string()).collect
::<Vec
<_
>>().join(", "))
261 pub enum TypeAnnotationNeeded
{
262 /// ```compile_fail,E0282
263 /// let x = "hello".chars().rev().collect();
266 /// An implementation cannot be chosen unambiguously because of lack of information.
267 /// ```compile_fail,E0283
268 /// let _ = Default::default();
271 /// ```compile_fail,E0284
272 /// let mut d: u64 = 2;
273 /// d = d % 1u32.into();
278 impl Into
<rustc_errors
::DiagnosticId
> for TypeAnnotationNeeded
{
279 fn into(self) -> rustc_errors
::DiagnosticId
{
281 Self::E0282
=> rustc_errors
::error_code
!(E0282
),
282 Self::E0283
=> rustc_errors
::error_code
!(E0283
),
283 Self::E0284
=> rustc_errors
::error_code
!(E0284
),
288 /// Information about a constant or a type containing inference variables.
289 pub struct InferenceDiagnosticsData
{
291 pub span
: Option
<Span
>,
292 pub kind
: UnderspecifiedArgKind
,
293 pub parent
: Option
<InferenceDiagnosticsParentData
>,
296 /// Data on the parent definition where a generic argument was declared.
297 pub struct InferenceDiagnosticsParentData
{
298 pub prefix
: &'
static str,
303 pub enum UnderspecifiedArgKind
{
304 Type { prefix: Cow<'static, str> }
,
305 Const { is_parameter: bool }
,
308 impl InferenceDiagnosticsData
{
309 /// Generate a label for a generic argument which can't be inferred. When not
310 /// much is known about the argument, `use_diag` may be used to describe the
312 fn cannot_infer_msg(&self, use_diag
: Option
<&UseDiagnostic
<'_
>>) -> String
{
313 if self.name
== "_" && matches
!(self.kind
, UnderspecifiedArgKind
::Type { .. }
) {
314 if let Some(use_diag
) = use_diag
{
315 return format
!("cannot infer type of {}", use_diag
.descr());
318 return "cannot infer type".to_string();
321 let suffix
= match (&self.parent
, use_diag
) {
322 (Some(parent
), _
) => format
!(" declared on the {} `{}`", parent
.prefix
, parent
.name
),
323 (None
, Some(use_diag
)) => format
!(" in {}", use_diag
.type_descr()),
324 (None
, None
) => String
::new(),
327 // For example: "cannot infer type for type parameter `T`"
328 format
!("cannot infer {} `{}`{}", self.kind
.prefix_string(), self.name
, suffix
)
332 impl InferenceDiagnosticsParentData
{
333 fn for_def_id(tcx
: TyCtxt
<'_
>, def_id
: DefId
) -> Option
<InferenceDiagnosticsParentData
> {
334 let parent_def_id
= tcx
.parent(def_id
)?
;
337 tcx
.def_key(parent_def_id
).disambiguated_data
.data
.get_opt_name()?
.to_string();
339 Some(InferenceDiagnosticsParentData
{
340 prefix
: tcx
.def_kind(parent_def_id
).descr(parent_def_id
),
342 def_id
: parent_def_id
,
347 impl UnderspecifiedArgKind
{
348 fn prefix_string(&self) -> Cow
<'
static, str> {
350 Self::Type { prefix }
=> format
!("type for {}", prefix
).into(),
351 Self::Const { is_parameter: true }
=> "the value of const parameter".into(),
352 Self::Const { is_parameter: false }
=> "the value of the constant".into(),
357 impl<'a
, 'tcx
> InferCtxt
<'a
, 'tcx
> {
358 /// Extracts data used by diagnostic for either types or constants
359 /// which were stuck during inference.
360 pub fn extract_inference_diagnostics_data(
362 arg
: GenericArg
<'tcx
>,
363 highlight
: Option
<ty
::print
::RegionHighlightMode
>,
364 ) -> InferenceDiagnosticsData
{
366 GenericArgKind
::Type(ty
) => {
367 if let ty
::Infer(ty
::TyVar(ty_vid
)) = *ty
.kind() {
368 let mut inner
= self.inner
.borrow_mut();
369 let ty_vars
= &inner
.type_variables();
370 let var_origin
= ty_vars
.var_origin(ty_vid
);
371 if let TypeVariableOriginKind
::TypeParameterDefinition(name
, def_id
) =
374 if name
!= kw
::SelfUpper
{
375 return InferenceDiagnosticsData
{
376 name
: name
.to_string(),
377 span
: Some(var_origin
.span
),
378 kind
: UnderspecifiedArgKind
::Type
{
379 prefix
: "type parameter".into(),
381 parent
: def_id
.and_then(|def_id
| {
382 InferenceDiagnosticsParentData
::for_def_id(self.tcx
, def_id
)
389 let mut s
= String
::new();
390 let mut printer
= ty
::print
::FmtPrinter
::new(self.tcx
, &mut s
, Namespace
::TypeNS
);
391 if let Some(highlight
) = highlight
{
392 printer
.region_highlight_mode
= highlight
;
394 let _
= ty
.print(printer
);
395 InferenceDiagnosticsData
{
398 kind
: UnderspecifiedArgKind
::Type { prefix: ty.prefix_string(self.tcx) }
,
402 GenericArgKind
::Const(ct
) => {
403 if let ty
::ConstKind
::Infer(InferConst
::Var(vid
)) = ct
.val
{
405 self.inner
.borrow_mut().const_unification_table().probe_value(vid
).origin
;
406 if let ConstVariableOriginKind
::ConstParameterDefinition(name
, def_id
) =
409 return InferenceDiagnosticsData
{
410 name
: name
.to_string(),
411 span
: Some(origin
.span
),
412 kind
: UnderspecifiedArgKind
::Const { is_parameter: true }
,
413 parent
: InferenceDiagnosticsParentData
::for_def_id(self.tcx
, def_id
),
417 debug_assert
!(!origin
.span
.is_dummy());
418 let mut s
= String
::new();
420 ty
::print
::FmtPrinter
::new(self.tcx
, &mut s
, Namespace
::ValueNS
);
421 if let Some(highlight
) = highlight
{
422 printer
.region_highlight_mode
= highlight
;
424 let _
= ct
.print(printer
);
425 InferenceDiagnosticsData
{
427 span
: Some(origin
.span
),
428 kind
: UnderspecifiedArgKind
::Const { is_parameter: false }
,
432 bug
!("unexpect const: {:?}", ct
);
435 GenericArgKind
::Lifetime(_
) => bug
!("unexpected lifetime"),
439 pub fn emit_inference_failure_err(
441 body_id
: Option
<hir
::BodyId
>,
443 arg
: GenericArg
<'tcx
>,
444 impl_candidates
: Vec
<ty
::TraitRef
<'tcx
>>,
445 error_code
: TypeAnnotationNeeded
,
446 ) -> DiagnosticBuilder
<'tcx
> {
447 let arg
= self.resolve_vars_if_possible(arg
);
448 let arg_data
= self.extract_inference_diagnostics_data(arg
, None
);
450 let mut local_visitor
= FindHirNodeVisitor
::new(&self, arg
, span
);
451 let ty_to_string
= |ty
: Ty
<'tcx
>| -> String
{
452 let mut s
= String
::new();
453 let mut printer
= ty
::print
::FmtPrinter
::new(self.tcx
, &mut s
, Namespace
::TypeNS
);
454 let mut inner
= self.inner
.borrow_mut();
455 let ty_vars
= inner
.type_variables();
456 let getter
= move |ty_vid
| {
457 let var_origin
= ty_vars
.var_origin(ty_vid
);
458 if let TypeVariableOriginKind
::TypeParameterDefinition(name
, _
) = var_origin
.kind
{
459 return Some(name
.to_string());
463 printer
.name_resolver
= Some(Box
::new(&getter
));
464 let _
= if let ty
::FnDef(..) = ty
.kind() {
465 // We don't want the regular output for `fn`s because it includes its path in
466 // invalid pseudo-syntax, we want the `fn`-pointer output instead.
467 ty
.fn_sig(self.tcx
).print(printer
)
474 if let Some(body_id
) = body_id
{
475 let expr
= self.tcx
.hir().expect_expr(body_id
.hir_id
);
476 local_visitor
.visit_expr(expr
);
478 let err_span
= if let Some(pattern
) = local_visitor
.found_arg_pattern
{
480 } else if let Some(span
) = arg_data
.span
{
481 // `span` here lets us point at `sum` instead of the entire right hand side expr:
482 // error[E0282]: type annotations needed
485 // 3 | let _ = x.sum() as f64;
486 // | ^^^ cannot infer type for `S`
488 } else if let Some(ExprKind
::MethodCall(_
, call_span
, _
, _
)) =
489 local_visitor
.found_method_call
.map(|e
| &e
.kind
)
491 // Point at the call instead of the whole expression:
492 // error[E0284]: type annotations needed
495 // 2 | vec![Ok(2)].into_iter().collect()?;
496 // | ^^^^^^^ cannot infer type
498 // = note: cannot resolve `<_ as std::ops::Try>::Ok == _`
499 if span
.contains(*call_span
) { *call_span }
else { span }
504 let is_named_and_not_impl_trait
=
505 |ty
: Ty
<'_
>| &ty
.to_string() != "_" && !ty
.is_impl_trait();
507 let ty_msg
= match (local_visitor
.found_node_ty
, local_visitor
.found_exact_method_call
) {
508 (_
, Some(_
)) => String
::new(),
509 (Some(ty
), _
) if ty
.is_closure() => {
511 if let ty
::Closure(_
, substs
) = *ty
.kind() { substs }
else { unreachable!() }
;
512 let fn_sig
= substs
.as_closure().sig();
513 let args
= closure_args(&fn_sig
);
514 let ret
= fn_sig
.output().skip_binder().to_string();
515 format
!(" for the closure `fn({}) -> {}`", args
, ret
)
517 (Some(ty
), _
) if is_named_and_not_impl_trait(ty
) => {
518 let ty
= ty_to_string(ty
);
519 format
!(" for `{}`", ty
)
524 // When `arg_data.name` corresponds to a type argument, show the path of the full type we're
525 // trying to infer. In the following example, `ty_msg` contains
526 // " for `std::result::Result<i32, E>`":
528 // error[E0282]: type annotations needed for `std::result::Result<i32, E>`
531 // L | let b = Ok(4);
532 // | - ^^ cannot infer type for `E` in `std::result::Result<i32, E>`
534 // | consider giving `b` the explicit type `std::result::Result<i32, E>`, where
535 // | the type parameter `E` is specified
537 let error_code
= error_code
.into();
538 let mut err
= self.tcx
.sess
.struct_span_err_with_code(
540 &format
!("type annotations needed{}", ty_msg
),
544 let use_diag
= local_visitor
.found_use_diagnostic
.as_ref();
545 if let Some(use_diag
) = use_diag
{
546 if use_diag
.applies_to(err_span
) {
547 use_diag
.attach_note(&mut err
);
551 let suffix
= match local_visitor
.found_node_ty
{
552 Some(ty
) if ty
.is_closure() => {
554 if let ty
::Closure(_
, substs
) = *ty
.kind() { substs }
else { unreachable!() }
;
555 let fn_sig
= substs
.as_closure().sig();
556 let ret
= fn_sig
.output().skip_binder().to_string();
558 let closure_decl_and_body_id
=
559 local_visitor
.found_closure
.and_then(|closure
| match &closure
.kind
{
560 ExprKind
::Closure(_
, decl
, body_id
, ..) => Some((decl
, *body_id
)),
564 if let Some((decl
, body_id
)) = closure_decl_and_body_id
{
565 closure_return_type_suggestion(
568 self.tcx
.hir().body(body_id
),
571 // We don't want to give the other suggestions when the problem is the
572 // closure return type.
575 arg_data
.cannot_infer_msg(use_diag
.filter(|d
| d
.applies_to(span
))),
580 // This shouldn't be reachable, but just in case we leave a reasonable fallback.
581 let args
= closure_args(&fn_sig
);
582 // This suggestion is incomplete, as the user will get further type inference
583 // errors due to the `_` placeholders and the introduction of `Box`, but it does
584 // nudge them in the right direction.
585 format
!("a boxed closure type like `Box<dyn Fn({}) -> {}>`", args
, ret
)
587 Some(ty
) if is_named_and_not_impl_trait(ty
) && arg_data
.name
== "_" => {
588 let ty
= ty_to_string(ty
);
589 format
!("the explicit type `{}`, with the type parameters specified", ty
)
591 Some(ty
) if is_named_and_not_impl_trait(ty
) && ty
.to_string() != arg_data
.name
=> {
592 let ty
= ty_to_string(ty
);
594 "the explicit type `{}`, where the type parameter `{}` is specified",
598 _
=> "a type".to_string(),
601 if let Some(e
) = local_visitor
.found_exact_method_call
{
602 if let ExprKind
::MethodCall(segment
, ..) = &e
.kind
{
603 // Suggest specifying type params or point out the return type of the call:
605 // error[E0282]: type annotations needed
606 // --> $DIR/type-annotations-needed-expr.rs:2:39
608 // LL | let _ = x.into_iter().sum() as f64;
611 // | cannot infer type for `S`
612 // | help: consider specifying the type argument in
613 // | the method call: `sum::<S>`
615 // = note: type must be known at this point
619 // error[E0282]: type annotations needed
620 // --> $DIR/issue-65611.rs:59:20
622 // LL | let x = buffer.last().unwrap().0.clone();
625 // | | cannot infer type for `T`
626 // | this method call resolves to `std::option::Option<&T>`
628 // = note: type must be known at this point
629 self.annotate_method_call(segment
, e
, &mut err
);
631 } else if let Some(pattern
) = local_visitor
.found_arg_pattern
{
632 // We don't want to show the default label for closures.
634 // So, before clearing, the output would look something like this:
637 // - ^^^^ cannot infer type for `[_; 0]`
639 // consider giving this closure parameter a type
642 // After clearing, it looks something like this:
645 // ^ consider giving this closure parameter the type `[_; 0]`
646 // with the type parameter `_` specified
650 format
!("consider giving this closure parameter {}", suffix
),
652 } else if let Some(pattern
) = local_visitor
.found_local_pattern
{
653 let msg
= if let Some(simple_ident
) = pattern
.simple_ident() {
654 match pattern
.span
.desugaring_kind() {
655 None
=> format
!("consider giving `{}` {}", simple_ident
, suffix
),
656 Some(_
) => format
!("this needs {}", suffix
),
659 format
!("consider giving this pattern {}", suffix
)
661 err
.span_label(pattern
.span
, msg
);
662 } else if let Some(e
) = local_visitor
.found_method_call
{
663 if let ExprKind
::MethodCall(segment
, _
, exprs
, _
) = &e
.kind
{
664 // Suggest impl candidates:
666 // error[E0283]: type annotations needed
667 // --> $DIR/E0283.rs:35:24
669 // LL | let bar = foo_impl.into() * 1u32;
672 // | | cannot infer type for type parameter `T` declared on the trait `Into`
673 // | this method call resolves to `T`
674 // | help: specify type like: `<Impl as Into<u32>>::into(foo_impl)`
676 // = note: cannot satisfy `Impl: Into<_>`
677 if !impl_candidates
.is_empty() && e
.span
.contains(span
) {
678 if let Some(expr
) = exprs
.first() {
679 if let ExprKind
::Path(hir
::QPath
::Resolved(_
, path
)) = expr
.kind
{
680 if let [path_segment
] = path
.segments
{
681 let candidate_len
= impl_candidates
.len();
682 let suggestions
= impl_candidates
.iter().map(|candidate
| {
685 candidate
, segment
.ident
, path_segment
.ident
688 err
.span_suggestions(
691 "use the fully qualified path for the potential candidate{}",
692 pluralize
!(candidate_len
),
695 Applicability
::MaybeIncorrect
,
701 // Suggest specifying type params or point out the return type of the call:
703 // error[E0282]: type annotations needed
704 // --> $DIR/type-annotations-needed-expr.rs:2:39
706 // LL | let _ = x.into_iter().sum() as f64;
709 // | cannot infer type for `S`
710 // | help: consider specifying the type argument in
711 // | the method call: `sum::<S>`
713 // = note: type must be known at this point
717 // error[E0282]: type annotations needed
718 // --> $DIR/issue-65611.rs:59:20
720 // LL | let x = buffer.last().unwrap().0.clone();
723 // | | cannot infer type for `T`
724 // | this method call resolves to `std::option::Option<&T>`
726 // = note: type must be known at this point
727 self.annotate_method_call(segment
, e
, &mut err
);
729 } else if let Some(scrutinee
) = local_visitor
.found_for_loop_iter
{
732 "the element type for this iterator is not specified".to_string(),
735 // Instead of the following:
736 // error[E0282]: type annotations needed
739 // 3 | let _ = x.sum() as f64;
740 // | --^^^--------- cannot infer type for `S`
742 // = note: type must be known at this point
744 // error[E0282]: type annotations needed
747 // 3 | let _ = x.sum() as f64;
748 // | ^^^ cannot infer type for `S`
750 // = note: type must be known at this point
751 let span
= arg_data
.span
.unwrap_or(err_span
);
753 // Avoid multiple labels pointing at `span`.
758 .any(|span_label
| span_label
.label
.is_some() && span_label
.span
== span
)
759 && local_visitor
.found_arg_pattern
.is_none()
761 // FIXME(const_generics): we would like to handle const arguments
762 // as part of the normal diagnostics flow below, but there appear to
763 // be subtleties in doing so, so for now we special-case const args
765 if let (UnderspecifiedArgKind
::Const { .. }
, Some(parent_data
)) =
766 (&arg_data
.kind
, &arg_data
.parent
)
768 // (#83606): Do not emit a suggestion if the parent has an `impl Trait`
769 // as an argument otherwise it will cause the E0282 error.
770 if !self.tcx
.generics_of(parent_data
.def_id
).has_impl_trait()
771 || self.tcx
.features().explicit_generic_args_with_impl_trait
773 err
.span_suggestion_verbose(
775 "consider specifying the const argument",
776 format
!("{}::<{}>", parent_data
.name
, arg_data
.name
),
777 Applicability
::MaybeIncorrect
,
784 arg_data
.cannot_infer_msg(use_diag
.filter(|d
| d
.applies_to(span
))),
791 fn trait_def_from_hir_fn(&self, hir_id
: hir
::HirId
) -> Option
<DefId
> {
792 // The DefId will be the method's trait item ID unless this is an inherent impl
793 if let Some((DefKind
::AssocFn
, def_id
)) =
794 self.in_progress_typeck_results?
.borrow().type_dependent_def(hir_id
)
799 .filter(|&parent_def_id
| self.tcx
.is_trait(parent_def_id
));
805 /// If the `FnSig` for the method call can be found and type arguments are identified as
806 /// needed, suggest annotating the call, otherwise point out the resulting type of the call.
807 fn annotate_method_call(
809 segment
: &hir
::PathSegment
<'_
>,
811 err
: &mut DiagnosticBuilder
<'_
>,
813 if let (Some(typeck_results
), None
) = (self.in_progress_typeck_results
, &segment
.args
) {
814 let borrow
= typeck_results
.borrow();
815 if let Some((DefKind
::AssocFn
, did
)) = borrow
.type_dependent_def(e
.hir_id
) {
816 let generics
= self.tcx
.generics_of(did
);
817 if !generics
.params
.is_empty() && !generics
.has_impl_trait() {
818 err
.span_suggestion_verbose(
819 segment
.ident
.span
.shrink_to_hi(),
821 "consider specifying the type argument{} in the method call",
822 pluralize
!(generics
.params
.len()),
829 .map(|p
| p
.name
.to_string())
830 .collect
::<Vec
<String
>>()
833 Applicability
::HasPlaceholders
,
836 let sig
= self.tcx
.fn_sig(did
);
837 let bound_output
= sig
.output();
838 let output
= bound_output
.skip_binder();
839 err
.span_label(e
.span
, &format
!("this method call resolves to `{}`", output
));
840 let kind
= output
.kind();
841 if let ty
::Projection(proj
) = kind
{
842 if let Some(span
) = self.tcx
.hir().span_if_local(proj
.item_def_id
) {
843 err
.span_label(span
, &format
!("`{}` defined here", output
));
851 pub fn need_type_info_err_in_generator(
853 kind
: hir
::GeneratorKind
,
856 ) -> DiagnosticBuilder
<'tcx
> {
857 let ty
= self.resolve_vars_if_possible(ty
);
858 let data
= self.extract_inference_diagnostics_data(ty
.into(), None
);
860 let mut err
= struct_span_err
!(
864 "type inside {} must be known in this context",
867 err
.span_label(span
, data
.cannot_infer_msg(None
));