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 more info for common trait resolution and async/await errors #83689

Merged
merged 6 commits into from
Apr 8, 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
Original file line number Diff line number Diff line change
Expand Up @@ -2070,7 +2070,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {

// Don't print the tuple of capture types
if !is_upvar_tys_infer_tuple {
err.note(&format!("required because it appears within the type `{}`", ty));
let msg = format!("required because it appears within the type `{}`", ty);
match ty.kind() {
ty::Adt(def, _) => match self.tcx.opt_item_name(def.did) {
Some(ident) => err.span_note(ident.span, &msg),
None => err.note(&msg),
},
_ => err.note(&msg),
};
}

obligated_types.push(ty);
Expand All @@ -2092,11 +2099,36 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
ObligationCauseCode::ImplDerivedObligation(ref data) => {
let mut parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
let parent_def_id = parent_trait_ref.def_id();
err.note(&format!(
let msg = format!(
"required because of the requirements on the impl of `{}` for `{}`",
parent_trait_ref.print_only_trait_path(),
parent_trait_ref.skip_binder().self_ty()
));
);
let mut candidates = vec![];
self.tcx.for_each_relevant_impl(
parent_def_id,
parent_trait_ref.self_ty().skip_binder(),
|impl_def_id| {
candidates.push(impl_def_id);
},
);
match &candidates[..] {
[def_id] => match self.tcx.hir().get_if_local(*def_id) {
Some(Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
..
})) => {
let mut spans = Vec::with_capacity(2);
if let Some(trait_ref) = of_trait {
spans.push(trait_ref.path.span);
}
spans.push(self_ty.span);
err.span_note(spans, &msg)
}
_ => err.note(&msg),
},
_ => err.note(&msg),
};

