diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 589b4d6a10ff1..67cf66f470829 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -1245,6 +1245,23 @@ impl<'tcx> LateContext<'tcx> { AbsolutePathPrinter { tcx: self.tcx }.print_def_path(def_id, &[]).unwrap() } + + /// Returns the associated type `name` for `self_ty` as an implementation of `trait_id`. + /// Do not invoke without first verifying that the type implements the trait. + pub fn get_associated_type( + &self, + self_ty: Ty<'tcx>, + trait_id: DefId, + name: &str, + ) -> Option> { + let tcx = self.tcx; + tcx.associated_items(trait_id) + .find_by_name_and_kind(tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id) + .and_then(|assoc| { + let proj = tcx.mk_projection(assoc.def_id, tcx.mk_substs_trait(self_ty, [])); + tcx.try_normalize_erasing_regions(self.param_env, proj).ok() + }) + } } impl<'tcx> abi::HasDataLayout for LateContext<'tcx> { diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs new file mode 100644 index 0000000000000..1d29a234a3c88 --- /dev/null +++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs @@ -0,0 +1,92 @@ +use crate::{LateContext, LateLintPass, LintContext}; + +use rustc_errors::DelayDm; +use rustc_hir as hir; +use rustc_middle::{traits::util::supertraits, ty}; +use rustc_span::sym; + +declare_lint! { + /// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the + /// `Deref` implementation with a `dyn SuperTrait` type as `Output`. + /// + /// These implementations will become shadowed when the `trait_upcasting` feature is stabilized. + /// The `deref` functions will no longer be called implicitly, so there might be behavior change. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(deref_into_dyn_supertrait)] + /// #![allow(dead_code)] + /// + /// use core::ops::Deref; + /// + /// trait A {} + /// trait B: A {} + /// impl<'a> Deref for dyn 'a + B { + /// type Target = dyn A; + /// fn deref(&self) -> &Self::Target { + /// todo!() + /// } + /// } + /// + /// fn take_a(_: &dyn A) { } + /// + /// fn take_b(b: &dyn B) { + /// take_a(b); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The dyn upcasting coercion feature adds new coercion rules, taking priority + /// over certain other coercion rules, which will cause some behavior change. + pub DEREF_INTO_DYN_SUPERTRAIT, + Warn, + "`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #89460 ", + }; +} + +declare_lint_pass!(DerefIntoDynSupertrait => [DEREF_INTO_DYN_SUPERTRAIT]); + +impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { + // `Deref` is being implemented for `t` + if let hir::ItemKind::Impl(impl_) = item.kind + && let Some(trait_) = &impl_.of_trait + && let t = cx.tcx.type_of(item.owner_id) + && let opt_did @ Some(did) = trait_.trait_def_id() + && opt_did == cx.tcx.lang_items().deref_trait() + // `t` is `dyn t_principal` + && let ty::Dynamic(data, _, ty::Dyn) = t.kind() + && let Some(t_principal) = data.principal() + // `::Target` is `dyn target_principal` + && let Some(target) = cx.get_associated_type(t, did, "Target") + && let ty::Dynamic(data, _, ty::Dyn) = target.kind() + && let Some(target_principal) = data.principal() + // `target_principal` is a supertrait of `t_principal` + && supertraits(cx.tcx, t_principal.with_self_ty(cx.tcx, cx.tcx.types.trait_object_dummy_self)) + .any(|sup| sup.map_bound(|x| ty::ExistentialTraitRef::erase_self_ty(cx.tcx, x)) == target_principal) + { + cx.struct_span_lint( + DEREF_INTO_DYN_SUPERTRAIT, + cx.tcx.def_span(item.owner_id.def_id), + DelayDm(|| { + format!( + "`{t}` implements `Deref` with supertrait `{target_principal}` as target" + ) + }), + |lint| { + if let Some(target_span) = impl_.items.iter().find_map(|i| (i.ident.name == sym::Target).then_some(i.span)) { + lint.span_label(target_span, "target type is set here"); + } + + lint + }, + ) + } + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index ebb7de70e0570..b6027476adfd9 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -49,6 +49,7 @@ extern crate tracing; mod array_into_iter; pub mod builtin; mod context; +mod deref_into_dyn_supertrait; mod early; mod enum_intrinsics_non_enums; mod errors; @@ -87,6 +88,7 @@ use rustc_span::Span; use array_into_iter::ArrayIntoIter; use builtin::*; +use deref_into_dyn_supertrait::*; use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; use for_loops_over_fallibles::*; use hidden_unicode_codepoints::*; @@ -192,6 +194,7 @@ macro_rules! late_lint_mod_passes { $args, [ ForLoopsOverFallibles: ForLoopsOverFallibles, + DerefIntoDynSupertrait: DerefIntoDynSupertrait, HardwiredLints: HardwiredLints, ImproperCTypesDeclarations: ImproperCTypesDeclarations, ImproperCTypesDefinitions: ImproperCTypesDefinitions, diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index b80facb1759ef..df0e17dea3c05 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3262,7 +3262,6 @@ declare_lint_pass! { UNUSED_TUPLE_STRUCT_FIELDS, NON_EXHAUSTIVE_OMITTED_PATTERNS, TEXT_DIRECTION_CODEPOINT_IN_COMMENT, - DEREF_INTO_DYN_SUPERTRAIT, DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, DUPLICATE_MACRO_ATTRIBUTES, SUSPICIOUS_AUTO_TRAIT_IMPLS, @@ -3764,51 +3763,6 @@ declare_lint! { "invisible directionality-changing codepoints in comment" } -declare_lint! { - /// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the - /// `Deref` implementation with a `dyn SuperTrait` type as `Output`. - /// - /// These implementations will become shadowed when the `trait_upcasting` feature is stabilized. - /// The `deref` functions will no longer be called implicitly, so there might be behavior change. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #![deny(deref_into_dyn_supertrait)] - /// #![allow(dead_code)] - /// - /// use core::ops::Deref; - /// - /// trait A {} - /// trait B: A {} - /// impl<'a> Deref for dyn 'a + B { - /// type Target = dyn A; - /// fn deref(&self) -> &Self::Target { - /// todo!() - /// } - /// } - /// - /// fn take_a(_: &dyn A) { } - /// - /// fn take_b(b: &dyn B) { - /// take_a(b); - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// The dyn upcasting coercion feature adds new coercion rules, taking priority - /// over certain other coercion rules, which will cause some behavior change. - pub DEREF_INTO_DYN_SUPERTRAIT, - Warn, - "`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #89460 ", - }; -} - declare_lint! { /// The `duplicate_macro_attributes` lint detects when a `#[test]`-like built-in macro /// attribute is duplicated on an item. This lint may trigger on `bench`, `cfg_eval`, `test` diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 1890c0e24bb44..e436328709bb7 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -651,12 +651,6 @@ pub enum ImplSource<'tcx, N> { /// Same as above, but for a function pointer type with the given signature. FnPointer(ImplSourceFnPointerData<'tcx, N>), - /// ImplSource for a builtin `DeterminantKind` trait implementation. - DiscriminantKind(ImplSourceDiscriminantKindData), - - /// ImplSource for a builtin `Pointee` trait implementation. - Pointee(ImplSourcePointeeData), - /// ImplSource automatically generated for a generator. Generator(ImplSourceGeneratorData<'tcx, N>), @@ -678,8 +672,6 @@ impl<'tcx, N> ImplSource<'tcx, N> { ImplSource::Generator(c) => c.nested, ImplSource::Object(d) => d.nested, ImplSource::FnPointer(d) => d.nested, - ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) - | ImplSource::Pointee(ImplSourcePointeeData) => vec![], ImplSource::TraitAlias(d) => d.nested, ImplSource::TraitUpcasting(d) => d.nested, ImplSource::ConstDestruct(i) => i.nested, @@ -696,8 +688,6 @@ impl<'tcx, N> ImplSource<'tcx, N> { ImplSource::Generator(c) => &c.nested, ImplSource::Object(d) => &d.nested, ImplSource::FnPointer(d) => &d.nested, - ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) - | ImplSource::Pointee(ImplSourcePointeeData) => &[], ImplSource::TraitAlias(d) => &d.nested, ImplSource::TraitUpcasting(d) => &d.nested, ImplSource::ConstDestruct(i) => &i.nested, @@ -741,12 +731,6 @@ impl<'tcx, N> ImplSource<'tcx, N> { fn_ty: p.fn_ty, nested: p.nested.into_iter().map(f).collect(), }), - ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => { - ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) - } - ImplSource::Pointee(ImplSourcePointeeData) => { - ImplSource::Pointee(ImplSourcePointeeData) - } ImplSource::TraitAlias(d) => ImplSource::TraitAlias(ImplSourceTraitAliasData { alias_def_id: d.alias_def_id, substs: d.substs, @@ -856,13 +840,6 @@ pub struct ImplSourceFnPointerData<'tcx, N> { pub nested: Vec, } -// FIXME(@lcnr): This should be refactored and merged with other builtin vtables. -#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] -pub struct ImplSourceDiscriminantKindData; - -#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] -pub struct ImplSourcePointeeData; - #[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] #[derive(TypeFoldable, TypeVisitable)] pub struct ImplSourceConstDestructData { diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 85ead3171e785..51ae245900822 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -105,6 +105,12 @@ pub type EvaluationCache<'tcx> = Cache< /// parameter environment. #[derive(PartialEq, Eq, Debug, Clone, TypeFoldable, TypeVisitable)] pub enum SelectionCandidate<'tcx> { + /// A builtin implementation for some specific traits, used in cases + /// where we cannot rely an ordinary library implementations. + /// + /// The most notable examples are `sized`, `Copy` and `Clone`. This is also + /// used for the `DiscriminantKind` and `Pointee` trait, both of which have + /// an associated type. BuiltinCandidate { /// `false` if there are no *further* obligations. has_nested: bool, @@ -137,12 +143,6 @@ pub enum SelectionCandidate<'tcx> { is_const: bool, }, - /// Builtin implementation of `DiscriminantKind`. - DiscriminantKindCandidate, - - /// Builtin implementation of `Pointee`. - PointeeCandidate, - TraitAliasCandidate, /// Matching `dyn Trait` with a supertrait of `Trait`. The index is the diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs index 7fbd57ac7354a..4937c6b7dc514 100644 --- a/compiler/rustc_middle/src/traits/structural_impls.rs +++ b/compiler/rustc_middle/src/traits/structural_impls.rs @@ -17,10 +17,6 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> { super::ImplSource::FnPointer(ref d) => write!(f, "({:?})", d), - super::ImplSource::DiscriminantKind(ref d) => write!(f, "{:?}", d), - - super::ImplSource::Pointee(ref d) => write!(f, "{:?}", d), - super::ImplSource::Object(ref d) => write!(f, "{:?}", d), super::ImplSource::Param(ref n, ct) => { @@ -125,11 +121,3 @@ impl fmt::Debug for traits::ImplSourceConstDestructData { write!(f, "ImplSourceConstDestructData(nested={:?})", self.nested) } } - -/////////////////////////////////////////////////////////////////////////// -// Lift implementations - -TrivialTypeTraversalAndLiftImpls! { - super::ImplSourceDiscriminantKindData, - super::ImplSourcePointeeData, -} diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 7ac4fcfa64c68..fff3f0467dfc4 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -30,7 +30,7 @@ use rustc_middle::metadata::ModChild; use rustc_middle::ty::{self, DefIdTree}; use rustc_session::cstore::CrateStore; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind}; -use rustc_span::source_map::{respan, Spanned}; +use rustc_span::source_map::respan; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; @@ -329,10 +329,12 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { .iter() .map(|field| respan(field.span, field.ident.map_or(kw::Empty, |ident| ident.name))) .collect(); - self.insert_field_names(def_id, field_names); + self.r.field_names.insert(def_id, field_names); } - fn insert_field_names(&mut self, def_id: DefId, field_names: Vec>) { + fn insert_field_names_extern(&mut self, def_id: DefId) { + let field_names = + self.r.cstore().struct_field_names_untracked(def_id, self.r.session).collect(); self.r.field_names.insert(def_id, field_names); } @@ -995,8 +997,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { let cstore = self.r.cstore(); match res { Res::Def(DefKind::Struct, def_id) => { - let field_names = - cstore.struct_field_names_untracked(def_id, self.r.session).collect(); if let Some((ctor_kind, ctor_def_id)) = cstore.ctor_untracked(def_id) { let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id); let ctor_vis = cstore.visibility_untracked(ctor_def_id); @@ -1006,13 +1006,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { .struct_constructors .insert(def_id, (ctor_res, ctor_vis, field_visibilities)); } - self.insert_field_names(def_id, field_names); - } - Res::Def(DefKind::Union, def_id) => { - let field_names = - cstore.struct_field_names_untracked(def_id, self.r.session).collect(); - self.insert_field_names(def_id, field_names); + self.insert_field_names_extern(def_id) } + Res::Def(DefKind::Union, def_id) => self.insert_field_names_extern(def_id), Res::Def(DefKind::AssocFn, def_id) => { if cstore.fn_has_self_parameter_untracked(def_id, self.r.session) { self.r.has_self.insert(def_id); @@ -1514,20 +1510,16 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { }; // Define a constructor name in the value namespace. - let fields_id = if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(&variant.data) { + if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(&variant.data) { let ctor_def_id = self.r.local_def_id(ctor_node_id); let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id.to_def_id()); self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id)); self.r.visibilities.insert(ctor_def_id, ctor_vis); - ctor_def_id - } else { - def_id - }; + } // Record field names for error reporting. - // FIXME: Always use non-ctor id as the key. - self.insert_field_names_local(fields_id.to_def_id(), &variant.data); + self.insert_field_names_local(def_id.to_def_id(), &variant.data); visit::walk_variant(self, variant); } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index b340bee28c3c3..9c95adc628bc6 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -21,6 +21,7 @@ use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind}; use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::PrimTy; +use rustc_middle::ty::DefIdTree; use rustc_session::lint; use rustc_session::parse::feature_err; use rustc_session::Session; @@ -1462,7 +1463,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { _ => return false, } } - (Res::Def(DefKind::Ctor(_, CtorKind::Fn), def_id), _) if ns == ValueNS => { + (Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_def_id), _) if ns == ValueNS => { + let def_id = self.r.parent(ctor_def_id); if let Some(span) = self.def_span(def_id) { err.span_label(span, &format!("`{}` defined here", path_str)); } @@ -1953,7 +1955,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { )); } } else { - let needs_placeholder = |def_id: DefId, kind: CtorKind| { + let needs_placeholder = |ctor_def_id: DefId, kind: CtorKind| { + let def_id = self.r.parent(ctor_def_id); let has_no_fields = self.r.field_names.get(&def_id).map_or(false, |f| f.is_empty()); match kind { CtorKind::Const => false, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 9f19b0092c00f..9aab28f494476 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -11,8 +11,8 @@ use super::Selection; use super::SelectionContext; use super::SelectionError; use super::{ - ImplSourceClosureData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData, - ImplSourceGeneratorData, ImplSourcePointeeData, ImplSourceUserDefinedData, + ImplSourceClosureData, ImplSourceFnPointerData, ImplSourceGeneratorData, + ImplSourceUserDefinedData, }; use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey}; @@ -28,6 +28,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_infer::infer::resolve::OpportunisticRegionResolver; +use rustc_infer::traits::ImplSourceBuiltinData; use rustc_middle::traits::select::OverflowError; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable}; @@ -1612,128 +1613,126 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( } } } - super::ImplSource::DiscriminantKind(..) => { - // While `DiscriminantKind` is automatically implemented for every type, - // the concrete discriminant may not be known yet. - // - // Any type with multiple potential discriminant types is therefore not eligible. + super::ImplSource::Builtin(..) => { + // While a builtin impl may be known to exist, the associated type may not yet + // be known. Any type with multiple potential associated types is therefore + // not eligible. let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty()); - match self_ty.kind() { - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Adt(..) - | ty::Foreign(_) - | ty::Str - | ty::Array(..) - | ty::Slice(_) - | ty::RawPtr(..) - | ty::Ref(..) - | ty::FnDef(..) - | ty::FnPtr(..) - | ty::Dynamic(..) - | ty::Closure(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) - | ty::Never - | ty::Tuple(..) - // Integers and floats always have `u8` as their discriminant. - | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true, - - ty::Projection(..) - | ty::Opaque(..) - | ty::Param(..) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Infer(..) - | ty::Error(_) => false, - } - } - super::ImplSource::Pointee(..) => { - // While `Pointee` is automatically implemented for every type, - // the concrete metadata type may not be known yet. - // - // Any type with multiple potential metadata types is therefore not eligible. - let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty()); - - let tail = selcx.tcx().struct_tail_with_normalize( - self_ty, - |ty| { - // We throw away any obligations we get from this, since we normalize - // and confirm these obligations once again during confirmation - normalize_with_depth( - selcx, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - ty, - ) - .value - }, - || {}, - ); - - match tail.kind() { - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Str - | ty::Array(..) - | ty::Slice(_) - | ty::RawPtr(..) - | ty::Ref(..) - | ty::FnDef(..) - | ty::FnPtr(..) - | ty::Dynamic(..) - | ty::Closure(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) - | ty::Never - // Extern types have unit metadata, according to RFC 2850 - | ty::Foreign(_) - // If returned by `struct_tail_without_normalization` this is a unit struct - // without any fields, or not a struct, and therefore is Sized. - | ty::Adt(..) - // If returned by `struct_tail_without_normalization` this is the empty tuple. - | ty::Tuple(..) - // Integers and floats are always Sized, and so have unit type metadata. - | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true, - - // type parameters, opaques, and unnormalized projections have pointer - // metadata if they're known (e.g. by the param_env) to be sized - ty::Param(_) | ty::Projection(..) | ty::Opaque(..) - if selcx.infcx().predicate_must_hold_modulo_regions( - &obligation.with( - selcx.tcx(), - ty::Binder::dummy(selcx.tcx().at(obligation.cause.span).mk_trait_ref( - LangItem::Sized, - [self_ty], - )) - .without_const(), - ), - ) => - { - true + let lang_items = selcx.tcx().lang_items(); + if lang_items.discriminant_kind_trait() == Some(poly_trait_ref.def_id()) { + match self_ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(..) + | ty::Foreign(_) + | ty::Str + | ty::Array(..) + | ty::Slice(_) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Dynamic(..) + | ty::Closure(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Never + | ty::Tuple(..) + // Integers and floats always have `u8` as their discriminant. + | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true, + + // type parameters, opaques, and unnormalized projections have pointer + // metadata if they're known (e.g. by the param_env) to be sized + ty::Param(_) + | ty::Projection(..) + | ty::Opaque(..) + | ty::Bound(..) + | ty::Placeholder(..) + | ty::Infer(..) + | ty::Error(_) => false, } + } else if lang_items.pointee_trait() == Some(poly_trait_ref.def_id()) { + let tail = selcx.tcx().struct_tail_with_normalize( + self_ty, + |ty| { + // We throw away any obligations we get from this, since we normalize + // and confirm these obligations once again during confirmation + normalize_with_depth( + selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + ty, + ) + .value + }, + || {}, + ); - // FIXME(compiler-errors): are Bound and Placeholder types ever known sized? - ty::Param(_) - | ty::Projection(..) - | ty::Opaque(..) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Infer(..) - | ty::Error(_) => { - if tail.has_infer_types() { - candidate_set.mark_ambiguous(); + match tail.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Array(..) + | ty::Slice(_) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Dynamic(..) + | ty::Closure(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Never + // Extern types have unit metadata, according to RFC 2850 + | ty::Foreign(_) + // If returned by `struct_tail_without_normalization` this is a unit struct + // without any fields, or not a struct, and therefore is Sized. + | ty::Adt(..) + // If returned by `struct_tail_without_normalization` this is the empty tuple. + | ty::Tuple(..) + // Integers and floats are always Sized, and so have unit type metadata. + | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true, + + // type parameters, opaques, and unnormalized projections have pointer + // metadata if they're known (e.g. by the param_env) to be sized + ty::Param(_) | ty::Projection(..) | ty::Opaque(..) + if selcx.infcx().predicate_must_hold_modulo_regions( + &obligation.with( + selcx.tcx(), + ty::Binder::dummy( + selcx.tcx().at(obligation.cause.span()).mk_trait_ref(LangItem::Sized, [self_ty]), + ) + .without_const(), + ), + ) => + { + true + } + + // FIXME(compiler-errors): are Bound and Placeholder types ever known sized? + ty::Param(_) + | ty::Projection(..) + | ty::Opaque(..) + | ty::Bound(..) + | ty::Placeholder(..) + | ty::Infer(..) + | ty::Error(_) => { + if tail.has_infer_types() { + candidate_set.mark_ambiguous(); + } + false } - false } + } else { + bug!("unexpected builtin trait with associated type: {poly_trait_ref:?}") } } super::ImplSource::Param(..) => { @@ -1771,7 +1770,6 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( false } super::ImplSource::AutoImpl(..) - | super::ImplSource::Builtin(..) | super::ImplSource::TraitUpcasting(_) | super::ImplSource::ConstDestruct(_) => { // These traits have no associated types. @@ -1850,14 +1848,10 @@ fn confirm_select_candidate<'cx, 'tcx>( super::ImplSource::Generator(data) => confirm_generator_candidate(selcx, obligation, data), super::ImplSource::Closure(data) => confirm_closure_candidate(selcx, obligation, data), super::ImplSource::FnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data), - super::ImplSource::DiscriminantKind(data) => { - confirm_discriminant_kind_candidate(selcx, obligation, data) - } - super::ImplSource::Pointee(data) => confirm_pointee_candidate(selcx, obligation, data), + super::ImplSource::Builtin(data) => confirm_builtin_candidate(selcx, obligation, data), super::ImplSource::Object(_) | super::ImplSource::AutoImpl(..) | super::ImplSource::Param(..) - | super::ImplSource::Builtin(..) | super::ImplSource::TraitUpcasting(_) | super::ImplSource::TraitAlias(..) | super::ImplSource::ConstDestruct(_) => { @@ -1921,68 +1915,55 @@ fn confirm_generator_candidate<'cx, 'tcx>( .with_addl_obligations(obligations) } -fn confirm_discriminant_kind_candidate<'cx, 'tcx>( +fn confirm_builtin_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - _: ImplSourceDiscriminantKindData, + data: ImplSourceBuiltinData>, ) -> Progress<'tcx> { let tcx = selcx.tcx(); - - let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty()); - // We get here from `poly_project_and_unify_type` which replaces bound vars - // with placeholders - debug_assert!(!self_ty.has_escaping_bound_vars()); + let self_ty = obligation.predicate.self_ty(); let substs = tcx.mk_substs([self_ty.into()].iter()); - - let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None); - - let predicate = ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy { substs, item_def_id: discriminant_def_id }, - term: self_ty.discriminant_ty(tcx).into(), + let lang_items = tcx.lang_items(); + let item_def_id = obligation.predicate.item_def_id; + let trait_def_id = tcx.trait_of_item(item_def_id).unwrap(); + let (term, obligations) = if lang_items.discriminant_kind_trait() == Some(trait_def_id) { + let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None); + assert_eq!(discriminant_def_id, item_def_id); + + (self_ty.discriminant_ty(tcx).into(), Vec::new()) + } else if lang_items.pointee_trait() == Some(trait_def_id) { + let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); + assert_eq!(metadata_def_id, item_def_id); + + let mut obligations = Vec::new(); + let (metadata_ty, check_is_sized) = self_ty.ptr_metadata_ty(tcx, |ty| { + normalize_with_depth_to( + selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + ty, + &mut obligations, + ) + }); + if check_is_sized { + let sized_predicate = ty::Binder::dummy( + tcx.at(obligation.cause.span()).mk_trait_ref(LangItem::Sized, [self_ty]), + ) + .without_const(); + obligations.push(obligation.with(tcx, sized_predicate)); + } + (metadata_ty.into(), obligations) + } else { + bug!("unexpected builtin trait with associated type: {:?}", obligation.predicate); }; - // We get here from `poly_project_and_unify_type` which replaces bound vars - // with placeholders, so dummy is okay here. - confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false) -} - -fn confirm_pointee_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - _: ImplSourcePointeeData, -) -> Progress<'tcx> { - let tcx = selcx.tcx(); - let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty()); - - let mut obligations = vec![]; - let (metadata_ty, check_is_sized) = self_ty.ptr_metadata_ty(tcx, |ty| { - normalize_with_depth_to( - selcx, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - ty, - &mut obligations, - ) - }); - if check_is_sized { - let sized_predicate = ty::Binder::dummy( - tcx.at(obligation.cause.span).mk_trait_ref(LangItem::Sized, [self_ty]), - ) - .without_const(); - obligations.push(obligation.with(tcx, sized_predicate)); - } - - let substs = tcx.mk_substs([self_ty.into()].iter()); - let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, Some(obligation.cause.span)); - - let predicate = ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy { substs, item_def_id: metadata_def_id }, - term: metadata_ty.into(), - }; + let predicate = + ty::ProjectionPredicate { projection_ty: ty::ProjectionTy { substs, item_def_id }, term }; confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false) .with_addl_obligations(obligations) + .with_addl_obligations(data.nested) } fn confirm_fn_pointer_candidate<'cx, 'tcx>( diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 3b107d9570f14..21be9a546ed36 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -6,11 +6,9 @@ //! //! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly use hir::LangItem; -use rustc_errors::DelayDm; use rustc_hir as hir; use rustc_infer::traits::ObligationCause; use rustc_infer::traits::{Obligation, SelectionError, TraitObligation}; -use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Ty, TypeVisitable}; use rustc_target::spec::abi::Abi; @@ -284,10 +282,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates); } else if lang_items.discriminant_kind_trait() == Some(def_id) { // `DiscriminantKind` is automatically implemented for every type. - candidates.vec.push(DiscriminantKindCandidate); + candidates.vec.push(BuiltinCandidate { has_nested: false }); } else if lang_items.pointee_trait() == Some(def_id) { // `Pointee` is automatically implemented for every type. - candidates.vec.push(PointeeCandidate); + candidates.vec.push(BuiltinCandidate { has_nested: false }); } else if lang_items.sized_trait() == Some(def_id) { // Sized is never implementable by end-users, it is // always automatically computed. @@ -811,16 +809,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &obligation.cause, ) { if deref_trait_ref.def_id() == target_trait_did { - self.tcx().struct_span_lint_hir( - DEREF_INTO_DYN_SUPERTRAIT, - obligation.cause.body_id, - obligation.cause.span, - DelayDm(|| format!( - "`{}` implements `Deref` with supertrait `{}` as output", - source, deref_trait_ref - )), - |lint| lint, - ); return; } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 2ec5d925b6900..5edff1463f4f9 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -22,11 +22,11 @@ use crate::traits::util::{self, closure_trait_ref_and_return_type, predicate_for use crate::traits::{ BuiltinDerivedObligation, ImplDerivedObligation, ImplDerivedObligationCause, ImplSource, ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData, - ImplSourceConstDestructData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData, - ImplSourceGeneratorData, ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData, - ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, ObjectCastObligation, - Obligation, ObligationCause, OutputTypeParameterMismatch, PredicateObligation, Selection, - SelectionError, TraitNotObjectSafe, TraitObligation, Unimplemented, VtblSegment, + ImplSourceConstDestructData, ImplSourceFnPointerData, ImplSourceGeneratorData, + ImplSourceObjectData, ImplSourceTraitAliasData, ImplSourceTraitUpcastingData, + ImplSourceUserDefinedData, Normalized, ObjectCastObligation, Obligation, ObligationCause, + OutputTypeParameterMismatch, PredicateObligation, Selection, SelectionError, + TraitNotObjectSafe, TraitObligation, Unimplemented, VtblSegment, }; use super::BuiltinImplConditions; @@ -94,12 +94,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSource::FnPointer(data) } - DiscriminantKindCandidate => { - ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) - } - - PointeeCandidate => ImplSource::Pointee(ImplSourcePointeeData), - TraitAliasCandidate => { let data = self.confirm_trait_alias_candidate(obligation); ImplSource::TraitAlias(data) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 2803a2d38c807..0a412eadbe3ad 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1568,20 +1568,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => false, // (*) - ( - BuiltinCandidate { has_nested: false } - | DiscriminantKindCandidate - | PointeeCandidate - | ConstDestructCandidate(_), - _, - ) => true, - ( - _, - BuiltinCandidate { has_nested: false } - | DiscriminantKindCandidate - | PointeeCandidate - | ConstDestructCandidate(_), - ) => false, + (BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_), _) => true, + (_, BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_)) => false, (ParamCandidate(other), ParamCandidate(victim)) => { let same_except_bound_vars = other.skip_binder().trait_ref diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 6436713b38811..469108345b1d8 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -264,8 +264,6 @@ fn resolve_associated_item<'tcx>( traits::ImplSource::AutoImpl(..) | traits::ImplSource::Param(..) | traits::ImplSource::TraitAlias(..) - | traits::ImplSource::DiscriminantKind(..) - | traits::ImplSource::Pointee(..) | traits::ImplSource::TraitUpcasting(_) | traits::ImplSource::ConstDestruct(_) => None, }) diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index fbc0fc397a5df..92b1b3493994d 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -902,6 +902,12 @@ impl str { /// /// assert_eq!(None, iter.next()); /// ``` + /// + /// If the string is empty or all whitespace, the iterator yields no string slices: + /// ``` + /// assert_eq!("".split_whitespace().next(), None); + /// assert_eq!(" ".split_whitespace().next(), None); + /// ``` #[must_use = "this returns the split string as an iterator, \ without modifying the original"] #[stable(feature = "split_whitespace", since = "1.1.0")] @@ -946,6 +952,12 @@ impl str { /// /// assert_eq!(None, iter.next()); /// ``` + /// + /// If the string is empty or all ASCII whitespace, the iterator yields no string slices: + /// ``` + /// assert_eq!("".split_whitespace().next(), None); + /// assert_eq!(" ".split_whitespace().next(), None); + /// ``` #[must_use = "this returns the split string as an iterator, \ without modifying the original"] #[stable(feature = "split_ascii_whitespace", since = "1.34.0")] diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index d12874e1bfd1e..ef28e2a855a04 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1071,7 +1071,7 @@ fn write_impl_section_heading(w: &mut Buffer, title: &str, id: &str) { w, "

