Skip to content

Commit

Permalink
Rollup merge of rust-lang#85682 - m-ou-se:array-into-iter-2, r=nikoma…
Browse files Browse the repository at this point in the history
…tsakis

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`
  • Loading branch information
JohnTitor committed Jun 22, 2021
2 parents 44f4a87 + a8614bc commit 90ac98f
Show file tree
Hide file tree
Showing 9 changed files with 237 additions and 318 deletions.
89 changes: 55 additions & 34 deletions compiler/rustc_lint/src/array_into_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_middle::ty;
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
use rustc_session::lint::FutureBreakage;
use rustc_span::symbol::sym;
use rustc_span::Span;

declare_lint! {
/// The `array_into_iter` lint detects calling `into_iter` on arrays.
Expand All @@ -20,37 +20,40 @@ declare_lint! {
///
/// ### Explanation
///
/// In the future, it is planned to add an `IntoIter` implementation for
/// arrays such that it will iterate over *values* of the array instead of
/// references. Due to how method resolution works, this will change
/// existing code that uses `into_iter` on arrays. The solution to avoid
/// this warning is to use `iter()` instead of `into_iter()`.
///
/// This is a [future-incompatible] lint to transition this to a hard error
/// in the future. See [issue #66145] for more details and a more thorough
/// description of the lint.
///
/// [issue #66145]: https://github.com/rust-lang/rust/issues/66145
/// [future-incompatible]: ../index.md#future-incompatible-lints
/// Since Rust 1.53, arrays implement `IntoIterator`. However, to avoid
/// breakage, `array.into_iter()` in Rust 2015 and 2018 code will still
/// behave as `(&array).into_iter()`, returning an iterator over
/// references, just like in Rust 1.52 and earlier.
/// This only applies to the method call syntax `array.into_iter()`, not to
/// any other syntax such as `for _ in array` or `IntoIterator::into_iter(array)`.
pub ARRAY_INTO_ITER,
Warn,
"detects calling `into_iter` on arrays",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #66145 <https://github.com/rust-lang/rust/issues/66145>",
edition: None,
future_breakage: Some(FutureBreakage {
date: None
})
};
"detects calling `into_iter` on arrays in Rust 2015 and 2018",
}

#[derive(Copy, Clone, Default)]
pub struct ArrayIntoIter {
for_expr_span: Span,
}

declare_lint_pass!(
/// Checks for instances of calling `into_iter` on arrays.
ArrayIntoIter => [ARRAY_INTO_ITER]
);
impl_lint_pass!(ArrayIntoIter => [ARRAY_INTO_ITER]);

impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
// Save the span of expressions in `for _ in expr` syntax,
// so we can give a better suggestion for those later.
if let hir::ExprKind::Match(arg, [_], hir::MatchSource::ForLoopDesugar) = &expr.kind {
if let hir::ExprKind::Call(path, [arg]) = &arg.kind {
if let hir::ExprKind::Path(hir::QPath::LangItem(
hir::LangItem::IntoIterIntoIter,
_,
)) = &path.kind
{
self.for_expr_span = arg.span;
}
}
}

// We only care about method call expressions.
if let hir::ExprKind::MethodCall(call, span, args, _) = &expr.kind {
if call.ident.name != sym::into_iter {
Expand Down Expand Up @@ -106,19 +109,37 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
_ => bug!("array type coerced to something other than array or slice"),
};
cx.struct_span_lint(ARRAY_INTO_ITER, *span, |lint| {
lint.build(&format!(
"this method call currently resolves to `<&{} as IntoIterator>::into_iter` (due \
to autoref coercions), but that might change in the future when \
`IntoIterator` impls for arrays are added.",
target,
))
.span_suggestion(
let mut diag = lint.build(&format!(
"this method call resolves to `<&{} as IntoIterator>::into_iter` \
(due to backwards compatibility), \
but will resolve to <{} as IntoIterator>::into_iter in Rust 2021.",
target, target,
));
diag.span_suggestion(
call.ident.span,
"use `.iter()` instead of `.into_iter()` to avoid ambiguity",
"iter".into(),
Applicability::MachineApplicable,
)
.emit();
);
if self.for_expr_span == expr.span {
let expr_span = expr.span.ctxt().outer_expn_data().call_site;
diag.span_suggestion(
receiver_arg.span.shrink_to_hi().to(expr_span.shrink_to_hi()),
"or remove `.into_iter()` to iterate by value",
String::new(),
Applicability::MaybeIncorrect,
);
} else {
diag.multipart_suggestion(
"or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value",
vec![
(expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()),
(receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), ")".into()),
],
Applicability::MaybeIncorrect,
);
}
diag.emit();
})
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ macro_rules! late_lint_passes {
// FIXME: Turn the computation of types which implement Debug into a query
// and change this to a module lint pass
MissingDebugImplementations: MissingDebugImplementations::default(),
ArrayIntoIter: ArrayIntoIter,
ArrayIntoIter: ArrayIntoIter::default(),
ClashingExternDeclarations: ClashingExternDeclarations::new(),
DropTraitConstraints: DropTraitConstraints,
TemporaryCStringAsPtr: TemporaryCStringAsPtr,
Expand Down
9 changes: 5 additions & 4 deletions src/test/ui/iterators/into-iter-on-arrays-2018.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,20 @@ fn main() {
// Before 2021, the method dispatched to `IntoIterator for &[T; N]`,
// which we continue to support for compatibility.
let _: Iter<'_, i32> = array.into_iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`

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

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

