Skip to content

Commit 1dceadd

Browse files
committed
Auto merge of #54946 - estebank:iterator, r=varkor
Add filtering option to `rustc_on_unimplemented` and reword `Iterator` E0277 errors - Add more targetting filters for arrays to `rustc_on_unimplemented` (Fix #53766) - Detect one element array of `Range` type, which is potentially a typo: `for _ in [0..10] {}` where iterating between `0` and `10` was intended. (Fix #23141) - Suggest `.bytes()` and `.chars()` for `String`. - Suggest borrowing or `.iter()` on arrays (Fix #36391) - Suggest using range literal when iterating on integers (Fix #34353) - Do not suggest `.iter()` by default (Fix #50773, fix #46806) - Add regression test (Fix #22872)
2 parents cbbd70d + def0f54 commit 1dceadd

33 files changed

+559
-45
lines changed

src/libcore/iter/iterator.rs

+62-1
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,72 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item=()>) {}
3030
/// [impl]: index.html#implementing-iterator
3131
#[stable(feature = "rust1", since = "1.0.0")]
3232
#[rustc_on_unimplemented(
33+
on(
34+
_Self="[std::ops::Range<Idx>; 1]",
35+
label="if you meant to iterate between two values, remove the square brackets",
36+
note="`[start..end]` is an array of one `Range`; you might have meant to have a `Range` \
37+
without the brackets: `start..end`"
38+
),
39+
on(
40+
_Self="[std::ops::RangeFrom<Idx>; 1]",
41+
label="if you meant to iterate from a value onwards, remove the square brackets",
42+
note="`[start..]` is an array of one `RangeFrom`; you might have meant to have a \
43+
`RangeFrom` without the brackets: `start..`, keeping in mind that iterating over an \
44+
unbounded iterator will run forever unless you `break` or `return` from within the \
45+
loop"
46+
),
47+
on(
48+
_Self="[std::ops::RangeTo<Idx>; 1]",
49+
label="if you meant to iterate until a value, remove the square brackets and add a \
50+
starting value",
51+
note="`[..end]` is an array of one `RangeTo`; you might have meant to have a bounded \
52+
`Range` without the brackets: `0..end`"
53+
),
54+
on(
55+
_Self="[std::ops::RangeInclusive<Idx>; 1]",
56+
label="if you meant to iterate between two values, remove the square brackets",
57+
note="`[start..=end]` is an array of one `RangeInclusive`; you might have meant to have a \
58+
`RangeInclusive` without the brackets: `start..=end`"
59+
),
60+
on(
61+
_Self="[std::ops::RangeToInclusive<Idx>; 1]",
62+
label="if you meant to iterate until a value (including it), remove the square brackets \
63+
and add a starting value",
64+
note="`[..=end]` is an array of one `RangeToInclusive`; you might have meant to have a \
65+
bounded `RangeInclusive` without the brackets: `0..=end`"
66+
),
67+
on(
68+
_Self="std::ops::RangeTo<Idx>",
69+
label="if you meant to iterate until a value, add a starting value",
70+
note="`..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a \
71+
bounded `Range`: `0..end`"
72+
),
73+
on(
74+
_Self="std::ops::RangeToInclusive<Idx>",
75+
label="if you meant to iterate until a value (including it), add a starting value",
76+
note="`..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant \
77+
to have a bounded `RangeInclusive`: `0..=end`"
78+
),
3379
on(
3480
_Self="&str",
3581
label="`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
3682
),
37-
label="`{Self}` is not an iterator; maybe try calling `.iter()` or a similar method"
83+
on(
84+
_Self="std::string::String",
85+
label="`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
86+
),
87+
on(
88+
_Self="[]",
89+
label="borrow the array with `&` or call `.iter()` on it to iterate over it",
90+
note="arrays are not an iterators, but slices like the following are: `&[1, 2, 3]`"
91+
),
92+
on(
93+
_Self="{integral}",
94+
note="if you want to iterate between `start` until a value `end`, use the exclusive range \
95+
syntax `start..end` or the inclusive range syntax `start..=end`"
96+
),
97+
label="`{Self}` is not an iterator",
98+
message="`{Self}` is not an iterator"
3899
)]
39100
#[doc(spotlight)]
40101
pub trait Iterator {

src/librustc/traits/error_reporting.rs

+34-3
Original file line numberDiff line numberDiff line change
@@ -349,9 +349,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
349349
fn on_unimplemented_note(
350350
&self,
351351
trait_ref: ty::PolyTraitRef<'tcx>,
352-
obligation: &PredicateObligation<'tcx>) ->
353-
OnUnimplementedNote
354-
{
352+
obligation: &PredicateObligation<'tcx>,
353+
) -> OnUnimplementedNote {
355354
let def_id = self.impl_similar_to(trait_ref, obligation)
356355
.unwrap_or(trait_ref.def_id());
357356
let trait_ref = *trait_ref.skip_binder();
@@ -410,6 +409,38 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
410409
flags.push(("crate_local".to_owned(), None));
411410
}
412411

412+
// Allow targetting all integers using `{integral}`, even if the exact type was resolved
413+
if self_ty.is_integral() {
414+
flags.push(("_Self".to_owned(), Some("{integral}".to_owned())));
415+
}
416+
417+
if let ty::Array(aty, len) = self_ty.sty {
418+
flags.push(("_Self".to_owned(), Some("[]".to_owned())));
419+
flags.push(("_Self".to_owned(), Some(format!("[{}]", aty))));
420+
if let Some(def) = aty.ty_adt_def() {
421+
// We also want to be able to select the array's type's original
422+
// signature with no type arguments resolved
423+
flags.push((
424+
"_Self".to_owned(),
425+
Some(format!("[{}]", self.tcx.type_of(def.did).to_string())),
426+
));
427+
let tcx = self.tcx;
428+
if let Some(len) = len.val.try_to_scalar().and_then(|scalar| {
429+
scalar.to_usize(tcx).ok()
430+
}) {
431+
flags.push((
432+
"_Self".to_owned(),
433+
Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)),
434+
));
435+
} else {
436+
flags.push((
437+
"_Self".to_owned(),
438+
Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())),
439+
));
440+
}
441+
}
442+
}
443+
413444
if let Ok(Some(command)) = OnUnimplementedDirective::of_item(
414445
self.tcx, trait_ref.def_id, def_id
415446
) {

src/test/ui/conservative_impl_trait.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
// #39872, #39553
1212

1313
fn will_ice(something: &u32) -> impl Iterator<Item = &u32> {
14-
//~^ ERROR the trait bound `(): std::iter::Iterator` is not satisfied [E0277]
14+
//~^ ERROR `()` is not an iterator
1515
}
1616

1717
fn main() {}

src/test/ui/conservative_impl_trait.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0277]: the trait bound `(): std::iter::Iterator` is not satisfied
1+
error[E0277]: `()` is not an iterator
22
--> $DIR/conservative_impl_trait.rs:13:33
33
|
44
LL | fn will_ice(something: &u32) -> impl Iterator<Item = &u32> {
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator; maybe try calling `.iter()` or a similar method
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator
66
|
77
= help: the trait `std::iter::Iterator` is not implemented for `()`
88
= note: the return type of a function must have a statically known size

src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr

+3-2
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,16 @@ LL | | }
7575
= help: see issue #48214
7676
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
7777