\ {title}\ - \ + §\

" ); } @@ -1536,7 +1536,7 @@ fn render_impl( render_rightside(w, cx, item, containing_item, render_mode); if trait_.is_some() { // Anchors are only used on trait impls. - write!(w, "", id); + write!(w, "§", id); } w.write_str("

"); render_assoc_item( @@ -1562,7 +1562,7 @@ fn render_impl( render_rightside(w, cx, item, containing_item, render_mode); if trait_.is_some() { // Anchors are only used on trait impls. - write!(w, "", id); + write!(w, "§", id); } w.write_str("

"); assoc_const( @@ -1587,7 +1587,7 @@ fn render_impl( write!(w, "
", id, item_type, in_trait_class); if trait_.is_some() { // Anchors are only used on trait impls. - write!(w, "", id); + write!(w, "§", id); } w.write_str("

"); assoc_type( @@ -1613,7 +1613,7 @@ fn render_impl( ); if trait_.is_some() { // Anchors are only used on trait impls. - write!(w, "", id); + write!(w, "§", id); } w.write_str("

"); assoc_type( @@ -1846,7 +1846,7 @@ pub(crate) fn render_impl_summary( }; write!(w, "
", id, aliases); render_rightside(w, cx, &i.impl_item, containing_item, RenderMode::Normal); - write!(w, "", id); + write!(w, "§", id); write!(w, "