// But you can always use the trait method explicitly as an array.
let _: IntoIter<i32, 10> = IntoIterator::into_iter(array);

for _ in [1, 2, 3].into_iter() {}
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
}

/// User type that dereferences to an array.
Expand Down
60 changes: 33 additions & 27 deletions src/test/ui/iterators/into-iter-on-arrays-2018.stderr
Original file line number Diff line number Diff line change
@@ -1,42 +1,48 @@
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.
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.
--> $DIR/into-iter-on-arrays-2018.rs:14:34
|
LL | let _: Iter<'_, i32> = array.into_iter();
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
| ^^^^^^^^^
|
= note: `#[warn(array_into_iter)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
LL | let _: Iter<'_, i32> = array.iter();
| ^^^^
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
|
LL | let _: Iter<'_, i32> = IntoIterator::into_iter(array);
| ^^^^^^^^^^^^^^^^^^^^^^^^ ^

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.
--> $DIR/into-iter-on-arrays-2018.rs:18:44
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.
--> $DIR/into-iter-on-arrays-2018.rs:17:44
|
LL | let _: Iter<'_, i32> = Box::new(array).into_iter();
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
| ^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>

warning: 2 warnings emitted

Future incompatibility report: Future breakage date: None, diagnostic:
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.
--> $DIR/into-iter-on-arrays-2018.rs:14:34
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
LL | let _: Iter<'_, i32> = array.into_iter();
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
LL | let _: Iter<'_, i32> = Box::new(array).iter();
| ^^^^
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
|
= note: `#[warn(array_into_iter)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
LL | let _: Iter<'_, i32> = IntoIterator::into_iter(Box::new(array));
| ^^^^^^^^^^^^^^^^^^^^^^^^ ^

Future breakage date: None, diagnostic:
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.
--> $DIR/into-iter-on-arrays-2018.rs:18:44
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.
--> $DIR/into-iter-on-arrays-2018.rs:27:24
|
LL | let _: Iter<'_, i32> = Box::new(array).into_iter();
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
LL | for _ in [1, 2, 3].into_iter() {}
| ^^^^^^^^^
|
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
LL | for _ in [1, 2, 3].iter() {}
| ^^^^
help: or remove `.into_iter()` to iterate by value
|
LL | for _ in [1, 2, 3] {}
| --

warning: 3 warnings emitted

36 changes: 12 additions & 24 deletions src/test/ui/iterators/into-iter-on-arrays-lint.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -7,43 +7,31 @@ fn main() {

// Expressions that should trigger the lint
small.iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
[1, 2].iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
big.iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
[0u8; 33].iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`

Box::new(small).iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
Box::new([1, 2]).iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
Box::new(big).iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
Box::new([0u8; 33]).iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`

Box::new(Box::new(small)).iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
Box::new(Box::new([1, 2])).iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
Box::new(Box::new(big)).iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
Box::new(Box::new([0u8; 33])).iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`

// Expressions that should not
(&[1, 2]).into_iter();
Expand Down
36 changes: 12 additions & 24 deletions src/test/ui/iterators/into-iter-on-arrays-lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,43 +7,31 @@ fn main() {

// Expressions that should trigger the lint
small.into_iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
[1, 2].into_iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
big.into_iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
[0u8; 33].into_iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`

Box::new(small).into_iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
Box::new([1, 2]).into_iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
Box::new(big).into_iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
Box::new([0u8; 33]).into_iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`

Box::new(Box::new(small)).into_iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
Box::new(Box::new([1, 2])).into_iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
Box::new(Box::new(big)).into_iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
Box::new(Box::new([0u8; 33])).into_iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`

// Expressions that should not
(&[1, 2]).into_iter();
Expand Down
Loading

0 comments on commit 90ac98f

Please sign in to comment.