Skip to content

Commit

Permalink
Rollup merge of #94237 - compiler-errors:dont-wrap-ambiguous-receiver…
Browse files Browse the repository at this point in the history
…s, r=lcnr

Do not suggest wrapping an item if it has ambiguous un-imported methods

If the method is defined for the receiver we have, but is ambiguous during probe, then it probably comes from one of several traits that just weren't `use`d. Don't suggest wrapping the receiver in `Box`/etc., even if that makes the method probe unambiguous.

Fixes #94218
  • Loading branch information
matthiaskrgr authored Feb 22, 2022
2 parents b322382 + 0626919 commit 396910a
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 39 deletions.
37 changes: 24 additions & 13 deletions compiler/rustc_typeck/src/check/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1485,27 +1485,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(self.tcx.mk_mut_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&mut "),
(self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&"),
] {
if let Ok(pick) = self.lookup_probe(
match self.lookup_probe(
span,
item_name,
*rcvr_ty,
rcvr,
crate::check::method::probe::ProbeScope::AllTraits,
) {
// If the method is defined for the receiver we have, it likely wasn't `use`d.
// We point at the method, but we just skip the rest of the check for arbitrary
// self types and rely on the suggestion to `use` the trait from
// `suggest_valid_traits`.
let did = Some(pick.item.container.id());
let skip = skippable.contains(&did);
if pick.autoderefs == 0 && !skip {
err.span_label(
pick.item.ident(self.tcx).span,
&format!("the method is available for `{}` here", rcvr_ty),
);
Ok(pick) => {
// If the method is defined for the receiver we have, it likely wasn't `use`d.
// We point at the method, but we just skip the rest of the check for arbitrary
// self types and rely on the suggestion to `use` the trait from
// `suggest_valid_traits`.
let did = Some(pick.item.container.id());
let skip = skippable.contains(&did);
if pick.autoderefs == 0 && !skip {
err.span_label(
pick.item.ident(self.tcx).span,
&format!("the method is available for `{}` here", rcvr_ty),
);
}
break;
}
break;
Err(MethodError::Ambiguity(_)) => {
// If the method is defined (but ambiguous) for the receiver we have, it is also
// likely we haven't `use`d it. It may be possible that if we `Box`/`Pin`/etc.
// the receiver, then it might disambiguate this method, but I think these
// suggestions are generally misleading (see #94218).
break;
}
_ => {}
}

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"),
Expand Down
26 changes: 0 additions & 26 deletions src/test/ui/rust-2021/future-prelude-collision-shadow.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,8 @@ error[E0599]: no method named `try_into` found for type `u8` in the current scop
LL | let _: u32 = 3u8.try_into().unwrap();
| ^^^^^^^^ method not found in `u8`
|
::: $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn try_into(self) -> Result<T, Self::Error>;
| --------
| |
| the method is available for `Box<u8>` here
| the method is available for `Pin<u8>` here
| the method is available for `Arc<u8>` here
| the method is available for `Rc<u8>` here
|
= help: items from traits can only be used if the trait is in scope
= note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
help: consider wrapping the receiver expression with the appropriate type
|
LL | let _: u32 = Box::new(3u8).try_into().unwrap();
| +++++++++ +
help: consider wrapping the receiver expression with the appropriate type
|
LL | let _: u32 = Pin::new(3u8).try_into().unwrap();
| +++++++++ +
help: consider wrapping the receiver expression with the appropriate type
|
LL | let _: u32 = Arc::new(3u8).try_into().unwrap();
| +++++++++ +
help: consider wrapping the receiver expression with the appropriate type
|
LL | let _: u32 = Rc::new(3u8).try_into().unwrap();
| ++++++++ +
help: the following traits are implemented but not in scope; perhaps add a `use` for one of them:
|
LL | use crate::m::TryIntoU32;
Expand Down
21 changes: 21 additions & 0 deletions src/test/ui/suggestions/dont-wrap-ambiguous-receivers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
mod banana {
//~^ HELP the following traits are implemented but not in scope
pub struct Chaenomeles;

pub trait Apple {
fn pick(&self) {}
}
impl Apple for Chaenomeles {}

pub trait Peach {
fn pick(&self, a: &mut ()) {}
}
impl<Mango: Peach> Peach for Box<Mango> {}
impl Peach for Chaenomeles {}
}

fn main() {
banana::Chaenomeles.pick()
//~^ ERROR no method named
//~| HELP items from traits can only be used if the trait is in scope
}
20 changes: 20 additions & 0 deletions src/test/ui/suggestions/dont-wrap-ambiguous-receivers.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error[E0599]: no method named `pick` found for struct `Chaenomeles` in the current scope
--> $DIR/dont-wrap-ambiguous-receivers.rs:18:25
|
LL | pub struct Chaenomeles;
| ----------------------- method `pick` not found for this
...
LL | banana::Chaenomeles.pick()
| ^^^^ method not found in `Chaenomeles`
|
= help: items from traits can only be used if the trait is in scope
help: the following traits are implemented but not in scope; perhaps add a `use` for one of them:
|
LL | use banana::Apple;
|
LL | use banana::Peach;
|

error: aborting due to previous error

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

0 comments on commit 396910a

Please sign in to comment.