78-
error[E0277]: the trait bound `i32: std::iter::Iterator` is not satisfied
78+
error[E0277]: `i32` is not an iterator
7979
--> $DIR/feature-gate-trivial_bounds.rs:50:1
8080
|
8181
LL | / fn use_for() where i32: Iterator { //~ ERROR
8282
LL | | for _ in 2i32 {}
8383
LL | | }
84-
| |_^ `i32` is not an iterator; maybe try calling `.iter()` or a similar method
84+
| |_^ `i32` is not an iterator
8585
|
8686
= help: the trait `std::iter::Iterator` is not implemented for `i32`
87+
= note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
8788
= help: see issue #48214
8889
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
8990

src/test/ui/for/for-c-in-str.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
fn main() {
1414
for c in "asdf" {
15-
//~^ ERROR the trait bound `&str: std::iter::Iterator` is not satisfied
15+
//~^ ERROR `&str` is not an iterator
1616
//~| NOTE `&str` is not an iterator
1717
//~| HELP the trait `std::iter::Iterator` is not implemented for `&str`
1818
//~| NOTE required by `std::iter::IntoIterator::into_iter`

src/test/ui/for/for-c-in-str.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0277]: the trait bound `&str: std::iter::Iterator` is not satisfied
1+
error[E0277]: `&str` is not an iterator
22
--> $DIR/for-c-in-str.rs:14:14
33
|
44
LL | for c in "asdf" {

src/test/ui/for/for-loop-bogosity.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ pub fn main() {
2424
x: 1,
2525
y: 2,
2626
};
27-
for x in bogus { //~ ERROR `MyStruct: std::iter::Iterator` is not satisfied
27+
for x in bogus {
28+
//~^ ERROR `MyStruct` is not an iterator
2829
drop(x);
2930
}
3031
}

src/test/ui/for/for-loop-bogosity.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0277]: the trait bound `MyStruct: std::iter::Iterator` is not satisfied
1+
error[E0277]: `MyStruct` is not an iterator
22
--> $DIR/for-loop-bogosity.rs:27:14
33
|
4-
LL | for x in bogus { //~ ERROR `MyStruct: std::iter::Iterator` is not satisfied
5-
| ^^^^^ `MyStruct` is not an iterator; maybe try calling `.iter()` or a similar method
4+
LL | for x in bogus {
5+
| ^^^^^ `MyStruct` is not an iterator
66
|
77
= help: the trait `std::iter::Iterator` is not implemented for `MyStruct`
88
= note: required by `std::iter::IntoIterator::into_iter`

src/test/ui/issues/issue-22872.rs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
trait Wrap<'b> {
2+
fn foo(&'b mut self);
3+
}
4+
5+
struct Wrapper<P>(P);
6+
7+
impl<'b, P> Wrap<'b> for Wrapper<P>
8+
where P: Process<'b>,
9+
<P as Process<'b>>::Item: Iterator {
10+
fn foo(&mut self) {}
11+
}
12+
13+
14+
pub trait Process<'a> {
15+
type Item;
16+
fn bar(&'a self);
17+
}
18+
19+
fn push_process<P>(process: P) where P: Process<'static> {
20+
let _: Box<for<'b> Wrap<'b>> = Box::new(Wrapper(process));
21+
}
22+
23+
fn main() {}

src/test/ui/issues/issue-22872.stderr

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0277]: the trait bound `for<'b> P: Process<'b>` is not satisfied
2+
--> $DIR/issue-22872.rs:20:36
3+
|
4+
LL | let _: Box<for<'b> Wrap<'b>> = Box::new(Wrapper(process));
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'b> Process<'b>` is not implemented for `P`
6+
|
7+
= help: consider adding a `where for<'b> P: Process<'b>` bound
8+
= note: required because of the requirements on the impl of `for<'b> Wrap<'b>` for `Wrapper<P>`
9+
= note: required for the cast to the object type `dyn for<'b> Wrap<'b>`
10+
11+
error[E0277]: `<P as Process<'b>>::Item` is not an iterator
12+
--> $DIR/issue-22872.rs:20:36
13+
|
14+
LL | let _: Box<for<'b> Wrap<'b>> = Box::new(Wrapper(process));
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ `<P as Process<'b>>::Item` is not an iterator
16+
|
17+
= help: the trait `for<'b> std::iter::Iterator` is not implemented for `<P as Process<'b>>::Item`
18+
= note: required because of the requirements on the impl of `for<'b> Wrap<'b>` for `Wrapper<P>`
19+
= note: required for the cast to the object type `dyn for<'b> Wrap<'b>`
20+
21+
error: aborting due to 2 previous errors
22+
23+
For more information about this error, try `rustc --explain E0277`.

