|  | use rustc_hir::{self as hir, LangItem}; | 
|  | use rustc_middle::ty; | 
|  | use rustc_session::{declare_lint, declare_lint_pass}; | 
|  | use rustc_span::{Ident, sym}; | 
|  | use rustc_trait_selection::traits::supertraits; | 
|  |  | 
|  | use crate::lints::{SupertraitAsDerefTarget, SupertraitAsDerefTargetLabel}; | 
|  | use crate::{LateContext, LateLintPass, LintContext}; | 
|  |  | 
|  | declare_lint! { | 
|  | /// The `deref_into_dyn_supertrait` lint is emitted whenever there is a `Deref` implementation | 
|  | /// for `dyn SubTrait` with a `dyn SuperTrait` type as the `Output` type. | 
|  | /// | 
|  | /// These implementations are "shadowed" by trait upcasting (stabilized since | 
|  | /// 1.86.0). The `deref` functions is no longer called implicitly, which might | 
|  | /// change behavior compared to previous rustc versions. | 
|  | /// | 
|  | /// ### 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 trait upcasting coercion added a new coercion rule, taking priority over certain other | 
|  | /// coercion rules, which causes some behavior change compared to older `rustc` versions. | 
|  | /// | 
|  | /// `deref` can be still called explicitly, it just isn't called as part of a deref coercion | 
|  | /// (since trait upcasting coercion takes priority). | 
|  | pub DEREF_INTO_DYN_SUPERTRAIT, | 
|  | Allow, | 
|  | "`Deref` implementation with a supertrait trait object for output is shadowed by trait upcasting", | 
|  | } | 
|  |  | 
|  | 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>) { | 
|  | let tcx = cx.tcx; | 
|  | // `Deref` is being implemented for `t` | 
|  | if let hir::ItemKind::Impl(impl_) = item.kind | 
|  | // the trait is a `Deref` implementation | 
|  | && let Some(of_trait) = &impl_.of_trait | 
|  | && let Some(did) = of_trait.trait_ref.trait_def_id() | 
|  | && tcx.is_lang_item(did, LangItem::Deref) | 
|  | // the self type is `dyn t_principal` | 
|  | && let self_ty = tcx.type_of(item.owner_id).instantiate_identity() | 
|  | && let ty::Dynamic(data, _) = self_ty.kind() | 
|  | && let Some(self_principal) = data.principal() | 
|  | // `<T as Deref>::Target` is `dyn target_principal` | 
|  | && let Some(target) = cx.get_associated_type(self_ty, did, sym::Target) | 
|  | && let ty::Dynamic(data, _) = target.kind() | 
|  | && let Some(target_principal) = data.principal() | 
|  | // `target_principal` is a supertrait of `t_principal` | 
|  | && let Some(supertrait_principal) = supertraits(tcx, self_principal.with_self_ty(tcx, self_ty)) | 
|  | .find(|supertrait| supertrait.def_id() == target_principal.def_id()) | 
|  | { | 
|  | // erase regions in self type for better diagnostic presentation | 
|  | let (self_ty, target_principal, supertrait_principal) = | 
|  | tcx.erase_and_anonymize_regions((self_ty, target_principal, supertrait_principal)); | 
|  | let label2 = tcx | 
|  | .associated_items(item.owner_id) | 
|  | .find_by_ident_and_kind( | 
|  | tcx, | 
|  | Ident::with_dummy_span(sym::Target), | 
|  | ty::AssocTag::Type, | 
|  | item.owner_id.to_def_id(), | 
|  | ) | 
|  | .map(|label| SupertraitAsDerefTargetLabel { label: tcx.def_span(label.def_id) }); | 
|  | let span = tcx.def_span(item.owner_id.def_id); | 
|  | cx.emit_span_lint( | 
|  | DEREF_INTO_DYN_SUPERTRAIT, | 
|  | span, | 
|  | SupertraitAsDerefTarget { | 
|  | self_ty, | 
|  | supertrait_principal: supertrait_principal.map_bound(|trait_ref| { | 
|  | ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) | 
|  | }), | 
|  | target_principal, | 
|  | label: span, | 
|  | label2, | 
|  | }, | 
|  | ); | 
|  | } | 
|  | } | 
|  | } |