"); if let Some(use_absolute) = use_absolute { diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index a0e5309a70cb0..0f9b3b15c77ff 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -717,7 +717,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: write!( w, "

\ - {1}\ + {1}§\

{2}", id, title, extra_content ) @@ -1147,7 +1147,7 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean: write!( w, "

\ - Fields\ + Fields§\

" ); for (field, ty) in fields { @@ -1156,7 +1156,7 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean: write!( w, "\ - \ + §\ {name}: {ty}\ ", id = id, @@ -1262,7 +1262,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: write!( w, "

\ - Variants{}\ + Variants{}§\

", document_non_exhaustive_header(it) ); @@ -1273,7 +1273,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: write!( w, "
\ - ", + §", id = id, ); render_stability_since_raw_with_extra( @@ -1325,7 +1325,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: w, "
\ \ - \ + §\ {f}: {t}\ ", id = id, @@ -1477,7 +1477,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean write!( w, "

\ - {}{}\ + {}{}§\

", if s.ctor_kind.is_none() { "Fields" } else { "Tuple Fields" }, document_non_exhaustive_header(it) @@ -1490,7 +1490,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean write!( w, "\ - \ + §\ {name}: {ty}\ ", item_type = ItemType::StructField, @@ -1908,7 +1908,7 @@ fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) { writeln!( w, "

\ - Layout

" + Layout§

" ); writeln!(w, "
"); diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 63530b924c270..e0a4f2364b682 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -730,9 +730,6 @@ a { h2.small-section-header > .anchor { padding-right: 6px; } -.anchor::before { - content: '§'; -} .main-heading a:hover, .example-wrap > pre.rust a:hover, diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index df13e597f1fdc..aa3bf827db4bf 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -115,6 +115,7 @@

{#- -#} > { + inner: I, +} + +impl> Iterator for TupleIter { + type Item = (T, T, T); + + fn next(&mut self) -> Option { + let inner = &mut self.inner; + + if let Some(first) = inner.next() + && let Some(second) = inner.next() + && let Some(third) = inner.next() + { + Some((first, second, third)) + } else { + None + } + } +} + +fn main() { + let vec: Vec = Vec::new(); + let mut tup_iter = TupleIter { + inner: vec.into_iter(), + }; + tup_iter.next(); +} diff --git a/src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs b/src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs index 5f5a2574bab03..d624187561ed7 100644 --- a/src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs +++ b/src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs @@ -7,7 +7,11 @@ use core::ops::Deref; // issue 89190 trait A {} trait B: A {} + impl<'a> Deref for dyn 'a + B { + //~^ ERROR `(dyn B + 'a)` implements `Deref` with supertrait `A` as target + //~| WARN this was previously accepted by the compiler but is being phased out; + type Target = dyn A; fn deref(&self) -> &Self::Target { todo!() @@ -18,8 +22,6 @@ fn take_a(_: &dyn A) {} fn whoops(b: &dyn B) { take_a(b) - //~^ ERROR `dyn B` implements `Deref` with supertrait `A` as output - //~^^ WARN this was previously accepted by the compiler but is being phased out; } fn main() {} diff --git a/src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr b/src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr index 41381a3ffd1c6..4533b1163425c 100644 --- a/src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr +++ b/src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr @@ -1,8 +1,11 @@ -error: `dyn B` implements `Deref` with supertrait `A` as output - --> $DIR/migrate-lint-deny.rs:20:12 +error: `(dyn B + 'a)` implements `Deref` with supertrait `A` as target + --> $DIR/migrate-lint-deny.rs:11:1 | -LL | take_a(b) - | ^ +LL | impl<'a> Deref for dyn 'a + B { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | type Target = dyn A; + | -------------------- target type is set here | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #89460 diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs index 06a39c5997e20..b4210d875104b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_opt; -use clippy_utils::ty::{get_associated_type, implements_trait, is_copy}; +use clippy_utils::ty::{implements_trait, is_copy}; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; @@ -25,7 +25,7 @@ pub(super) fn check<'tcx>( && let Some(method_id) = typeck.type_dependent_def_id(cloned_call.hir_id) && cx.tcx.trait_of_item(method_id) == Some(iter_id) && let cloned_recv_ty = typeck.expr_ty_adjusted(cloned_recv) - && let Some(iter_assoc_ty) = get_associated_type(cx, cloned_recv_ty, iter_id, "Item") + && let Some(iter_assoc_ty) = cx.get_associated_type(cloned_recv_ty, iter_id, "Item") && matches!(*iter_assoc_ty.kind(), ty::Ref(_, ty, _) if !is_copy(cx, ty)) { if needs_into_iter diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 4eb579af7a12a..52a4ff7d1ae4f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -2,7 +2,7 @@ use super::utils::clone_or_copy_needed; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::ForLoop; use clippy_utils::source::snippet_opt; -use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait}; +use clippy_utils::ty::{get_iterator_item_ty, implements_trait}; use clippy_utils::{fn_def_id, get_parent_expr}; use rustc_errors::Applicability; use rustc_hir::{def_id::DefId, Expr, ExprKind}; @@ -54,7 +54,7 @@ pub fn check_for_loop_iter( if let Some(into_iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator); let collection_ty = cx.typeck_results().expr_ty(collection); if implements_trait(cx, collection_ty, into_iterator_trait_id, &[]); - if let Some(into_iter_item_ty) = get_associated_type(cx, collection_ty, into_iterator_trait_id, "Item"); + if let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, "Item"); if iter_item_ty == into_iter_item_ty; if let Some(collection_snippet) = snippet_opt(cx, collection.span); diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index 375ebc903b400..8b000cd754cd1 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -2,9 +2,11 @@ use super::implicit_clone::is_clone_like; use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; -use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs}; +use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs}; use clippy_utils::visitors::find_all_ret_expressions; -use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty}; +use clippy_utils::{ + fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty, +}; use clippy_utils::{meets_msrv, msrvs}; use rustc_errors::Applicability; use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, Node}; @@ -18,7 +20,9 @@ use rustc_middle::ty::EarlyBinder; use rustc_middle::ty::{self, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty}; use rustc_semver::RustcVersion; use rustc_span::{sym, Symbol}; -use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause}; +use rustc_trait_selection::traits::{ + query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause, +}; use std::cmp::max; use super::UNNECESSARY_TO_OWNED; @@ -146,7 +150,7 @@ fn check_addr_of_expr( if_chain! { if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref); if implements_trait(cx, receiver_ty, deref_trait_id, &[]); - if get_associated_type(cx, receiver_ty, deref_trait_id, "Target") == Some(target_ty); + if cx.get_associated_type(receiver_ty, deref_trait_id, "Target") == Some(target_ty); then { if n_receiver_refs > 0 { span_lint_and_sugg( @@ -341,13 +345,13 @@ fn get_input_traits_and_projections<'tcx>( if trait_predicate.trait_ref.self_ty() == input { trait_predicates.push(trait_predicate); } - }, + } PredicateKind::Projection(projection_predicate) => { if projection_predicate.projection_ty.self_ty() == input { projection_predicates.push(projection_predicate); } - }, - _ => {}, + } + _ => {} } } (trait_predicates, projection_predicates) @@ -462,7 +466,12 @@ fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id: /// Returns true if the named method can be used to convert the receiver to its "owned" /// representation. -fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name: Symbol, method_def_id: DefId) -> bool { +fn is_to_owned_like<'a>( + cx: &LateContext<'a>, + call_expr: &Expr<'a>, + method_name: Symbol, + method_def_id: DefId, +) -> bool { is_clone_like(cx, method_name.as_str(), method_def_id) || is_cow_into_owned(cx, method_name, method_def_id) || is_to_string_on_string_like(cx, call_expr, method_name, method_def_id) @@ -490,7 +499,7 @@ fn is_to_string_on_string_like<'a>( && let GenericArgKind::Type(ty) = generic_arg.unpack() && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef) - && (get_associated_type(cx, ty, deref_trait_id, "Target") == Some(cx.tcx.types.str_) || + && (cx.get_associated_type(ty, deref_trait_id, "Target") == Some(cx.tcx.types.str_) || implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()])) { true } else { diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 1b65b701409e4..8284dc5c28c0b 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -117,24 +117,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' pub fn get_iterator_item_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { cx.tcx .get_diagnostic_item(sym::Iterator) - .and_then(|iter_did| get_associated_type(cx, ty, iter_did, "Item")) -} - -/// Returns the associated type `name` for `ty` as an implementation of `trait_id`. -/// Do not invoke without first verifying that the type implements the trait. -pub fn get_associated_type<'tcx>( - cx: &LateContext<'tcx>, - ty: Ty<'tcx>, - trait_id: DefId, - name: &str, -) -> Option> { - cx.tcx - .associated_items(trait_id) - .find_by_name_and_kind(cx.tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id) - .and_then(|assoc| { - let proj = cx.tcx.mk_projection(assoc.def_id, cx.tcx.mk_substs_trait(ty, [])); - cx.tcx.try_normalize_erasing_regions(cx.param_env, proj).ok() - }) + .and_then(|iter_did| cx.get_associated_type(ty, iter_did, "Item")) } /// Get the diagnostic name of a type, e.g. `sym::HashMap`. To check if a type