From fb1fb7d2ef45760bfe133381286dc750fe51e49e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 23 Apr 2021 18:24:02 -0700 Subject: [PATCH] Tweak suggestion output --- .../rustc_typeck/src/check/method/suggest.rs | 35 +++++++++++++++---- src/test/ui/hygiene/trait_items.stderr | 3 ++ .../no-method-suggested-traits.stderr | 8 +++++ src/test/ui/issues/issue-43189.stderr | 5 +++ src/test/ui/issues/issue-56175.stderr | 10 ++++++ .../rust-2018/trait-import-suggestions.stderr | 6 ++++ .../ui/shadowed/shadowed-trait-methods.stderr | 3 ++ .../import-trait-for-method-call.stderr | 13 +------ src/test/ui/traits/item-privacy.stderr | 3 ++ 9 files changed, 67 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 47e4e1223ff18..73e35f0171aa7 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -988,6 +988,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut alt_rcvr_sugg = false; if let SelfSource::MethodCall(rcvr) = source { debug!(?span, ?item_name, ?rcvr_ty, ?rcvr); + let skippable = [ + 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(), + ]; // 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. @@ -996,6 +1002,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (self.tcx.mk_mut_ref(&ty::ReErased, rcvr_ty), "&mut "), (self.tcx.mk_imm_ref(&ty::ReErased, rcvr_ty), "&"), ] { + if let Ok(pick) = 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.span, + &format!("the method is available for `{}` here", rcvr_ty), + ); + } + 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"), @@ -1015,13 +1042,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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); + let skip = skippable.contains(&did); // Make sure the method is defined for the *actual* receiver: we don't // want to treat `Box` as a receiver if it only works because of // an autoderef to `&self` diff --git a/src/test/ui/hygiene/trait_items.stderr b/src/test/ui/hygiene/trait_items.stderr index d24336883e963..2913a955dce1b 100644 --- a/src/test/ui/hygiene/trait_items.stderr +++ b/src/test/ui/hygiene/trait_items.stderr @@ -1,6 +1,9 @@ error[E0599]: no method named `f` found for unit type `()` in the current scope --> $DIR/trait_items.rs:17:24 | +LL | fn f(&self) {} + | - the method is available for `()` here +... LL | fn f() { ::baz::m!(); } | ------------ in this macro invocation ... diff --git a/src/test/ui/impl-trait/no-method-suggested-traits.stderr b/src/test/ui/impl-trait/no-method-suggested-traits.stderr index 64ddcb81c0a9b..b993115502fd5 100644 --- a/src/test/ui/impl-trait/no-method-suggested-traits.stderr +++ b/src/test/ui/impl-trait/no-method-suggested-traits.stderr @@ -37,6 +37,9 @@ LL | use no_method_suggested_traits::Reexported; error[E0599]: no method named `method` found for type `char` in the current scope --> $DIR/no-method-suggested-traits.rs:30:9 | +LL | fn method(&self) {} + | ------ the method is available for `char` here +... LL | 'a'.method(); | ^^^^^^ method not found in `char` | @@ -63,6 +66,11 @@ error[E0599]: no method named `method` found for type `i32` in the current scope | LL | 1i32.method(); | ^^^^^^ method not found in `i32` + | + ::: $DIR/auxiliary/no_method_suggested_traits.rs:8:12 + | +LL | fn method(&self) {} + | ------ the method is available for `i32` here | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: diff --git a/src/test/ui/issues/issue-43189.stderr b/src/test/ui/issues/issue-43189.stderr index 3f63cb8e78fba..3a3767c349d65 100644 --- a/src/test/ui/issues/issue-43189.stderr +++ b/src/test/ui/issues/issue-43189.stderr @@ -3,6 +3,11 @@ error[E0599]: no method named `a` found for unit type `()` in the current scope | LL | ().a(); | ^ method not found in `()` + | + ::: $DIR/auxiliary/xcrate-issue-43189-a.rs:5:8 + | +LL | fn a(&self) {} + | - the method is available for `()` here | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: diff --git a/src/test/ui/issues/issue-56175.stderr b/src/test/ui/issues/issue-56175.stderr index ee3f609f47dca..e6b0fffce663d 100644 --- a/src/test/ui/issues/issue-56175.stderr +++ b/src/test/ui/issues/issue-56175.stderr @@ -3,6 +3,11 @@ error[E0599]: no method named `trait_method` found for struct `FooStruct` in the | LL | reexported_trait::FooStruct.trait_method(); | ^^^^^^^^^^^^ method not found in `FooStruct` + | + ::: $DIR/auxiliary/reexported-trait.rs:3:12 + | +LL | fn trait_method(&self) { + | ------------ the method is available for `FooStruct` here | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: @@ -15,6 +20,11 @@ error[E0599]: no method named `trait_method_b` found for struct `FooStruct` in t | LL | reexported_trait::FooStruct.trait_method_b(); | ^^^^^^^^^^^^^^ method not found in `FooStruct` + | + ::: $DIR/auxiliary/reexported-trait.rs:7:12 + | +LL | fn trait_method_b(&self) { + | -------------- the method is available for `FooStruct` here | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: diff --git a/src/test/ui/rust-2018/trait-import-suggestions.stderr b/src/test/ui/rust-2018/trait-import-suggestions.stderr index 4b1898345a32e..2cf5a073fe5c2 100644 --- a/src/test/ui/rust-2018/trait-import-suggestions.stderr +++ b/src/test/ui/rust-2018/trait-import-suggestions.stderr @@ -1,6 +1,9 @@ error[E0599]: no method named `foobar` found for type `u32` in the current scope --> $DIR/trait-import-suggestions.rs:22:11 | +LL | fn foobar(&self) { } + | ------ the method is available for `u32` here +... LL | x.foobar(); | ^^^^^^ method not found in `u32` | @@ -11,6 +14,9 @@ LL | x.foobar(); error[E0599]: no method named `bar` found for type `u32` in the current scope --> $DIR/trait-import-suggestions.rs:28:7 | +LL | fn bar(&self) { } + | --- the method is available for `u32` here +... LL | x.bar(); | ^^^ method not found in `u32` | diff --git a/src/test/ui/shadowed/shadowed-trait-methods.stderr b/src/test/ui/shadowed/shadowed-trait-methods.stderr index 362907ecbd7ef..c3b9084affdb3 100644 --- a/src/test/ui/shadowed/shadowed-trait-methods.stderr +++ b/src/test/ui/shadowed/shadowed-trait-methods.stderr @@ -1,6 +1,9 @@ error[E0599]: no method named `f` found for unit type `()` in the current scope --> $DIR/shadowed-trait-methods.rs:13:8 | +LL | pub trait T { fn f(&self) {} } + | - the method is available for `()` here +... LL | ().f() | ^ method not found in `()` | diff --git a/src/test/ui/suggestions/import-trait-for-method-call.stderr b/src/test/ui/suggestions/import-trait-for-method-call.stderr index b6fc09cc5d0ad..f3ae20552f3d5 100644 --- a/src/test/ui/suggestions/import-trait-for-method-call.stderr +++ b/src/test/ui/suggestions/import-trait-for-method-call.stderr @@ -7,20 +7,9 @@ LL | h.finish() ::: $SRC_DIR/core/src/hash/mod.rs:LL:COL | LL | fn finish(&self) -> u64; - | ------ - | | - | the method is available for `Box` here - | the method is available for `Box<&mut DefaultHasher>` here + | ------ the method is available for `DefaultHasher` here | = help: items from traits can only be used if the trait is in scope -help: consider wrapping the receiver expression with the appropriate type - | -LL | Box::new(h).finish() - | ^^^^^^^^^ ^ -help: consider wrapping the receiver expression with the appropriate type - | -LL | Box::new(&mut h).finish() - | ^^^^^^^^^^^^^ ^ help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL | use std::hash::Hasher; diff --git a/src/test/ui/traits/item-privacy.stderr b/src/test/ui/traits/item-privacy.stderr index 68d527dc786aa..30daf8e277024 100644 --- a/src/test/ui/traits/item-privacy.stderr +++ b/src/test/ui/traits/item-privacy.stderr @@ -20,6 +20,9 @@ error[E0599]: no method named `b` found for struct `S` in the current scope LL | struct S; | --------- method `b` not found for this ... +LL | fn b(&self) { } + | - the method is available for `S` here +... LL | S.b(); | ^ method not found in `S` |