Skip to content

Commit db95b5c

Browse files
sasurau4estebank
andcommitted
Add suggestion for impl_candidates with E0283
Update compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs Co-authored-by: Esteban Kuber <[email protected]>
1 parent 86e0ff4 commit db95b5c

File tree

4 files changed

+55
-7
lines changed

4 files changed

+55
-7
lines changed

Diff for: compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs

+39-1
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
429429
body_id: Option<hir::BodyId>,
430430
span: Span,
431431
arg: GenericArg<'tcx>,
432+
impl_candidates: Vec<ty::TraitRef<'tcx>>,
432433
error_code: TypeAnnotationNeeded,
433434
) -> DiagnosticBuilder<'tcx> {
434435
let arg = self.resolve_vars_if_possible(arg);
@@ -653,7 +654,44 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
653654
};
654655
err.span_label(pattern.span, msg);
655656
} else if let Some(e) = local_visitor.found_method_call {
656-
if let ExprKind::MethodCall(segment, ..) = &e.kind {
657+
if let ExprKind::MethodCall(segment, _, exprs, _) = &e.kind {
658+
// Suggest impl candidates:
659+
//
660+
// error[E0283]: type annotations needed
661+
// --> $DIR/E0283.rs:35:24
662+
// |
663+
// LL | let bar = foo_impl.into() * 1u32;
664+
// | ---------^^^^--
665+
// | | |
666+
// | | cannot infer type for type parameter `T` declared on the trait `Into`
667+
// | this method call resolves to `T`
668+
// | help: specify type like: `<Impl as Into<u32>>::into(foo_impl)`
669+
// |
670+
// = note: cannot satisfy `Impl: Into<_>`
671+
if !impl_candidates.is_empty() && e.span.contains(span) {
672+
if let Some(expr) = exprs.first() {
673+
if let ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind {
674+
if let [path_segment] = &path.segments[..] {
675+
let candidate_len = impl_candidates.len();
676+
let suggestions = impl_candidates.iter().map(|candidate| {
677+
format!(
678+
"{}::{}({})",
679+
candidate, segment.ident, path_segment.ident
680+
)
681+
});
682+
err.span_suggestions(
683+
e.span,
684+
&format!(
685+
"use the fully qualified path for the potential candidate{}",
686+
pluralize!(candidate_len),
687+
),
688+
suggestions,
689+
Applicability::MaybeIncorrect,
690+
);
691+
}
692+
}
693+
};
694+
}
657695
// Suggest specifying type params or point out the return type of the call:
658696
//
659697
// error[E0282]: type annotations needed

Diff for: compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -1498,11 +1498,18 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
14981498
// check upstream for type errors and don't add the obligations to
14991499
// begin with in those cases.
15001500
if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
1501-
self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0282).emit();
1501+
self.emit_inference_failure_err(body_id, span, subst, vec![], ErrorCode::E0282)
1502+
.emit();
15021503
return;
15031504
}
1504-
let mut err =
1505-
self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0283);
1505+
let impl_candidates = self.find_similar_impl_candidates(trait_ref);
1506+
let mut err = self.emit_inference_failure_err(
1507+
body_id,
1508+
span,
1509+
subst,
1510+
impl_candidates,
1511+
ErrorCode::E0283,
1512+
);
15061513
err.note(&format!("cannot satisfy `{}`", predicate));
15071514
if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code {
15081515
self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
@@ -1566,7 +1573,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
15661573
return;
15671574
}
15681575

1569-
self.emit_inference_failure_err(body_id, span, arg, ErrorCode::E0282)
1576+
self.emit_inference_failure_err(body_id, span, arg, vec![], ErrorCode::E0282)
15701577
}
15711578

15721579
ty::PredicateKind::Subtype(data) => {
@@ -1577,7 +1584,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
15771584
let SubtypePredicate { a_is_expected: _, a, b } = data;
15781585
// both must be type variables, or the other would've been instantiated
15791586
assert!(a.is_ty_var() && b.is_ty_var());
1580-
self.emit_inference_failure_err(body_id, span, a.into(), ErrorCode::E0282)
1587+
self.emit_inference_failure_err(body_id, span, a.into(), vec![], ErrorCode::E0282)
15811588
}
15821589
ty::PredicateKind::Projection(data) => {
15831590
let trait_ref = bound_predicate.rebind(data).to_poly_trait_ref(self.tcx);
@@ -1592,6 +1599,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
15921599
body_id,
15931600
span,
15941601
self_ty.into(),
1602+
vec![],
15951603
ErrorCode::E0284,
15961604
);
15971605
err.note(&format!("cannot satisfy `{}`", predicate));

Diff for: compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1479,7 +1479,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14791479
ty
14801480
} else {
14811481
if !self.is_tainted_by_errors() {
1482-
self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282)
1482+
self.emit_inference_failure_err((**self).body_id, sp, ty.into(), vec![], E0282)
14831483
.note("type must be known at this point")
14841484
.emit();
14851485
}

Diff for: compiler/rustc_typeck/src/check/writeback.rs

+2
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
694694
Some(self.body.id()),
695695
self.span.to_span(self.tcx),
696696
t.into(),
697+
vec![],
697698
E0282,
698699
)
699700
.emit();
@@ -707,6 +708,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
707708
Some(self.body.id()),
708709
self.span.to_span(self.tcx),
709710
c.into(),
711+
vec![],
710712
E0282,
711713
)
712714
.emit();

0 commit comments

Comments
 (0)