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

Lines changed: 62 additions & 1 deletion
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

Lines changed: 34 additions & 3 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 3 additions & 2 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 2 additions & 1 deletion
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

Lines changed: 3 additions & 3 deletions
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

Lines changed: 23 additions & 0 deletions
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() {}

0 commit comments

Comments
 (0)