Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 90ac98f

Browse files
authoredJun 22, 2021
Rollup merge of rust-lang#85682 - m-ou-se:array-into-iter-2, r=nikomatsakis
Update array_into_iter lint for 1.53 and edition changes. This updates the array_into_iter lint for Rust 1.53 and the edition changes. See rust-lang#84513 r? `@estebank`
2 parents 44f4a87 + a8614bc commit 90ac98f

9 files changed

+237
-318
lines changed
 

‎compiler/rustc_lint/src/array_into_iter.rs

+55-34
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use rustc_errors::Applicability;
33
use rustc_hir as hir;
44
use rustc_middle::ty;
55
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
6-
use rustc_session::lint::FutureBreakage;
76
use rustc_span::symbol::sym;
7+
use rustc_span::Span;
88

99
declare_lint! {
1010
/// The `array_into_iter` lint detects calling `into_iter` on arrays.
@@ -20,37 +20,40 @@ declare_lint! {
2020
///
2121
/// ### Explanation
2222
///
23-
/// In the future, it is planned to add an `IntoIter` implementation for
24-
/// arrays such that it will iterate over *values* of the array instead of
25-
/// references. Due to how method resolution works, this will change
26-
/// existing code that uses `into_iter` on arrays. The solution to avoid
27-
/// this warning is to use `iter()` instead of `into_iter()`.
28-
///
29-
/// This is a [future-incompatible] lint to transition this to a hard error
30-
/// in the future. See [issue #66145] for more details and a more thorough
31-
/// description of the lint.
32-
///
33-
/// [issue #66145]: https://github.com/rust-lang/rust/issues/66145
34-
/// [future-incompatible]: ../index.md#future-incompatible-lints
23+
/// Since Rust 1.53, arrays implement `IntoIterator`. However, to avoid
24+
/// breakage, `array.into_iter()` in Rust 2015 and 2018 code will still
25+
/// behave as `(&array).into_iter()`, returning an iterator over
26+
/// references, just like in Rust 1.52 and earlier.
27+
/// This only applies to the method call syntax `array.into_iter()`, not to
28+
/// any other syntax such as `for _ in array` or `IntoIterator::into_iter(array)`.
3529
pub ARRAY_INTO_ITER,
3630
Warn,
37-
"detects calling `into_iter` on arrays",
38-
@future_incompatible = FutureIncompatibleInfo {
39-
reference: "issue #66145 <https://github.com/rust-lang/rust/issues/66145>",
40-
edition: None,
41-
future_breakage: Some(FutureBreakage {
42-
date: None
43-
})
44-
};
31+
"detects calling `into_iter` on arrays in Rust 2015 and 2018",
32+
}
33+
34+
#[derive(Copy, Clone, Default)]
35+
pub struct ArrayIntoIter {
36+
for_expr_span: Span,
4537
}
4638

47-
declare_lint_pass!(
48-
/// Checks for instances of calling `into_iter` on arrays.
49-
ArrayIntoIter => [ARRAY_INTO_ITER]
50-
);
39+
impl_lint_pass!(ArrayIntoIter => [ARRAY_INTO_ITER]);
5140

5241
impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
5342
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
43+
// Save the span of expressions in `for _ in expr` syntax,
44+
// so we can give a better suggestion for those later.
45+
if let hir::ExprKind::Match(arg, [_], hir::MatchSource::ForLoopDesugar) = &expr.kind {
46+
if let hir::ExprKind::Call(path, [arg]) = &arg.kind {
47+
if let hir::ExprKind::Path(hir::QPath::LangItem(
48+
hir::LangItem::IntoIterIntoIter,
49+
_,
50+
)) = &path.kind
51+
{
52+
self.for_expr_span = arg.span;
53+
}
54+
}
55+
}
56+
5457
// We only care about method call expressions.
5558
if let hir::ExprKind::MethodCall(call, span, args, _) = &expr.kind {
5659
if call.ident.name != sym::into_iter {
@@ -106,19 +109,37 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
106109
_ => bug!("array type coerced to something other than array or slice"),
107110
};
108111
cx.struct_span_lint(ARRAY_INTO_ITER, *span, |lint| {
109-
lint.build(&format!(
110-
"this method call currently resolves to `<&{} as IntoIterator>::into_iter` (due \
111-
to autoref coercions), but that might change in the future when \
112-
`IntoIterator` impls for arrays are added.",
113-
target,
114-
))
115-
.span_suggestion(
112+
let mut diag = lint.build(&format!(
113+
"this method call resolves to `<&{} as IntoIterator>::into_iter` \
114+
(due to backwards compatibility), \
115+
but will resolve to <{} as IntoIterator>::into_iter in Rust 2021.",
116+
target, target,
117+
));
118+
diag.span_suggestion(
116119
call.ident.span,
117120
"use `.iter()` instead of `.into_iter()` to avoid ambiguity",
118121
"iter".into(),
119122
Applicability::MachineApplicable,
120-
)
121-
.emit();
123+
);
124+
if self.for_expr_span == expr.span {
125+
let expr_span = expr.span.ctxt().outer_expn_data().call_site;
126+
diag.span_suggestion(
127+
receiver_arg.span.shrink_to_hi().to(expr_span.shrink_to_hi()),
128+
"or remove `.into_iter()` to iterate by value",
129+
String::new(),
130+
Applicability::MaybeIncorrect,
131+
);
132+
} else {
133+
diag.multipart_suggestion(
134+
"or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value",
135+
vec![
136+
(expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()),
137+
(receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), ")".into()),
138+
],
139+
Applicability::MaybeIncorrect,
140+
);
141+
}
142+
diag.emit();
122143
})
123144
}
124145
}

