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

Avoid describing a method as 'not found' when bounds are unsatisfied #81149

Merged
merged 1 commit into from
Jan 28, 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
8 changes: 4 additions & 4 deletions compiler/rustc_errors/src/diagnostic_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,18 @@ macro_rules! forward {
});
};

// Forward pattern for &mut self -> &mut Self, with S: Into<MultiSpan>
// type parameter. No obvious way to make this more generic.
// Forward pattern for &mut self -> &mut Self, with generic parameters.
(
$(#[$attrs:meta])*
pub fn $n:ident<S: Into<MultiSpan>>(
pub fn $n:ident<$($generic:ident: $bound:path),*>(
&mut self,
$($name:ident: $ty:ty),*
$(,)?
) -> &mut Self
) => {
$(#[$attrs])*
forward_inner_docs!(concat!("See [`Diagnostic::", stringify!($n), "()`].") =>
pub fn $n<S: Into<MultiSpan>>(&mut self, $($name: $ty),*) -> &mut Self {
pub fn $n<$($generic: $bound),*>(&mut self, $($name: $ty),*) -> &mut Self {
self.0.diagnostic.$n($($name),*);
self
});
Expand Down Expand Up @@ -398,6 +397,7 @@ impl<'a> DiagnosticBuilder<'a> {
self
}

forward!(pub fn set_primary_message<M: Into<String>>(&mut self, msg: M) -> &mut Self);
forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);

Expand Down
53 changes: 34 additions & 19 deletions compiler/rustc_typeck/src/check/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}

let mut label_span_not_found = || {
if unsatisfied_predicates.is_empty() {
err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
} else {
err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
}
self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
};

// If the method name is the name of a field with a function or closure type,
// give a helping note that it has to be called as `(x.f)(...)`.
if let SelfSource::MethodCall(expr) = source {
Expand Down Expand Up @@ -501,12 +510,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let field_kind = if is_accessible { "field" } else { "private field" };
err.span_label(item_name.span, format!("{}, not a method", field_kind));
} else if lev_candidate.is_none() && static_sources.is_empty() {
err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
label_span_not_found();
}
} else {
err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
label_span_not_found();
}

if self.is_fn_ty(&rcvr_ty, span) {
Expand Down Expand Up @@ -721,10 +728,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.map(|(_, path)| path)
.collect::<Vec<_>>()
.join("\n");
let actual_prefix = actual.prefix_string();
err.set_primary_message(&format!(
"the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
));
err.note(&format!(
"the method `{}` exists but the following trait bounds were not \
satisfied:\n{}",
item_name, bound_list
"the following trait bounds were not satisfied:\n{bound_list}"
));
}
}
Expand All @@ -742,7 +751,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}

