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