Rollup merge of #88512 - m-ou-se:array-into-iter-deref-stuff, r=estebank

Upgrade array_into_iter lint to include Deref-to-array types.

Fixes https://github.com/rust-lang/rust/issues/88099

Fixes the issue mentioned here: https://github.com/rust-lang/rust/pull/84147#issuecomment-819000436
This commit is contained in:
Mara Bos 2021-09-02 19:10:15 +02:00 committed by GitHub
commit ea82d0651a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 63 additions and 108 deletions

View file

@ -74,39 +74,45 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
_ => return, _ => return,
}; };
// As this is a method call expression, we have at least one // As this is a method call expression, we have at least one argument.
// argument.
let receiver_arg = &args[0]; let receiver_arg = &args[0];
let receiver_ty = cx.typeck_results().expr_ty(receiver_arg);
let adjustments = cx.typeck_results().expr_adjustments(receiver_arg);
// Peel all `Box<_>` layers. We have to special case `Box` here as let target = match adjustments.last() {
// `Box` is the only thing that values can be moved out of via Some(Adjustment { kind: Adjust::Borrow(_), target }) => target,
// method call. `Box::new([1]).into_iter()` should trigger this _ => return,
// lint. };
let mut recv_ty = cx.typeck_results().expr_ty(receiver_arg);
let mut num_box_derefs = 0; let types =
while recv_ty.is_box() { std::iter::once(receiver_ty).chain(adjustments.iter().map(|adj| adj.target));
num_box_derefs += 1;
recv_ty = recv_ty.boxed_ty(); let mut found_array = false;
for ty in types {
match ty.kind() {
// If we run into a &[T; N] or &[T] first, there's nothing to warn about.
// It'll resolve to the reference version.
ty::Ref(_, inner_ty, _) if inner_ty.is_array() => return,
ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => return,
// Found an actual array type without matching a &[T; N] first.
// This is the problematic case.
ty::Array(..) => {
found_array = true;
break;
}
_ => {}
}
} }
// Make sure we found an array after peeling the boxes. if !found_array {
if !matches!(recv_ty.kind(), ty::Array(..)) {
return; return;
} }
// Make sure that there is an autoref coercion at the expected
// position. The first `num_box_derefs` adjustments are the derefs
// of the box.
match cx.typeck_results().expr_adjustments(receiver_arg).get(num_box_derefs) {
Some(Adjustment { kind: Adjust::Borrow(_), .. }) => {}
_ => return,
}
// Emit lint diagnostic. // Emit lint diagnostic.
let target = match *cx.typeck_results().expr_ty_adjusted(receiver_arg).kind() { let target = match *target.kind() {
ty::Ref(_, inner_ty, _) if inner_ty.is_array() => "[T; N]", ty::Ref(_, inner_ty, _) if inner_ty.is_array() => "[T; N]",
ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => "[T]", ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => "[T]",
// We know the original first argument type is an array type, // We know the original first argument type is an array type,
// we know that the first adjustment was an autoref coercion // we know that the first adjustment was an autoref coercion
// and we know that `IntoIterator` is the trait involved. The // and we know that `IntoIterator` is the trait involved. The
@ -135,7 +141,7 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
String::new(), String::new(),
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} else { } else if receiver_ty.is_array() {
diag.multipart_suggestion( diag.multipart_suggestion(
"or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value", "or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value",
vec![ vec![

View file

@ -19,9 +19,12 @@ fn main() {
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning //~| WARNING this changes meaning
// 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> = Rc::new(array).into_iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
let _: Iter<'_, i32> = Array(array).into_iter(); let _: Iter<'_, i32> = Array(array).into_iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
// But you can always use the trait method explicitly as an array. // But you can always use the trait method explicitly as an array.
let _: IntoIter<i32, 10> = IntoIterator::into_iter(array); let _: IntoIter<i32, 10> = IntoIterator::into_iter(array);

View file

@ -20,21 +20,31 @@ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (du
--> $DIR/into-iter-on-arrays-2018.rs:18:44 --> $DIR/into-iter-on-arrays-2018.rs:18:44
| |
LL | let _: Iter<'_, i32> = Box::new(array).into_iter(); LL | let _: Iter<'_, i32> = Box::new(array).into_iter();
| ^^^^^^^^^ | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
| |
= warning: this changes meaning in Rust 2021 = warning: this changes meaning in Rust 2021
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
LL | let _: Iter<'_, i32> = Box::new(array).iter();
| ~~~~
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
|
LL | let _: Iter<'_, i32> = IntoIterator::into_iter(Box::new(array));
| ++++++++++++++++++++++++ ~
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. 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:29:24 --> $DIR/into-iter-on-arrays-2018.rs:22:43
|
LL | let _: Iter<'_, i32> = Rc::new(array).into_iter();
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
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:25:41
|
LL | let _: Iter<'_, i32> = Array(array).into_iter();
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
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:32:24
| |
LL | for _ in [1, 2, 3].into_iter() {} LL | for _ in [1, 2, 3].into_iter() {}
| ^^^^^^^^^ | ^^^^^^^^^
@ -51,5 +61,5 @@ LL - for _ in [1, 2, 3].into_iter() {}
LL + for _ in [1, 2, 3] {} LL + for _ in [1, 2, 3] {}
| |
warning: 3 warnings emitted warning: 5 warnings emitted

View file

@ -71,137 +71,73 @@ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (du
--> $DIR/into-iter-on-arrays-lint.rs:23:21 --> $DIR/into-iter-on-arrays-lint.rs:23:21
| |
LL | Box::new(small).into_iter(); LL | Box::new(small).into_iter();
| ^^^^^^^^^ | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
| |
= warning: this changes meaning in Rust 2021 = warning: this changes meaning in Rust 2021
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
LL | Box::new(small).iter();
| ~~~~
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
|
LL | IntoIterator::into_iter(Box::new(small));
| ++++++++++++++++++++++++ ~
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. 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-lint.rs:26:22 --> $DIR/into-iter-on-arrays-lint.rs:26:22
| |
LL | Box::new([1, 2]).into_iter(); LL | Box::new([1, 2]).into_iter();
| ^^^^^^^^^ | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
| |
= warning: this changes meaning in Rust 2021 = warning: this changes meaning in Rust 2021
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
LL | Box::new([1, 2]).iter();
| ~~~~
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
|
LL | IntoIterator::into_iter(Box::new([1, 2]));
| ++++++++++++++++++++++++ ~
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. 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-lint.rs:29:19 --> $DIR/into-iter-on-arrays-lint.rs:29:19
| |
LL | Box::new(big).into_iter(); LL | Box::new(big).into_iter();
| ^^^^^^^^^ | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
| |
= warning: this changes meaning in Rust 2021 = warning: this changes meaning in Rust 2021
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
LL | Box::new(big).iter();
| ~~~~
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
|
LL | IntoIterator::into_iter(Box::new(big));
| ++++++++++++++++++++++++ ~
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. 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-lint.rs:32:25 --> $DIR/into-iter-on-arrays-lint.rs:32:25
| |
LL | Box::new([0u8; 33]).into_iter(); LL | Box::new([0u8; 33]).into_iter();
| ^^^^^^^^^ | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
| |
= warning: this changes meaning in Rust 2021 = warning: this changes meaning in Rust 2021
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
LL | Box::new([0u8; 33]).iter();
| ~~~~
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
|
LL | IntoIterator::into_iter(Box::new([0u8; 33]));
| ++++++++++++++++++++++++ ~
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. 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-lint.rs:36:31 --> $DIR/into-iter-on-arrays-lint.rs:36:31
| |
LL | Box::new(Box::new(small)).into_iter(); LL | Box::new(Box::new(small)).into_iter();
| ^^^^^^^^^ | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
| |
= warning: this changes meaning in Rust 2021 = warning: this changes meaning in Rust 2021
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
LL | Box::new(Box::new(small)).iter();
| ~~~~
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
|
LL | IntoIterator::into_iter(Box::new(Box::new(small)));
| ++++++++++++++++++++++++ ~
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. 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-lint.rs:39:32 --> $DIR/into-iter-on-arrays-lint.rs:39:32
| |
LL | Box::new(Box::new([1, 2])).into_iter(); LL | Box::new(Box::new([1, 2])).into_iter();
| ^^^^^^^^^ | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
| |
= warning: this changes meaning in Rust 2021 = warning: this changes meaning in Rust 2021
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
LL | Box::new(Box::new([1, 2])).iter();
| ~~~~
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
|
LL | IntoIterator::into_iter(Box::new(Box::new([1, 2])));
| ++++++++++++++++++++++++ ~
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. 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-lint.rs:42:29 --> $DIR/into-iter-on-arrays-lint.rs:42:29
| |
LL | Box::new(Box::new(big)).into_iter(); LL | Box::new(Box::new(big)).into_iter();
| ^^^^^^^^^ | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
| |
= warning: this changes meaning in Rust 2021 = warning: this changes meaning in Rust 2021
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
LL | Box::new(Box::new(big)).iter();
| ~~~~
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
|
LL | IntoIterator::into_iter(Box::new(Box::new(big)));
| ++++++++++++++++++++++++ ~
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. 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-lint.rs:45:35 --> $DIR/into-iter-on-arrays-lint.rs:45:35
| |
LL | Box::new(Box::new([0u8; 33])).into_iter(); LL | Box::new(Box::new([0u8; 33])).into_iter();
| ^^^^^^^^^ | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
| |
= warning: this changes meaning in Rust 2021 = warning: this changes meaning in Rust 2021
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
LL | Box::new(Box::new([0u8; 33])).iter();
| ~~~~
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
|
LL | IntoIterator::into_iter(Box::new(Box::new([0u8; 33])));
| ++++++++++++++++++++++++ ~
warning: 12 warnings emitted warning: 12 warnings emitted