Skip to content

Commit

Permalink
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
  • Loading branch information
Dylan-DPC authored Mar 31, 2021
2 parents 4fdac23 + 06b82ab commit d79d6b3
Show file tree
Hide file tree
Showing 57 changed files with 677 additions and 162 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2067,7 +2067,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 @@ -2089,11 +2096,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
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
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
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 + Send> RequiresRequiresShareAndSend for X<T> { }
Expand Down
Loading

0 comments on commit d79d6b3

Please sign in to comment.