diff options
| author | Mara Bos <m-ou.se@m-ou.se> | 2021-08-30 23:41:48 +0200 |
|---|---|---|
| committer | Mara Bos <m-ou.se@m-ou.se> | 2021-08-30 23:43:38 +0200 |
| commit | 422ad3bec2a9b41345cf1dd95a4ce4b4d9f159d8 (patch) | |
| tree | fad689a1a010fc960d15f2ba95e66f7e33a266d8 | |
| parent | 13edc17f65bcad7fe9046720a16fc192e810970e (diff) | |
| download | rust-422ad3bec2a9b41345cf1dd95a4ce4b4d9f159d8.tar.gz rust-422ad3bec2a9b41345cf1dd95a4ce4b4d9f159d8.zip | |
Upgrade array_into_iter lint to include Deref-to-array types.
| -rw-r--r-- | compiler/rustc_lint/src/array_into_iter.rs | 52 |
1 files changed, 29 insertions, 23 deletions
diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index 21fad5f9af6..2e20f376766 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -74,39 +74,45 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { _ => return, }; - // As this is a method call expression, we have at least one - // argument. + // As this is a method call expression, we have at least one argument. 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 - // `Box` is the only thing that values can be moved out of via - // method call. `Box::new([1]).into_iter()` should trigger this - // lint. - let mut recv_ty = cx.typeck_results().expr_ty(receiver_arg); - let mut num_box_derefs = 0; - while recv_ty.is_box() { - num_box_derefs += 1; - recv_ty = recv_ty.boxed_ty(); - } + let target = match adjustments.last() { + Some(Adjustment { kind: Adjust::Borrow(_), target }) => target, + _ => return, + }; - // Make sure we found an array after peeling the boxes. - if !matches!(recv_ty.kind(), ty::Array(..)) { - return; + let types = + std::iter::once(receiver_ty).chain(adjustments.iter().map(|adj| adj.target)); + + 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 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, + if !found_array { + return; } // 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 matches!(inner_ty.kind(), ty::Slice(..)) => "[T]", - // We know the original first argument type is an array type, // we know that the first adjustment was an autoref coercion // and we know that `IntoIterator` is the trait involved. The |
