From 336f31432df03e4dbd635dddedad1c9e67271a0c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 30 Aug 2021 21:19:24 +0200 Subject: [PATCH 1/3] Warn when [T; N].into_iter() is ambiguous in the new edition. --- Cargo.lock | 1 + compiler/rustc_lint/src/lib.rs | 2 ++ compiler/rustc_typeck/Cargo.toml | 1 + .../src/check/method/prelude2021.rs | 27 +++++++++++++++---- 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 74a316ed5f04e..f47704bbf6841 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4405,6 +4405,7 @@ dependencies = [ "rustc_hir_pretty", "rustc_index", "rustc_infer", + "rustc_lint", "rustc_macros", "rustc_middle", "rustc_session", diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 24ac723f2c913..ef4bda666ba06 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -62,6 +62,8 @@ mod traits; mod types; mod unused; +pub use array_into_iter::ARRAY_INTO_ITER; + use rustc_ast as ast; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; diff --git a/compiler/rustc_typeck/Cargo.toml b/compiler/rustc_typeck/Cargo.toml index fa5ef63f5c52e..dd76a5e4b99b2 100644 --- a/compiler/rustc_typeck/Cargo.toml +++ b/compiler/rustc_typeck/Cargo.toml @@ -26,3 +26,4 @@ rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_ty_utils = { path = "../rustc_ty_utils" } +rustc_lint = { path = "../rustc_lint" } diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_typeck/src/check/method/prelude2021.rs index b5bc9d3599acb..d5881ad8a5126 100644 --- a/compiler/rustc_typeck/src/check/method/prelude2021.rs +++ b/compiler/rustc_typeck/src/check/method/prelude2021.rs @@ -5,7 +5,7 @@ use rustc_ast::Mutability; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_middle::ty::subst::InternalSubsts; -use rustc_middle::ty::{Adt, Ref, Ty}; +use rustc_middle::ty::{Adt, Array, Ref, Ty}; use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS; use rustc_span::symbol::kw::Underscore; use rustc_span::symbol::{sym, Ident}; @@ -38,11 +38,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - // These are the method names that were added to prelude in Rust 2021 - if !matches!(segment.ident.name, sym::try_into) { + // `try_into` was added to the prelude in Rust 2021. + // `into_iter` wasn't, but `[T; N].into_iter()` doesn't resolve to + // IntoIterator::into_iter before Rust 2021, which results in the same + // problem. + if !matches!(segment.ident.name, sym::try_into | sym::into_iter) { return; } + let prelude_or_array_lint = if segment.ident.name == sym::into_iter { + // The `into_iter` problem is only a thing for arrays. + if let Array(..) = self_ty.kind() { + // In this case, it wasn't really a prelude addition that was the problem. + // Instead, the problem is that the array-into_iter hack will no longer apply in Rust 2021. + rustc_lint::ARRAY_INTO_ITER + } else { + // No problem in this case. + return; + } + } else { + RUST_2021_PRELUDE_COLLISIONS + }; + // No need to lint if method came from std/core, as that will now be in the prelude if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) { return; @@ -69,7 +86,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Inherent impls only require not relying on autoref and autoderef in order to // ensure that the trait implementation won't be used self.tcx.struct_span_lint_hir( - RUST_2021_PRELUDE_COLLISIONS, + prelude_or_array_lint, self_expr.hir_id, self_expr.span, |lint| { @@ -130,7 +147,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // trait implementations require full disambiguation to not clash with the new prelude // additions (i.e. convert from dot-call to fully-qualified call) self.tcx.struct_span_lint_hir( - RUST_2021_PRELUDE_COLLISIONS, + prelude_or_array_lint, call_expr.hir_id, call_expr.span, |lint| { From 756ef3bff619e1d67620b1dfc80f1246cd6aac48 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 30 Aug 2021 21:23:56 +0200 Subject: [PATCH 2/3] Add test for 2021 ambiguous [T; N].into_iter(). --- .../rust-2021/array-into-iter-ambiguous.fixed | 27 +++++++++++++++++++ .../ui/rust-2021/array-into-iter-ambiguous.rs | 27 +++++++++++++++++++ .../array-into-iter-ambiguous.stderr | 16 +++++++++++ 3 files changed, 70 insertions(+) create mode 100644 src/test/ui/rust-2021/array-into-iter-ambiguous.fixed create mode 100644 src/test/ui/rust-2021/array-into-iter-ambiguous.rs create mode 100644 src/test/ui/rust-2021/array-into-iter-ambiguous.stderr diff --git a/src/test/ui/rust-2021/array-into-iter-ambiguous.fixed b/src/test/ui/rust-2021/array-into-iter-ambiguous.fixed new file mode 100644 index 0000000000000..76f661baed750 --- /dev/null +++ b/src/test/ui/rust-2021/array-into-iter-ambiguous.fixed @@ -0,0 +1,27 @@ +// See https://github.com/rust-lang/rust/issues/88475 +// run-rustfix +// edition:2018 +// check-pass +#![warn(array_into_iter)] +#![allow(unused)] + +struct FooIter; + +trait MyIntoIter { + fn into_iter(self) -> FooIter; +} + +impl MyIntoIter for [T; N] { + fn into_iter(self) -> FooIter { + FooIter + } +} + +struct Point; + +pub fn main() { + let points: [Point; 1] = [Point]; + let y = MyIntoIter::into_iter(points); + //~^ WARNING trait method `into_iter` will become ambiguous in Rust 2021 + //~| WARNING this changes meaning in Rust 2021 +} diff --git a/src/test/ui/rust-2021/array-into-iter-ambiguous.rs b/src/test/ui/rust-2021/array-into-iter-ambiguous.rs new file mode 100644 index 0000000000000..83fbf8f6c218d --- /dev/null +++ b/src/test/ui/rust-2021/array-into-iter-ambiguous.rs @@ -0,0 +1,27 @@ +// See https://github.com/rust-lang/rust/issues/88475 +// run-rustfix +// edition:2018 +// check-pass +#![warn(array_into_iter)] +#![allow(unused)] + +struct FooIter; + +trait MyIntoIter { + fn into_iter(self) -> FooIter; +} + +impl MyIntoIter for [T; N] { + fn into_iter(self) -> FooIter { + FooIter + } +} + +struct Point; + +pub fn main() { + let points: [Point; 1] = [Point]; + let y = points.into_iter(); + //~^ WARNING trait method `into_iter` will become ambiguous in Rust 2021 + //~| WARNING this changes meaning in Rust 2021 +} diff --git a/src/test/ui/rust-2021/array-into-iter-ambiguous.stderr b/src/test/ui/rust-2021/array-into-iter-ambiguous.stderr new file mode 100644 index 0000000000000..fac8d21c7b48a --- /dev/null +++ b/src/test/ui/rust-2021/array-into-iter-ambiguous.stderr @@ -0,0 +1,16 @@ +warning: trait method `into_iter` will become ambiguous in Rust 2021 + --> $DIR/array-into-iter-ambiguous.rs:24:13 + | +LL | let y = points.into_iter(); + | ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `MyIntoIter::into_iter(points)` + | +note: the lint level is defined here + --> $DIR/array-into-iter-ambiguous.rs:5:9 + | +LL | #![warn(array_into_iter)] + | ^^^^^^^^^^^^^^^ + = warning: this changes meaning in Rust 2021 + = note: for more information, see + +warning: 1 warning emitted + From ac93ca3b94fefb2ac4844722d4b3222e2f331046 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 30 Aug 2021 23:57:16 +0200 Subject: [PATCH 3/3] Turn to ifs into a match. --- .../src/check/method/prelude2021.rs | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_typeck/src/check/method/prelude2021.rs index d5881ad8a5126..063c8e555677b 100644 --- a/compiler/rustc_typeck/src/check/method/prelude2021.rs +++ b/compiler/rustc_typeck/src/check/method/prelude2021.rs @@ -38,26 +38,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - // `try_into` was added to the prelude in Rust 2021. - // `into_iter` wasn't, but `[T; N].into_iter()` doesn't resolve to - // IntoIterator::into_iter before Rust 2021, which results in the same - // problem. - if !matches!(segment.ident.name, sym::try_into | sym::into_iter) { - return; - } - - let prelude_or_array_lint = if segment.ident.name == sym::into_iter { - // The `into_iter` problem is only a thing for arrays. - if let Array(..) = self_ty.kind() { + let prelude_or_array_lint = match segment.ident.name { + // `try_into` was added to the prelude in Rust 2021. + sym::try_into => RUST_2021_PRELUDE_COLLISIONS, + // `into_iter` wasn't added to the prelude, + // but `[T; N].into_iter()` doesn't resolve to IntoIterator::into_iter + // before Rust 2021, which results in the same problem. + // It is only a problem for arrays. + sym::into_iter if let Array(..) = self_ty.kind() => { // In this case, it wasn't really a prelude addition that was the problem. // Instead, the problem is that the array-into_iter hack will no longer apply in Rust 2021. rustc_lint::ARRAY_INTO_ITER - } else { - // No problem in this case. - return; } - } else { - RUST_2021_PRELUDE_COLLISIONS + _ => return, }; // No need to lint if method came from std/core, as that will now be in the prelude