src/test/ui/issues/issue-28098.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010

1111
fn main() {
1212
let _ = Iterator::next(&mut ());
13-
//~^ ERROR `(): std::iter::Iterator` is not satisfied
13+
//~^ ERROR `()` is not an iterator
1414

1515
for _ in false {}
16-
//~^ ERROR `bool: std::iter::Iterator` is not satisfied
16+
//~^ ERROR `bool` is not an iterator
1717

1818
let _ = Iterator::next(&mut ());
19-
//~^ ERROR `(): std::iter::Iterator` is not satisfied
19+
//~^ ERROR `()` is not an iterator
2020

2121
other()
2222
}
@@ -25,11 +25,11 @@ pub fn other() {
2525
// check errors are still reported globally
2626

2727
let _ = Iterator::next(&mut ());
28-
//~^ ERROR `(): std::iter::Iterator` is not satisfied
28+
//~^ ERROR `()` is not an iterator
2929

3030
let _ = Iterator::next(&mut ());
31-
//~^ ERROR `(): std::iter::Iterator` is not satisfied
31+
//~^ ERROR `()` is not an iterator
3232

3333
for _ in false {}
34-
//~^ ERROR `bool: std::iter::Iterator` is not satisfied
34+
//~^ ERROR `bool` is not an iterator
3535
}

src/test/ui/issues/issue-28098.stderr

+12-12
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,53 @@
1-
error[E0277]: the trait bound `(): std::iter::Iterator` is not satisfied
1+
error[E0277]: `()` is not an iterator
22
--> $DIR/issue-28098.rs:12:13
33
|
44
LL | let _ = Iterator::next(&mut ());
5-
| ^^^^^^^^^^^^^^ `()` is not an iterator; maybe try calling `.iter()` or a similar method
5+
| ^^^^^^^^^^^^^^ `()` is not an iterator
66
|
77
= help: the trait `std::iter::Iterator` is not implemented for `()`
88
= note: required by `std::iter::Iterator::next`
99

