diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index be4f12c6d1cb8..085e3811ac1a3 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -155,6 +155,7 @@ symbols! { FormatSpec, Formatter, From, + FromIterator, Future, FxHashMap, FxHashSet, diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_typeck/src/check/method/prelude2021.rs index 6ca0b3ed66b39..f13e23914f7ab 100644 --- a/compiler/rustc_typeck/src/check/method/prelude2021.rs +++ b/compiler/rustc_typeck/src/check/method/prelude2021.rs @@ -4,11 +4,13 @@ use hir::ItemKind; use rustc_ast::Mutability; use rustc_errors::Applicability; use rustc_hir as hir; +use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{Ref, Ty}; use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS; use rustc_span::symbol::kw::Underscore; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; +use rustc_trait_selection::infer::InferCtxtExt; use crate::check::{ method::probe::{self, Pick}, @@ -206,6 +208,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } + // For from_iter, check if the type actually implements FromIterator. + // If we know it does not, we don't need to warn. + if method_name.name == sym::from_iter { + if let Some(trait_def_id) = self.tcx.get_diagnostic_item(sym::FromIterator) { + if !self + .infcx + .type_implements_trait( + trait_def_id, + self_ty, + InternalSubsts::empty(), + self.param_env, + ) + .may_apply() + { + return; + } + } + } + // No need to lint if this is an inherent method called on a specific type, like `Vec::foo(...)`, // since such methods take precedence over trait methods. if matches!(pick.kind, probe::PickKind::InherentImplPick) { diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 348e1f7e3f23d..7f87ead6feed6 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -89,6 +89,7 @@ over elements of type `{A}`", label = "value of type `{Self}` cannot be built from `std::iter::Iterator`" )] +#[rustc_diagnostic_item = "FromIterator"] pub trait FromIterator: Sized { /// Creates a value from an iterator. /// diff --git a/src/test/ui/rust-2021/future-prelude-collision-unneeded.rs b/src/test/ui/rust-2021/future-prelude-collision-unneeded.rs index 4be82056ad59b..247d5884b868a 100644 --- a/src/test/ui/rust-2021/future-prelude-collision-unneeded.rs +++ b/src/test/ui/rust-2021/future-prelude-collision-unneeded.rs @@ -11,8 +11,50 @@ impl S { } } -// See https://github.com/rust-lang/rust/issues/86633 +struct X; + +trait Hey { + fn from_iter(_: i32) -> Self; +} + +impl Hey for X { + fn from_iter(_: i32) -> Self { + X + } +} + +struct Y(T); + +impl Hey for Y { + fn from_iter(_: i32) -> Self { + Y(0) + } +} + +struct Z(T); + +impl Hey for Z { + fn from_iter(_: i32) -> Self { + Z(0) + } +} + +impl std::iter::FromIterator for Z { + fn from_iter>(_: T) -> Self { + todo!() + } +} + fn main() { + // See https://github.com/rust-lang/rust/issues/86633 let s = S; let s2 = s.try_into(); + + // Check that we do not issue suggestions for types that do not implement `FromIter`. + // + // See https://github.com/rust-lang/rust/issues/86902 + X::from_iter(1); + Y::from_iter(1); + Y::::from_iter(1); + Z::::from_iter(1); }