if actual.is_enum() {
// Don't emit a suggestion if we found an actual method
// that had unsatisfied trait bounds
if unsatisfied_predicates.is_empty() && actual.is_enum() {
let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
if let Some(suggestion) = lev_distance::find_best_match_for_name(
&adt_def.variants.iter().map(|s| s.ident.name).collect::<Vec<_>>(),
Expand Down Expand Up @@ -778,17 +789,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_label(span, msg);
}
} else if let Some(lev_candidate) = lev_candidate {
let def_kind = lev_candidate.kind.as_def_kind();
err.span_suggestion(
span,
&format!(
"there is {} {} with a similar name",
def_kind.article(),
def_kind.descr(lev_candidate.def_id),
),
lev_candidate.ident.to_string(),
Applicability::MaybeIncorrect,
);
// Don't emit a suggestion if we found an actual method
// that had unsatisfied trait bounds
if unsatisfied_predicates.is_empty() {
let def_kind = lev_candidate.kind.as_def_kind();
err.span_suggestion(
span,
&format!(
"there is {} {} with a similar name",
def_kind.article(),
def_kind.descr(lev_candidate.def_id),
),
lev_candidate.ident.to_string(),
Applicability::MaybeIncorrect,
);
}
}

return Some(err);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_typeck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ This API is completely unstable and subject to change.
#![feature(bool_to_option)]
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
#![feature(format_args_capture)]
#![feature(in_band_lifetimes)]
#![feature(is_sorted)]
#![feature(nll)]
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/associated-types/hr-associated-type-bound-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ where

fn main() {
1u32.f("abc");
//~^ ERROR no method named `f` found for type `u32` in the current scope
//~^ ERROR the method
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
error[E0599]: no method named `f` found for type `u32` in the current scope
error[E0599]: the method `f` exists for type `u32`, but its trait bounds were not satisfied
--> $DIR/hr-associated-type-bound-2.rs:19:10
|
LL | 1u32.f("abc");
| ^ method not found in `u32`
| ^ method cannot be called on `u32` due to unsatisfied trait bounds
|
= note: the method `f` exists but the following trait bounds were not satisfied:
= note: the following trait bounds were not satisfied:
`<u32 as X<'b>>::U: Clone`
which is required by `u32: X`

Expand Down
6 changes: 3 additions & 3 deletions src/test/ui/derives/derive-assoc-type-not-impl.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0599]: no method named `clone` found for struct `Bar<NotClone>` in the current scope
error[E0599]: the method `clone` exists for struct `Bar<NotClone>`, but its trait bounds were not satisfied
--> $DIR/derive-assoc-type-not-impl.rs:18:30
|
LL | struct Bar<T: Foo> {
Expand All @@ -11,7 +11,7 @@ LL | struct NotClone;
| ---------------- doesn't satisfy `NotClone: Clone`
...
LL | Bar::<NotClone> { x: 1 }.clone();
| ^^^^^ method not found in `Bar<NotClone>`
| ^^^^^ method cannot be called on `Bar<NotClone>` due to unsatisfied trait bounds
|
::: $SRC_DIR/core/src/clone.rs:LL:COL
|
Expand All @@ -21,7 +21,7 @@ LL | fn clone(&self) -> Self;
| the method is available for `Arc<Bar<NotClone>>` here
| the method is available for `Rc<Bar<NotClone>>` here
|
= note: the method `clone` exists but the following trait bounds were not satisfied:
= note: the following trait bounds were not satisfied:
`NotClone: Clone`
which is required by `Bar<NotClone>: Clone`
= help: items from traits can only be used if the trait is implemented and in scope
Expand Down
12 changes: 6 additions & 6 deletions src/test/ui/hrtb/issue-30786.migrate.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0599]: no method named `filterx` found for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>` in the current scope
error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>`, but its trait bounds were not satisfied
--> $DIR/issue-30786.rs:128:22
|
LL | pub struct Map<S, F> {
Expand All @@ -8,17 +8,17 @@ LL | pub struct Map<S, F> {
| doesn't satisfy `_: StreamExt`
...
LL | let filter = map.filterx(|x: &_| true);
| ^^^^^^^ method not found in `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>`
| ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>` due to unsatisfied trait bounds
|
= note: the method `filterx` exists but the following trait bounds were not satisfied:
= note: the following trait bounds were not satisfied:
`&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
which is required by `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
`&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
which is required by `&Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
`&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
which is required by `&mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`

error[E0599]: no method named `countx` found for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` in the current scope
error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>`, but its trait bounds were not satisfied
--> $DIR/issue-30786.rs:141:24
|
LL | pub struct Filter<S, F> {
Expand All @@ -28,9 +28,9 @@ LL | pub struct Filter<S, F> {
| doesn't satisfy `_: StreamExt`
...
LL | let count = filter.countx();
| ^^^^^^ method not found in `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>`
| ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` due to unsatisfied trait bounds
|
= note: the method `countx` exists but the following trait bounds were not satisfied:
= note: the following trait bounds were not satisfied:
`&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
which is required by `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
`&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
Expand Down
12 changes: 6 additions & 6 deletions src/test/ui/hrtb/issue-30786.nll.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0599]: no method named `filterx` found for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>` in the current scope
error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>`, but its trait bounds were not satisfied
--> $DIR/issue-30786.rs:128:22
|
LL | pub struct Map<S, F> {
Expand All @@ -8,17 +8,17 @@ LL | pub struct Map<S, F> {
| doesn't satisfy `_: StreamExt`
...
LL | let filter = map.filterx(|x: &_| true);
| ^^^^^^^ method not found in `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>`
| ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>` due to unsatisfied trait bounds
|
= note: the method `filterx` exists but the following trait bounds were not satisfied:
= note: the following trait bounds were not satisfied:
`&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
which is required by `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
`&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
which is required by `&Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
`&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
which is required by `&mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`

error[E0599]: no method named `countx` found for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` in the current scope
error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>`, but its trait bounds were not satisfied
--> $DIR/issue-30786.rs:141:24
|
LL | pub struct Filter<S, F> {
Expand All @@ -28,9 +28,9 @@ LL | pub struct Filter<S, F> {
| doesn't satisfy `_: StreamExt`
...
LL | let count = filter.countx();
| ^^^^^^ method not found in `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>`
| ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` due to unsatisfied trait bounds
|
= note: the method `countx` exists but the following trait bounds were not satisfied:
= note: the following trait bounds were not satisfied:
`&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
which is required by `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
`&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
Expand Down
8 changes: 4 additions & 4 deletions src/test/ui/hrtb/issue-30786.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ fn variant1() {
// guess.
let map = source.mapx(|x: &_| x);
let filter = map.filterx(|x: &_| true);
//[migrate]~^ ERROR no method named `filterx`
//[nll]~^^ ERROR no method named `filterx`
//[migrate]~^ ERROR the method
//[nll]~^^ ERROR the method
}

fn variant2() {
Expand All @@ -139,8 +139,8 @@ fn variant2() {
let map = source.mapx(identity);
let filter = map.filterx(|x: &_| true);
let count = filter.countx();
//[migrate]~^ ERROR no method named `countx`
//[nll]~^^ ERROR no method named `countx`
//[migrate]~^ ERROR the method
//[nll]~^^ ERROR the method
}

fn main() {}
6 changes: 3 additions & 3 deletions src/test/ui/issues/issue-21596.stderr
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
error[E0599]: no method named `to_string` found for raw pointer `*const u8` in the current scope
error[E0599]: the method `to_string` exists for raw pointer `*const u8`, but its trait bounds were not satisfied
--> $DIR/issue-21596.rs:4:22
|
LL | println!("{}", z.to_string());
| ^^^^^^^^^ method not found in `*const u8`
| ^^^^^^^^^ method cannot be called on `*const u8` due to unsatisfied trait bounds
|
= note: try using `<*const T>::as_ref()` to get a reference to the type behind the pointer: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref
= note: using `<*const T>::as_ref()` on a pointer which is unaligned or points to invalid or uninitialized memory is undefined behavior
= note: the method `to_string` exists but the following trait bounds were not satisfied:
= note: the following trait bounds were not satisfied:
`*const u8: std::fmt::Display`
which is required by `*const u8: ToString`

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-31173.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub fn get_tok(it: &mut IntoIter<u8>) {
//~^ ERROR type mismatch resolving
//~| expected type `u8`
//~| found reference `&_`
.collect(); //~ ERROR no method named `collect`
.collect(); //~ ERROR the method
}

fn main() {}
6 changes: 3 additions & 3 deletions src/test/ui/issues/issue-31173.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ LL | .cloned()
= note: expected type `u8`
found reference `&_`

error[E0599]: no method named `collect` found for struct `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>` in the current scope
error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>`, but its trait bounds were not satisfied
--> $DIR/issue-31173.rs:14:10
|
LL | .collect();
| ^^^^^^^ method not found in `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>`
| ^^^^^^^ method cannot be called on `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>` due to unsatisfied trait bounds
|
::: $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL
|
Expand All @@ -23,7 +23,7 @@ LL | pub struct Cloned<I> {
LL | pub struct TakeWhile<I, P> {
| -------------------------- doesn't satisfy `<_ as Iterator>::Item = &_`
|
= note: the method `collect` exists but the following trait bounds were not satisfied:
= note: the following trait bounds were not satisfied:
`<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]> as Iterator>::Item = &_`
which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>: Iterator`
`Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>: Iterator`
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-35677.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::collections::HashSet;

fn is_subset<T>(this: &HashSet<T>, other: &HashSet<T>) -> bool {
this.is_subset(other)
//~^ ERROR no method named
//~^ ERROR the method
}

fn main() {}
6 changes: 3 additions & 3 deletions src/test/ui/issues/issue-35677.stderr
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
error[E0599]: no method named `is_subset` found for reference `&HashSet<T>` in the current scope
error[E0599]: the method `is_subset` exists for reference `&HashSet<T>`, but its trait bounds were not satisfied
--> $DIR/issue-35677.rs:4:10
|
LL | this.is_subset(other)
| ^^^^^^^^^ method not found in `&HashSet<T>`
| ^^^^^^^^^ method cannot be called on `&HashSet<T>` due to unsatisfied trait bounds
|
= note: the method `is_subset` exists but the following trait bounds were not satisfied:
= note: the following trait bounds were not satisfied:
`T: Eq`
`T: Hash`

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
fn main() {
let _result = &Some(42).as_deref();
//~^ ERROR no method named `as_deref` found for enum `Option<{integer}>`
//~^ ERROR the method
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
error[E0599]: no method named `as_deref` found for enum `Option<{integer}>` in the current scope
error[E0599]: the method `as_deref` exists for enum `Option<{integer}>`, but its trait bounds were not satisfied
--> $DIR/option-as_deref.rs:2:29
|
LL | let _result = &Some(42).as_deref();
| ^^^^^^^^ help: there is an associated function with a similar name: `as_ref`
| ^^^^^^^^
|
= note: the method `as_deref` exists but the following trait bounds were not satisfied:
= note: the following trait bounds were not satisfied:
`{integer}: Deref`
`<{integer} as Deref>::Target = _`

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
fn main() {
let _result = &mut Some(42).as_deref_mut();
//~^ ERROR no method named `as_deref_mut` found for enum `Option<{integer}>`
//~^ ERROR the method
}
Loading