Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add suggestion for impl_candidates with E0283 #81042

Merged
merged 2 commits into from
Jan 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
body_id: Option<hir::BodyId>,
span: Span,
arg: GenericArg<'tcx>,
impl_candidates: Vec<ty::TraitRef<'tcx>>,
error_code: TypeAnnotationNeeded,
) -> DiagnosticBuilder<'tcx> {
let arg = self.resolve_vars_if_possible(arg);
Expand Down Expand Up @@ -653,7 +654,44 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
};
err.span_label(pattern.span, msg);
} else if let Some(e) = local_visitor.found_method_call {
if let ExprKind::MethodCall(segment, ..) = &e.kind {
if let ExprKind::MethodCall(segment, _, exprs, _) = &e.kind {
// Suggest impl candidates:
//
// error[E0283]: type annotations needed
// --> $DIR/E0283.rs:35:24
// |
// LL | let bar = foo_impl.into() * 1u32;
// | ---------^^^^--
// | | |
// | | cannot infer type for type parameter `T` declared on the trait `Into`
// | this method call resolves to `T`
// | help: specify type like: `<Impl as Into<u32>>::into(foo_impl)`
// |
// = note: cannot satisfy `Impl: Into<_>`
if !impl_candidates.is_empty() && e.span.contains(span) {
if let Some(expr) = exprs.first() {
if let ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind {
if let [path_segment] = &path.segments[..] {
let candidate_len = impl_candidates.len();
let suggestions = impl_candidates.iter().map(|candidate| {
format!(
"{}::{}({})",
candidate, segment.ident, path_segment.ident
)
});
err.span_suggestions(
e.span,
&format!(
"use the fully qualified path for the potential candidate{}",
pluralize!(candidate_len),
),
suggestions,
Applicability::MaybeIncorrect,
);
}
}
};
}
// Suggest specifying type params or point out the return type of the call:
//
// error[E0282]: type annotations needed
Expand Down
18 changes: 13 additions & 5 deletions compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1498,11 +1498,18 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
// check upstream for type errors and don't add the obligations to
// begin with in those cases.
if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0282).emit();
self.emit_inference_failure_err(body_id, span, subst, vec![], ErrorCode::E0282)
.emit();
return;
}
let mut err =
self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0283);
let impl_candidates = self.find_similar_impl_candidates(trait_ref);
let mut err = self.emit_inference_failure_err(
body_id,
span,
subst,
impl_candidates,
ErrorCode::E0283,
);
err.note(&format!("cannot satisfy `{}`", predicate));
if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code {
self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
Expand Down Expand Up @@ -1566,7 +1573,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
return;
}

self.emit_inference_failure_err(body_id, span, arg, ErrorCode::E0282)
self.emit_inference_failure_err(body_id, span, arg, vec![], ErrorCode::E0282)
}

ty::PredicateKind::Subtype(data) => {
Expand All @@ -1577,7 +1584,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
let SubtypePredicate { a_is_expected: _, a, b } = data;
// both must be type variables, or the other would've been instantiated
assert!(a.is_ty_var() && b.is_ty_var());
self.emit_inference_failure_err(body_id, span, a.into(), ErrorCode::E0282)
self.emit_inference_failure_err(body_id, span, a.into(), vec![], ErrorCode::E0282)
}
ty::PredicateKind::Projection(data) => {
let trait_ref = bound_predicate.rebind(data).to_poly_trait_ref(self.tcx);
Expand All @@ -1592,6 +1599,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
body_id,
span,
self_ty.into(),
vec![],
ErrorCode::E0284,
);
err.note(&format!("cannot satisfy `{}`", predicate));
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1479,7 +1479,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty
} else {
if !self.is_tainted_by_errors() {
self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282)
self.emit_inference_failure_err((**self).body_id, sp, ty.into(), vec![], E0282)
.note("type must be known at this point")
.emit();
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_typeck/src/check/writeback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
Some(self.body.id()),
self.span.to_span(self.tcx),
t.into(),
vec![],
E0282,
)
.emit();
Expand All @@ -707,6 +708,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
Some(self.body.id()),
self.span.to_span(self.tcx),
c.into(),
vec![],
E0282,
)
.emit();
Expand Down
18 changes: 18 additions & 0 deletions src/test/ui/error-codes/E0283.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,18 @@ impl Generator for Impl {
fn create() -> u32 { 1 }
}

impl Impl {
fn new() -> Self {
Impl{}
}
}

impl Into<u32> for Impl {
fn into(self) -> u32 { 1 }
}

fn foo(bar: u32) {}

struct AnotherImpl;

impl Generator for AnotherImpl {
Expand All @@ -17,3 +29,9 @@ impl Generator for AnotherImpl {
fn main() {
let cont: u32 = Generator::create(); //~ ERROR E0283
}

fn buzz() {
let foo_impl = Impl::new();
let bar = foo_impl.into() * 1u32; //~ ERROR E0283
foo(bar);
}
16 changes: 14 additions & 2 deletions src/test/ui/error-codes/E0283.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0283]: type annotations needed
--> $DIR/E0283.rs:18:21
--> $DIR/E0283.rs:30:21
|
LL | fn create() -> u32;
| ------------------- required by `Generator::create`
Expand All @@ -9,6 +9,18 @@ LL | let cont: u32 = Generator::create();
|
= note: cannot satisfy `_: Generator`

error: aborting due to previous error
error[E0283]: type annotations needed
--> $DIR/E0283.rs:35:24
|
LL | let bar = foo_impl.into() * 1u32;
| ---------^^^^--
| | |
| | cannot infer type for type parameter `T` declared on the trait `Into`
| this method call resolves to `T`
| help: use the fully qualified path for the potential candidate: `<Impl as Into<u32>>::into(foo_impl)`
|
= note: cannot satisfy `Impl: Into<_>`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0283`.