Skip to content

Commit

Permalink
diagnostics: use rustc_on_unimplemented to recommend [].iter()
Browse files Browse the repository at this point in the history
To make this work, the `#[rustc_on_unimplemented]` data needs to be used to
report method resolution errors, which is most of what this commit does.

Fixes rust-lang#94581
  • Loading branch information
notriddle committed Mar 8, 2022
1 parent d137c3a commit 81e9fad
Show file tree
Hide file tree
Showing 12 changed files with 256 additions and 161 deletions.
9 changes: 9 additions & 0 deletions compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1887,6 +1887,15 @@ impl<'tcx> Ty<'tcx> {
}
}

#[inline]
pub fn is_array_slice(self) -> bool {
match self.kind() {
Slice(_) => true,
RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => matches!(ty.kind(), Slice(_)),
_ => false,
}
}

#[inline]
pub fn is_array(self) -> bool {
matches!(self.kind(), Array(..))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::iter;

use super::InferCtxtPrivExt;

crate trait InferCtxtExt<'tcx> {
pub trait InferCtxtExt<'tcx> {
/*private*/
fn impl_similar_to(
&self,
Expand Down Expand Up @@ -202,6 +202,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
flags.push((sym::_Self, Some("{integral}".to_owned())));
}

if self_ty.is_array_slice() {
flags.push((sym::_Self, Some("&[]".to_owned())));
}

if let ty::Array(aty, len) = self_ty.kind() {
flags.push((sym::_Self, Some("[]".to_owned())));
flags.push((sym::_Self, Some(format!("[{}]", aty))));
Expand Down
349 changes: 202 additions & 147 deletions compiler/rustc_typeck/src/check/method/suggest.rs

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions library/core/src/iter/traits/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
note = "`..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant \
to have a bounded `RangeInclusive`: `0..=end`"
),
on(
_Self = "[]",
label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`"
),
on(_Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"),
on(
_Self = "&str",
label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-21596.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0599]: the method `to_string` exists for raw pointer `*const u8`, but its trait bounds were not satisfied
error[E0599]: `*const u8` doesn't implement `std::fmt::Display`
--> $DIR/issue-21596.rs:4:22
|
LL | println!("{}", z.to_string());
| ^^^^^^^^^ method cannot be called on `*const u8` due to unsatisfied trait bounds
| ^^^^^^^^^ `*const u8` cannot be formatted with the default formatter
|
= 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
Expand Down
10 changes: 5 additions & 5 deletions src/test/ui/issues/issue-31173.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut std:
LL | .collect();
| ^^^^^^^ 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
|
LL | pub struct Cloned<I> {
| -------------------- doesn't satisfy `_: Iterator`
|
::: $SRC_DIR/core/src/iter/adapters/take_while.rs:LL:COL
|
LL | pub struct TakeWhile<I, P> {
| -------------------------- doesn't satisfy `<_ as Iterator>::Item = &_`
|
::: $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL
|
LL | pub struct Cloned<I> {
| -------------------- doesn't satisfy `_: Iterator`
|
= 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`
Expand Down
7 changes: 7 additions & 0 deletions src/test/ui/methods/issues/issue-94581.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
fn get_slice() -> &'static [i32] {
&[1, 2, 3, 4]
}

fn main() {
let sqsum = get_slice().map(|i| i * i).sum(); //~ ERROR [E0599]
}
15 changes: 15 additions & 0 deletions src/test/ui/methods/issues/issue-94581.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
error[E0599]: `&'static [i32]` is not an iterator
--> $DIR/issue-94581.rs:6:29
|
LL | let sqsum = get_slice().map(|i| i * i).sum();
| ^^^ `&'static [i32]` is not an iterator; try calling `.iter()`
|
= note: the following trait bounds were not satisfied:
`&'static [i32]: Iterator`
which is required by `&mut &'static [i32]: Iterator`
`[i32]: Iterator`
which is required by `&mut [i32]: Iterator`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0599`.
2 changes: 1 addition & 1 deletion src/test/ui/methods/method-call-err-msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ fn main() {

let y = Foo;
y.zero()
.take() //~ ERROR the method
.take() //~ ERROR not an iterator
.one(0);
y.three::<usize>(); //~ ERROR this function takes 3 arguments but 0 arguments were supplied
}
4 changes: 2 additions & 2 deletions src/test/ui/methods/method-call-err-msg.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ note: associated function defined here
LL | fn two(self, _: isize, _: isize) -> Foo { self }
| ^^^ ---- -------- --------

error[E0599]: the method `take` exists for struct `Foo`, but its trait bounds were not satisfied
error[E0599]: `Foo` is not an iterator
--> $DIR/method-call-err-msg.rs:19:7
|
LL | pub struct Foo;
Expand All @@ -50,7 +50,7 @@ LL | pub struct Foo;
| doesn't satisfy `Foo: Iterator`
...
LL | .take()
| ^^^^ method cannot be called on `Foo` due to unsatisfied trait bounds
| ^^^^ `Foo` is not an iterator
|
= note: the following trait bounds were not satisfied:
`Foo: Iterator`
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/mismatched_types/issue-36053-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
use std::iter::once;
fn main() {
once::<&str>("str").fuse().filter(|a: &str| true).count();
//~^ ERROR the method
//~^ ERROR not an iterator
//~| ERROR type mismatch in closure arguments
}
4 changes: 2 additions & 2 deletions src/test/ui/mismatched_types/issue-36053-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ note: required by a bound in `filter`
LL | P: FnMut(&Self::Item) -> bool,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `filter`

error[E0599]: the method `count` exists for struct `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>`, but its trait bounds were not satisfied
error[E0599]: `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` is not an iterator
--> $DIR/issue-36053-2.rs:7:55
|
LL | once::<&str>("str").fuse().filter(|a: &str| true).count();
| -------------- ^^^^^ method cannot be called on `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` due to unsatisfied trait bounds
| -------------- ^^^^^ `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` is not an iterator
| |
| doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool`
| doesn't satisfy `_: FnMut<(&&str,)>`
Expand Down

0 comments on commit 81e9fad

Please sign in to comment.