]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
Rollup merge of #107656 - jonhoo:bump-rust-installer, r=Mark-Simulacrum
[rust.git] / compiler / rustc_lint / src / deref_into_dyn_supertrait.rs
1 use crate::{
2     lints::{SupertraitAsDerefTarget, SupertraitAsDerefTargetLabel},
3     LateContext, LateLintPass, LintContext,
4 };
5
6 use rustc_hir as hir;
7 use rustc_middle::{traits::util::supertraits, ty};
8 use rustc_span::sym;
9
10 declare_lint! {
11     /// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the
12     /// `Deref` implementation with a `dyn SuperTrait` type as `Output`.
13     ///
14     /// These implementations will become shadowed when the `trait_upcasting` feature is stabilized.
15     /// The `deref` functions will no longer be called implicitly, so there might be behavior change.
16     ///
17     /// ### Example
18     ///
19     /// ```rust,compile_fail
20     /// #![deny(deref_into_dyn_supertrait)]
21     /// #![allow(dead_code)]
22     ///
23     /// use core::ops::Deref;
24     ///
25     /// trait A {}
26     /// trait B: A {}
27     /// impl<'a> Deref for dyn 'a + B {
28     ///     type Target = dyn A;
29     ///     fn deref(&self) -> &Self::Target {
30     ///         todo!()
31     ///     }
32     /// }
33     ///
34     /// fn take_a(_: &dyn A) { }
35     ///
36     /// fn take_b(b: &dyn B) {
37     ///     take_a(b);
38     /// }
39     /// ```
40     ///
41     /// {{produces}}
42     ///
43     /// ### Explanation
44     ///
45     /// The dyn upcasting coercion feature adds new coercion rules, taking priority
46     /// over certain other coercion rules, which will cause some behavior change.
47     pub DEREF_INTO_DYN_SUPERTRAIT,
48     Warn,
49     "`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future",
50     @future_incompatible = FutureIncompatibleInfo {
51         reference: "issue #89460 <https://github.com/rust-lang/rust/issues/89460>",
52     };
53 }
54
55 declare_lint_pass!(DerefIntoDynSupertrait => [DEREF_INTO_DYN_SUPERTRAIT]);
56
57 impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
58     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
59         // `Deref` is being implemented for `t`
60         if let hir::ItemKind::Impl(impl_) = item.kind
61             && let Some(trait_) = &impl_.of_trait
62             && let t = cx.tcx.type_of(item.owner_id)
63             && let opt_did @ Some(did) = trait_.trait_def_id()
64             && opt_did == cx.tcx.lang_items().deref_trait()
65             // `t` is `dyn t_principal`
66             && let ty::Dynamic(data, _, ty::Dyn) = t.kind()
67             && let Some(t_principal) = data.principal()
68             // `<T as Deref>::Target` is `dyn target_principal`
69             && let Some(target) = cx.get_associated_type(t, did, "Target")
70             && let ty::Dynamic(data, _, ty::Dyn) = target.kind()
71             && let Some(target_principal) = data.principal()
72             // `target_principal` is a supertrait of `t_principal`
73             && supertraits(cx.tcx, t_principal.with_self_ty(cx.tcx, cx.tcx.types.trait_object_dummy_self))
74                 .any(|sup| sup.map_bound(|x| ty::ExistentialTraitRef::erase_self_ty(cx.tcx, x)) == target_principal)
75         {
76             let label = impl_.items.iter().find_map(|i| (i.ident.name == sym::Target).then_some(i.span)).map(|label| SupertraitAsDerefTargetLabel {
77                 label,
78             });
79             cx.emit_spanned_lint(DEREF_INTO_DYN_SUPERTRAIT, cx.tcx.def_span(item.owner_id.def_id), SupertraitAsDerefTarget {
80                 t,
81                 target_principal: target_principal.to_string(),
82                 label,
83             });
84         }
85     }
86 }