hax_frontend_exporter/traits/
utils.rs

1//! Each item can involve three kinds of predicates:
2//! - input aka required predicates: the predicates required to mention the item. These are usually `where`
3//!   clauses (or equivalent) on the item:
4//! ```ignore
5//! struct Foo<T: Clone> { ... }
6//! trait Foo<T> where T: Clone { ... }
7//! fn function<I>() where I: Iterator, I::Item: Clone { ... }
8//! ```
9//! - output aka implied predicates: the predicates that are implied by the presence of this item in a
10//!   signature. This is mostly trait parent predicates:
11//! ```ignore
12//! trait Foo: Clone { ... }
13//! fn bar<T: Foo>() {
14//!   // from `T: Foo` we can deduce `T: Clone`
15//! }
16//! ```
17//!   This could also include implied predicates such as `&'a T` implying `T: 'a` but we don't
18//!   consider these.
19//! - "self" predicate: that's the special `Self: Trait` predicate in scope within a trait
20//!   declaration or implementation for trait `Trait`.
21//!
22//! Note that within a given item the polarity is reversed: input predicates are the ones that can
23//! be assumed to hold and output predicates must be proven to hold. The "self" predicate is both
24//! assumed and proven within an impl block, and just assumed within a trait declaration block.
25//!
26//! The current implementation considers all predicates on traits to be outputs, which has the
27//! benefit of reducing the size of signatures. Moreover, the rules on which bounds are required vs
28//! implied are subtle. We may change this if this proves to be a problem.
29use rustc_hir::def::DefKind;
30use rustc_middle::ty::*;
31use rustc_span::def_id::DefId;
32
33/// Returns a list of type predicates for the definition with ID `def_id`, including inferred
34/// lifetime constraints. This is the basic list of predicates we use for essentially all items.
35pub fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> GenericPredicates<'_> {
36    let mut result = tcx.explicit_predicates_of(def_id);
37    let inferred_outlives = tcx.inferred_outlives_of(def_id);
38    if !inferred_outlives.is_empty() {
39        let inferred_outlives_iter = inferred_outlives
40            .iter()
41            .map(|(clause, span)| ((*clause).upcast(tcx), *span));
42        result.predicates = tcx.arena.alloc_from_iter(
43            result
44                .predicates
45                .into_iter()
46                .copied()
47                .chain(inferred_outlives_iter),
48        );
49    }
50    result
51}
52
53/// The predicates that must hold to mention this item. E.g.
54///
55/// ```ignore
56/// // `U: OtherTrait` is required, `Self: Sized` is implied.
57/// trait Trait<U: OtherTrait>: Sized {
58///     // `T: Clone` is required, `Self::Type<T>: Debug` is implied.
59///     type Type<T: Clone>: Debug;
60/// }
61/// ```
62pub fn required_predicates<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> GenericPredicates<'tcx> {
63    use DefKind::*;
64    match tcx.def_kind(def_id) {
65        AssocConst
66        | AssocFn
67        | AssocTy
68        | Const
69        | Enum
70        | Fn
71        | ForeignTy
72        | Impl { .. }
73        | OpaqueTy
74        | Static { .. }
75        | Struct
76        | TraitAlias
77        | TyAlias
78        | Union => predicates_defined_on(tcx, def_id),
79        // We consider all predicates on traits to be outputs
80        Trait => Default::default(),
81        // `predicates_defined_on` ICEs on other def kinds.
82        _ => Default::default(),
83    }
84}
85
86/// The special "self" predicate on a trait.
87pub fn self_predicate<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> PolyTraitRef<'tcx> {
88    // Copied from the code of `tcx.predicates_of()`.
89    Binder::dummy(TraitRef::identity(tcx, def_id))
90}
91
92/// The predicates that can be deduced from the presence of this item in a signature. We only
93/// consider predicates implied by traits here, not implied bounds such as `&'a T` implying `T:
94/// 'a`. E.g.
95///
96/// ```ignore
97/// // `U: OtherTrait` is required, `Self: Sized` is implied.
98/// trait Trait<U: OtherTrait>: Sized {
99///     // `T: Clone` is required, `Self::Type<T>: Debug` is implied.
100///     type Type<T: Clone>: Debug;
101/// }
102/// ```
103pub fn implied_predicates<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> GenericPredicates<'tcx> {
104    use DefKind::*;
105    let parent = tcx.opt_parent(def_id);
106    match tcx.def_kind(def_id) {
107        // We consider all predicates on traits to be outputs
108        Trait => predicates_defined_on(tcx, def_id),
109        AssocTy if matches!(tcx.def_kind(parent.unwrap()), Trait) => {
110            GenericPredicates {
111                parent,
112                // `skip_binder` is for an `EarlyBinder`
113                predicates: tcx.explicit_item_bounds(def_id).skip_binder(),
114                ..GenericPredicates::default()
115            }
116        }
117        _ => GenericPredicates::default(),
118    }
119}
120
121/// Erase all regions. Largely copied from `tcx.erase_regions`.
122pub fn erase_all_regions<'tcx, T>(tcx: TyCtxt<'tcx>, value: T) -> T
123where
124    T: TypeFoldable<TyCtxt<'tcx>>,
125{
126    use rustc_middle::ty;
127    struct RegionEraserVisitor<'tcx> {
128        tcx: TyCtxt<'tcx>,
129    }
130
131    impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RegionEraserVisitor<'tcx> {
132        fn cx(&self) -> TyCtxt<'tcx> {
133            self.tcx
134        }
135
136        fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
137            ty.super_fold_with(self)
138        }
139
140        fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
141        where
142            T: TypeFoldable<TyCtxt<'tcx>>,
143        {
144            // Empty the binder
145            Binder::dummy(t.skip_binder().fold_with(self))
146        }
147
148        fn fold_region(&mut self, _r: ty::Region<'tcx>) -> ty::Region<'tcx> {
149            // We erase bound regions despite it being possibly incorrect. `for<'a> fn(&'a
150            // ())` and `fn(&'free ())` are different types: they may implement different
151            // traits and have a different `TypeId`. It's unclear whether this can cause us
152            // to select the wrong trait reference.
153            self.tcx.lifetimes.re_erased
154        }
155    }
156    value.fold_with(&mut RegionEraserVisitor { tcx })
157}
158
159// Lifetimes are irrelevant when resolving instances.
160pub fn erase_and_norm<'tcx, T>(tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>, x: T) -> T
161where
162    T: TypeFoldable<TyCtxt<'tcx>> + Copy,
163{
164    erase_all_regions(
165        tcx,
166        tcx.try_normalize_erasing_regions(typing_env, x)
167            .unwrap_or(x),
168    )
169}
170
171pub trait ToPolyTraitRef<'tcx> {
172    fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>;
173}
174
175impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> {
176    fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> {
177        self.map_bound_ref(|trait_pred| trait_pred.trait_ref)
178    }
179}