let mut parent_predicate = parent_trait_ref.without_const().to_predicate(tcx);
let mut data = data;
Expand Down Expand Up @@ -2147,19 +2179,60 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
)
});
}
ObligationCauseCode::CompareImplMethodObligation { .. } => {
err.note(&format!(
"the requirement `{}` appears on the impl method but not on the corresponding \
trait method",
predicate
));
ObligationCauseCode::CompareImplMethodObligation {
item_name,
trait_item_def_id,
..
} => {
let msg = format!(
"the requirement `{}` appears on the impl method `{}` but not on the \
corresponding trait method",
predicate, item_name,
);
let sp = self
.tcx
.opt_item_name(trait_item_def_id)
.map(|i| i.span)
.unwrap_or_else(|| self.tcx.def_span(trait_item_def_id));
let mut assoc_span: MultiSpan = sp.into();
assoc_span.push_span_label(
sp,
format!("this trait method doesn't have the requirement `{}`", predicate),
);
if let Some(ident) = self
.tcx
.opt_associated_item(trait_item_def_id)
.and_then(|i| self.tcx.opt_item_name(i.container.id()))
{
assoc_span.push_span_label(ident.span, "in this trait".into());
}
err.span_note(assoc_span, &msg);
}
ObligationCauseCode::CompareImplTypeObligation { .. } => {
err.note(&format!(
"the requirement `{}` appears on the associated impl type but not on the \
ObligationCauseCode::CompareImplTypeObligation {
item_name, trait_item_def_id, ..
} => {
let msg = format!(
"the requirement `{}` appears on the associated impl type `{}` but not on the \
corresponding associated trait type",
predicate
));
predicate, item_name,
);
let sp = self.tcx.def_span(trait_item_def_id);
let mut assoc_span: MultiSpan = sp.into();
assoc_span.push_span_label(
sp,
format!(
"this trait associated type doesn't have the requirement `{}`",
predicate,
),
);
if let Some(ident) = self
.tcx
.opt_associated_item(trait_item_def_id)
.and_then(|i| self.tcx.opt_item_name(i.container.id()))
{
assoc_span.push_span_label(ident.span, "in this trait".into());
}
err.span_note(assoc_span, &msg);
}
ObligationCauseCode::CompareImplConstObligation => {
err.note(&format!(
Expand Down
105 changes: 53 additions & 52 deletions compiler/rustc_typeck/src/check/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -987,59 +987,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
let mut alt_rcvr_sugg = false;
if let SelfSource::MethodCall(rcvr) = source {
info!(?span, ?item_name, ?rcvr_ty, ?rcvr);
if let ty::Adt(..) = rcvr_ty.kind() {
// Try alternative arbitrary self types that could fulfill this call.
// FIXME: probe for all types that *could* be arbitrary self-types, not
// just this list.
for (rcvr_ty, post) in &[
(rcvr_ty, ""),
(self.tcx.mk_mut_ref(&ty::ReErased, rcvr_ty), "&mut "),
(self.tcx.mk_imm_ref(&ty::ReErased, rcvr_ty), "&"),
debug!(?span, ?item_name, ?rcvr_ty, ?rcvr);
// Try alternative arbitrary self types that could fulfill this call.
// FIXME: probe for all types that *could* be arbitrary self-types, not
// just this list.
for (rcvr_ty, post) in &[
(rcvr_ty, ""),
(self.tcx.mk_mut_ref(&ty::ReErased, rcvr_ty), "&mut "),
(self.tcx.mk_imm_ref(&ty::ReErased, rcvr_ty), "&"),
] {
for (rcvr_ty, pre) in &[
(self.tcx.mk_lang_item(rcvr_ty, LangItem::OwnedBox), "Box::new"),
(self.tcx.mk_lang_item(rcvr_ty, LangItem::Pin), "Pin::new"),
(self.tcx.mk_diagnostic_item(rcvr_ty, sym::Arc), "Arc::new"),
(self.tcx.mk_diagnostic_item(rcvr_ty, sym::Rc), "Rc::new"),
] {
for (rcvr_ty, pre) in &[
(self.tcx.mk_lang_item(rcvr_ty, LangItem::OwnedBox), "Box::new"),
(self.tcx.mk_lang_item(rcvr_ty, LangItem::Pin), "Pin::new"),
(self.tcx.mk_diagnostic_item(rcvr_ty, sym::Arc), "Arc::new"),
(self.tcx.mk_diagnostic_item(rcvr_ty, sym::Rc), "Rc::new"),
] {
if let Some(new_rcvr_t) = *rcvr_ty {
if let Ok(pick) = self.lookup_probe(
span,
item_name,
new_rcvr_t,
rcvr,
crate::check::method::probe::ProbeScope::AllTraits,
) {
debug!("try_alt_rcvr: pick candidate {:?}", pick);
// Make sure the method is defined for the *actual* receiver:
// we don't want to treat `Box<Self>` as a receiver if
// it only works because of an autoderef to `&self`
if pick.autoderefs == 0
// We don't want to suggest a container type when the missing method is
// `.clone()`, otherwise we'd suggest `Arc::new(foo).clone()`, which is
// far from what the user really wants.
&& Some(pick.item.container.id()) != self.tcx.lang_items().clone_trait()
{
err.span_label(
pick.item.ident.span,
&format!(
"the method is available for `{}` here",
new_rcvr_t
),
);
err.multipart_suggestion(
"consider wrapping the receiver expression with the \
appropriate type",
vec![
(rcvr.span.shrink_to_lo(), format!("{}({}", pre, post)),
(rcvr.span.shrink_to_hi(), ")".to_string()),
],
Applicability::MaybeIncorrect,
);
// We don't care about the other suggestions.
alt_rcvr_sugg = true;
}
if let Some(new_rcvr_t) = *rcvr_ty {
if let Ok(pick) = self.lookup_probe(
span,
item_name,
new_rcvr_t,
rcvr,
crate::check::method::probe::ProbeScope::AllTraits,
) {
debug!("try_alt_rcvr: pick candidate {:?}", pick);
let did = Some(pick.item.container.id());
// We don't want to suggest a container type when the missing
// method is `.clone()` or `.deref()` otherwise we'd suggest
// `Arc::new(foo).clone()`, which is far from what the user wants.
let skip = [
self.tcx.lang_items().clone_trait(),
self.tcx.lang_items().deref_trait(),
self.tcx.lang_items().deref_mut_trait(),
self.tcx.lang_items().drop_trait(),
]
.contains(&did);
// Make sure the method is defined for the *actual* receiver: we don't
// want to treat `Box<Self>` as a receiver if it only works because of
// an autoderef to `&self`
if pick.autoderefs == 0 && !skip {
err.span_label(
pick.item.ident.span,
&format!("the method is available for `{}` here", new_rcvr_t),
);
err.multipart_suggestion(
"consider wrapping the receiver expression with the \
appropriate type",
vec![
(rcvr.span.shrink_to_lo(), format!("{}({}", pre, post)),
(rcvr.span.shrink_to_hi(), ")".to_string()),
],
Applicability::MaybeIncorrect,
);
// We don't care about the other suggestions.
alt_rcvr_sugg = true;
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,7 @@ unsafe impl<T: ?Sized> Freeze for &mut T {}
/// [`pin` module]: crate::pin
#[stable(feature = "pin", since = "1.33.0")]
#[rustc_on_unimplemented(
on(_Self = "std::future::Future", note = "consider using `Box::pin`",),
note = "consider using `Box::pin`",
message = "`{Self}` cannot be unpinned"
)]
#[lang = "unpin"]
Expand Down
18 changes: 15 additions & 3 deletions src/test/ui/associated-types/impl-wf-cycle-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ LL | |
LL | | }
| |_^
|
= note: required because of the requirements on the impl of `Grault` for `(T,)`
note: required because of the requirements on the impl of `Grault` for `(T,)`
--> $DIR/impl-wf-cycle-1.rs:15:17
|
LL | impl<T: Grault> Grault for (T,)
| ^^^^^^ ^^^^
= note: 1 redundant requirements hidden
= note: required because of the requirements on the impl of `Grault` for `(T,)`

Expand All @@ -20,7 +24,11 @@ error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
LL | type A = ();
| ^^^^^^^^^^^^
|
= note: required because of the requirements on the impl of `Grault` for `(T,)`
note: required because of the requirements on the impl of `Grault` for `(T,)`
--> $DIR/impl-wf-cycle-1.rs:15:17
|
LL | impl<T: Grault> Grault for (T,)
| ^^^^^^ ^^^^
= note: 1 redundant requirements hidden
= note: required because of the requirements on the impl of `Grault` for `(T,)`

Expand All @@ -30,7 +38,11 @@ error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
LL | type B = bool;
| ^^^^^^^^^^^^^^
|
= note: required because of the requirements on the impl of `Grault` for `(T,)`
note: required because of the requirements on the impl of `Grault` for `(T,)`
--> $DIR/impl-wf-cycle-1.rs:15:17
|
LL | impl<T: Grault> Grault for (T,)
| ^^^^^^ ^^^^
= note: 1 redundant requirements hidden
= note: required because of the requirements on the impl of `Grault` for `(T,)`

Expand Down
12 changes: 10 additions & 2 deletions src/test/ui/associated-types/impl-wf-cycle-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,23 @@ LL | |
LL | | }
| |_^
|
= note: required because of the requirements on the impl of `Grault` for `(T,)`
note: required because of the requirements on the impl of `Grault` for `(T,)`
--> $DIR/impl-wf-cycle-2.rs:7:17
|
LL | impl<T: Grault> Grault for (T,)
| ^^^^^^ ^^^^

error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
--> $DIR/impl-wf-cycle-2.rs:11:5
|
LL | type A = ();
| ^^^^^^^^^^^^
|
= note: required because of the requirements on the impl of `Grault` for `(T,)`
note: required because of the requirements on the impl of `Grault` for `(T,)`
--> $DIR/impl-wf-cycle-2.rs:7:17
|
LL | impl<T: Grault> Grault for (T,)
| ^^^^^^ ^^^^

error: aborting due to 2 previous errors

Expand Down
6 changes: 5 additions & 1 deletion src/test/ui/associated-types/issue-44153.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ LL | fn visit() {}
LL | <() as Visit>::visit();
| ^^^^^^^^^^^^^^^^^^^^ expected `&()`, found `()`
|
= note: required because of the requirements on the impl of `Visit` for `()`
note: required because of the requirements on the impl of `Visit` for `()`
--> $DIR/issue-44153.rs:13:10
|
LL | impl<'a> Visit for () where
| ^^^^^ ^^

error: aborting due to previous error

Expand Down
6 changes: 5 additions & 1 deletion src/test/ui/associated-types/issue-65774-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ error[E0277]: the trait bound `T: MyDisplay` is not satisfied
LL | let closure = |config: &mut <S as MPU>::MpuConfig| writer.my_write(&config);
| ^^^^^^^ the trait `MyDisplay` is not implemented for `T`
|
= note: required because of the requirements on the impl of `MyDisplay` for `&mut T`
note: required because of the requirements on the impl of `MyDisplay` for `&mut T`
--> $DIR/issue-65774-1.rs:5:24
|
LL | impl<'a, T: MyDisplay> MyDisplay for &'a mut T { }
| ^^^^^^^^^ ^^^^^^^^^
= note: required for the cast to the object type `dyn MyDisplay`

error: aborting due to 2 previous errors
Expand Down
6 changes: 5 additions & 1 deletion src/test/ui/async-await/issue-72590-type-error-sized.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ LL | async fn frob(self) {}
| ^^^^ doesn't have a size known at compile-time
|
= help: within `Foo`, the trait `Sized` is not implemented for `str`
= note: required because it appears within the type `Foo`
note: required because it appears within the type `Foo`
--> $DIR/issue-72590-type-error-sized.rs:5:8
|
LL | struct Foo {
| ^^^
= help: unsized fn params are gated as an unstable feature
help: function arguments must have a statically known size, borrowed types always have a known size
|
Expand Down
Loading