10-
error[E0277]: the trait bound `bool: std::iter::Iterator` is not satisfied
10+
error[E0277]: `bool` is not an iterator
1111
--> $DIR/issue-28098.rs:15:14
1212
|
1313
LL | for _ in false {}
14-
| ^^^^^ `bool` is not an iterator; maybe try calling `.iter()` or a similar method
14+
| ^^^^^ `bool` is not an iterator
1515
|
1616
= help: the trait `std::iter::Iterator` is not implemented for `bool`
1717
= note: required by `std::iter::IntoIterator::into_iter`
1818

19-
error[E0277]: the trait bound `(): std::iter::Iterator` is not satisfied
19+
error[E0277]: `()` is not an iterator
2020
--> $DIR/issue-28098.rs:18:13
2121
|
2222
LL | let _ = Iterator::next(&mut ());
23-
| ^^^^^^^^^^^^^^ `()` is not an iterator; maybe try calling `.iter()` or a similar method
23+
| ^^^^^^^^^^^^^^ `()` is not an iterator
2424
|
2525
= help: the trait `std::iter::Iterator` is not implemented for `()`
2626
= note: required by `std::iter::Iterator::next`
2727

28-
error[E0277]: the trait bound `(): std::iter::Iterator` is not satisfied
28+
error[E0277]: `()` is not an iterator
2929
--> $DIR/issue-28098.rs:27:13
3030
|
3131
LL | let _ = Iterator::next(&mut ());
32-
| ^^^^^^^^^^^^^^ `()` is not an iterator; maybe try calling `.iter()` or a similar method
32+
| ^^^^^^^^^^^^^^ `()` is not an iterator
3333
|
3434
= help: the trait `std::iter::Iterator` is not implemented for `()`
3535
= note: required by `std::iter::Iterator::next`
3636

37-
error[E0277]: the trait bound `(): std::iter::Iterator` is not satisfied
37+
error[E0277]: `()` is not an iterator
3838
--> $DIR/issue-28098.rs:30:13
3939
|
4040
LL | let _ = Iterator::next(&mut ());
41-
| ^^^^^^^^^^^^^^ `()` is not an iterator; maybe try calling `.iter()` or a similar method
41+
| ^^^^^^^^^^^^^^ `()` is not an iterator
4242
|
4343
= help: the trait `std::iter::Iterator` is not implemented for `()`
4444
= note: required by `std::iter::Iterator::next`
4545

46-
error[E0277]: the trait bound `bool: std::iter::Iterator` is not satisfied
46+
error[E0277]: `bool` is not an iterator
4747
--> $DIR/issue-28098.rs:33:14
4848
|
4949
LL | for _ in false {}
50-
| ^^^^^ `bool` is not an iterator; maybe try calling `.iter()` or a similar method
50+
| ^^^^^ `bool` is not an iterator
5151
|
5252
= help: the trait `std::iter::Iterator` is not implemented for `bool`
5353
= note: required by `std::iter::IntoIterator::into_iter`

src/test/ui/issues/issue-50480.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@
1212
//~^ ERROR the trait `Copy` may not be implemented for this type
1313
struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
1414
//~^ ERROR cannot find type `NotDefined` in this scope
15-
//~| ERROR the trait bound `i32: std::iter::Iterator` is not satisfied
15+
//~| ERROR `i32` is not an iterator
1616

1717
fn main() {}

src/test/ui/issues/issue-50480.stderr

+3-2
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ error[E0412]: cannot find type `NotDefined` in this scope
44
LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
55
| ^^^^^^^^^^ not found in this scope
66

7-
error[E0277]: the trait bound `i32: std::iter::Iterator` is not satisfied
7+
error[E0277]: `i32` is not an iterator
88
--> $DIR/issue-50480.rs:13:24
99
|
1010
LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
11-
| ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator; maybe try calling `.iter()` or a similar method
11+
| ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator
1212
|
1313
= help: the trait `std::iter::Iterator` is not implemented for `i32`
14+
= note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
1415

1516
error[E0204]: the trait `Copy` may not be implemented for this type
1617
--> $DIR/issue-50480.rs:11:17
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
fn main() {
2+
for _ in [0..1] {}
3+
for _ in [0..=1] {}
4+
for _ in [0..] {}
5+
for _ in [..1] {}
6+
for _ in [..=1] {}
7+
let start = 0;
8+
let end = 0;
9+
for _ in [start..end] {}
10+
let array_of_range = [start..end];
11+
for _ in array_of_range {}
12+
for _ in [0..1, 2..3] {}
13+
for _ in [0..=1] {}
14+
}

0 commit comments

Comments
 (0)