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}