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..063c8e555677b 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,10 +38,20 @@ 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) { - return; - } + 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 + } + _ => return, + }; // 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) { @@ -69,7 +79,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 +140,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| { 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 +