‎compiler/rustc_lint/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ macro_rules! late_lint_passes {
163163
// FIXME: Turn the computation of types which implement Debug into a query
164164
// and change this to a module lint pass
165165
MissingDebugImplementations: MissingDebugImplementations::default(),
166-
ArrayIntoIter: ArrayIntoIter,
166+
ArrayIntoIter: ArrayIntoIter::default(),
167167
ClashingExternDeclarations: ClashingExternDeclarations::new(),
168168
DropTraitConstraints: DropTraitConstraints,
169169
TemporaryCStringAsPtr: TemporaryCStringAsPtr,

‎src/test/ui/iterators/into-iter-on-arrays-2018.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,20 @@ fn main() {
1212
// Before 2021, the method dispatched to `IntoIterator for &[T; N]`,
1313
// which we continue to support for compatibility.
1414
let _: Iter<'_, i32> = array.into_iter();
15-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
16-
//~| WARNING this was previously accepted by the compiler but is being phased out
15+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
1716

1817
let _: Iter<'_, i32> = Box::new(array).into_iter();
19-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
20-
//~| WARNING this was previously accepted by the compiler but is being phased out
18+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
2119

2220
// The `array_into_iter` lint doesn't cover other wrappers that deref to an array.
2321
let _: Iter<'_, i32> = Rc::new(array).into_iter();
2422
let _: Iter<'_, i32> = Array(array).into_iter();
2523

2624
// But you can always use the trait method explicitly as an array.
2725
let _: IntoIter<i32, 10> = IntoIterator::into_iter(array);
26+
27+
for _ in [1, 2, 3].into_iter() {}
28+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
2829
}
2930

3031
/// User type that dereferences to an array.
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,48 @@
1-
warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
1+
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
22
--> $DIR/into-iter-on-arrays-2018.rs:14:34
33
|
44
LL | let _: Iter<'_, i32> = array.into_iter();
5-
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
5+
| ^^^^^^^^^
66
|
77
= note: `#[warn(array_into_iter)]` on by default
8-
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
9-
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
8+
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
9+
|
10+
LL | let _: Iter<'_, i32> = array.iter();
11+
| ^^^^
12+
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
13+
|
14+
LL | let _: Iter<'_, i32> = IntoIterator::into_iter(array);
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^ ^
1016

11-
warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
12-
--> $DIR/into-iter-on-arrays-2018.rs:18:44
17+
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
18+
--> $DIR/into-iter-on-arrays-2018.rs:17:44
1319
|
1420
LL | let _: Iter<'_, i32> = Box::new(array).into_iter();
15-
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
21+
| ^^^^^^^^^
1622
|
17-
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
18-
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
19-
20-
warning: 2 warnings emitted
21-
22-
Future incompatibility report: Future breakage date: None, diagnostic:
23-
warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
24-
--> $DIR/into-iter-on-arrays-2018.rs:14:34
23+
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
2524
|
26-
LL | let _: Iter<'_, i32> = array.into_iter();
27-
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
25+
LL | let _: Iter<'_, i32> = Box::new(array).iter();
26+
| ^^^^
27+
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
2828
|
29-
= note: `#[warn(array_into_iter)]` on by default
30-
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
31-
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
29+
LL | let _: Iter<'_, i32> = IntoIterator::into_iter(Box::new(array));
30+
| ^^^^^^^^^^^^^^^^^^^^^^^^ ^
3231

33-
Future breakage date: None, diagnostic:
34-
warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
35-
--> $DIR/into-iter-on-arrays-2018.rs:18:44
32+
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
33+
--> $DIR/into-iter-on-arrays-2018.rs:27:24
3634
|
37-
LL | let _: Iter<'_, i32> = Box::new(array).into_iter();
38-
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
35+
LL | for _ in [1, 2, 3].into_iter() {}
36+
| ^^^^^^^^^
37+
|
38+
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
3939
|
40-
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
41-
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
40+
LL | for _ in [1, 2, 3].iter() {}
41+
| ^^^^
42+
help: or remove `.into_iter()` to iterate by value
43+
|
44+
LL | for _ in [1, 2, 3] {}
45+
| --
46+
47+
warning: 3 warnings emitted
4248

‎src/test/ui/iterators/into-iter-on-arrays-lint.fixed

+12-24
Original file line numberDiff line numberDiff line change
@@ -7,43 +7,31 @@ fn main() {
77

88
// Expressions that should trigger the lint
99
small.iter();
10-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
11-
//~| WARNING this was previously accepted by the compiler but is being phased out
10+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
1211
[1, 2].iter();
13-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
14-
//~| WARNING this was previously accepted by the compiler but is being phased out
12+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
1513
big.iter();
16-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
17-
//~| WARNING this was previously accepted by the compiler but is being phased out
14+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
1815
[0u8; 33].iter();
19-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
20-
//~| WARNING this was previously accepted by the compiler but is being phased out
16+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
2117

2218
Box::new(small).iter();
23-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
24-
//~| WARNING this was previously accepted by the compiler but is being phased out
19+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
2520
Box::new([1, 2]).iter();
26-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
27-
//~| WARNING this was previously accepted by the compiler but is being phased out
21+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
2822
Box::new(big).iter();
29-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
30-
//~| WARNING this was previously accepted by the compiler but is being phased out
23+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
3124
Box::new([0u8; 33]).iter();
32-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
33-
//~| WARNING this was previously accepted by the compiler but is being phased out
25+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
3426

3527
Box::new(Box::new(small)).iter();
36-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
37-
//~| WARNING this was previously accepted by the compiler but is being phased out
28+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
3829
Box::new(Box::new([1, 2])).iter();
39-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
40-
//~| WARNING this was previously accepted by the compiler but is being phased out
30+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
4131
Box::new(Box::new(big)).iter();
42-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
43-
//~| WARNING this was previously accepted by the compiler but is being phased out
32+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
4433
Box::new(Box::new([0u8; 33])).iter();
45-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
46-
//~| WARNING this was previously accepted by the compiler but is being phased out
34+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
4735

4836
// Expressions that should not
4937
(&[1, 2]).into_iter();

‎src/test/ui/iterators/into-iter-on-arrays-lint.rs

+12-24
Original file line numberDiff line numberDiff line change
@@ -7,43 +7,31 @@ fn main() {
77

88
// Expressions that should trigger the lint
99
small.into_iter();
10-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
11-
//~| WARNING this was previously accepted by the compiler but is being phased out
10+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
1211
[1, 2].into_iter();
13-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
14-
//~| WARNING this was previously accepted by the compiler but is being phased out
12+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
1513
big.into_iter();
16-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
17-
//~| WARNING this was previously accepted by the compiler but is being phased out
14+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
1815
[0u8; 33].into_iter();
19-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
20-
//~| WARNING this was previously accepted by the compiler but is being phased out
16+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
2117

2218
Box::new(small).into_iter();
23-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
24-
//~| WARNING this was previously accepted by the compiler but is being phased out
19+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
2520
Box::new([1, 2]).into_iter();
26-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
27-
//~| WARNING this was previously accepted by the compiler but is being phased out
21+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
2822
Box::new(big).into_iter();
29-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
30-
//~| WARNING this was previously accepted by the compiler but is being phased out
23+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
3124
Box::new([0u8; 33]).into_iter();
32-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
33-
//~| WARNING this was previously accepted by the compiler but is being phased out
25+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
3426

3527
Box::new(Box::new(small)).into_iter();
36-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
37-
//~| WARNING this was previously accepted by the compiler but is being phased out
28+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
3829
Box::new(Box::new([1, 2])).into_iter();
39-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
40-
//~| WARNING this was previously accepted by the compiler but is being phased out
30+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
4131
Box::new(Box::new(big)).into_iter();
42-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
43-
//~| WARNING this was previously accepted by the compiler but is being phased out
32+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
4433
Box::new(Box::new([0u8; 33])).into_iter();
45-
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
46-
//~| WARNING this was previously accepted by the compiler but is being phased out
34+
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
4735

4836
// Expressions that should not
4937
(&[1, 2]).into_iter();

‎src/test/ui/iterators/into-iter-on-arrays-lint.stderr

+119-183
Large diffs are not rendered by default.

‎src/test/ui/lint/issue-78660-cap-lints-future-compat.rs

-10
This file was deleted.

‎src/test/ui/lint/issue-78660-cap-lints-future-compat.stderr

-11
This file was deleted.

0 commit comments

Comments
 (0)
Please sign in to comment.