Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rollup merge of rust-lang#83689 - estebank:cool-bears-hot-tip, r=davi…
Browse files Browse the repository at this point in the history
…dtwco

Add more info for common trait resolution and async/await errors

* Suggest `Pin::new`/`Box::new`/`Arc::new`/`Box::pin` in more cases
* Point at `impl` and type defs introducing requirements on E0277
Dylan-DPC authored Mar 31, 2021

Verified

This commit was signed with the committer’s verified signature.
sandy081 Sandeep Somavarapu
2 parents cb59053 + 06b82ab commit a41cb7d
Showing 57 changed files with 677 additions and 162 deletions.
Original file line number Diff line number Diff line change
@@ -2069,7 +2069,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);
@@ -2091,11 +2098,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;
105 changes: 53 additions & 52 deletions compiler/rustc_typeck/src/check/method/suggest.rs
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
2 changes: 1 addition & 1 deletion library/core/src/marker.rs
Original file line number Diff line number Diff line change
@@ -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"]
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
@@ -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,)`

@@ -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,)`

@@ -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,)`

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
@@ -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

6 changes: 5 additions & 1 deletion src/test/ui/associated-types/issue-44153.stderr
Original file line number Diff line number Diff line change
@@ -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

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
@@ -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
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
@@ -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
|
48 changes: 48 additions & 0 deletions src/test/ui/async-await/pin-needed-to-poll-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use std::{
future::Future,
pin::Pin,
marker::Unpin,
task::{Context, Poll},
};

struct Sleep(std::marker::PhantomPinned);

impl Future for Sleep {
type Output = ();

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Poll::Ready(())
}
}

impl Drop for Sleep {
fn drop(&mut self) {}
}

fn sleep() -> Sleep {
Sleep(std::marker::PhantomPinned)
}


struct MyFuture {
sleep: Sleep,
}

impl MyFuture {
fn new() -> Self {
Self {
sleep: sleep(),
}
}
}

impl Future for MyFuture {
type Output = ();

fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Pin::new(&mut self.sleep).poll(cx)
//~^ ERROR `PhantomPinned` cannot be unpinned
}
}

fn main() {}
17 changes: 17 additions & 0 deletions src/test/ui/async-await/pin-needed-to-poll-2.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
error[E0277]: `PhantomPinned` cannot be unpinned
--> $DIR/pin-needed-to-poll-2.rs:43:9
|
LL | Pin::new(&mut self.sleep).poll(cx)
| ^^^^^^^^ within `Sleep`, the trait `Unpin` is not implemented for `PhantomPinned`
|
= note: consider using `Box::pin`
note: required because it appears within the type `Sleep`
--> $DIR/pin-needed-to-poll-2.rs:8:8
|
LL | struct Sleep(std::marker::PhantomPinned);
| ^^^^^
= note: required by `Pin::<P>::new`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
6 changes: 5 additions & 1 deletion src/test/ui/block-result/issue-22645.stderr
Original file line number Diff line number Diff line change
@@ -6,7 +6,11 @@ LL | b + 3
|
= help: the following implementations were found:
<f64 as Scalar>
= note: required because of the requirements on the impl of `Add<{integer}>` for `Bob`
note: required because of the requirements on the impl of `Add<{integer}>` for `Bob`
--> $DIR/issue-22645.rs:8:19
|
LL | impl<RHS: Scalar> Add <RHS> for Bob {
| ^^^^^^^^^ ^^^

error[E0308]: mismatched types
--> $DIR/issue-22645.rs:15:3
Original file line number Diff line number Diff line change
@@ -9,7 +9,11 @@ LL | impl <T:Sync+'static> RequiresRequiresShareAndSend for X<T> { }
LL | pub trait RequiresRequiresShareAndSend : RequiresShare + Send { }
| ---- required by this bound in `RequiresRequiresShareAndSend`
|
= note: required because it appears within the type `X<T>`
note: required because it appears within the type `X<T>`
--> $DIR/builtin-superkinds-in-metadata.rs:9:8
|
LL | struct X<T>(T);
| ^
help: consider further restricting this bound
|
LL | impl <T:Sync+'static + std::marker::Send> RequiresRequiresShareAndSend for X<T> { }
Loading

0 comments on commit a41cb7d

Please sign in to comment.