hax_frontend_exporter/traits/
utils.rs1use hax_frontend_exporter_options::BoundsOptions;
30use rustc_hir::LangItem;
31use rustc_hir::def::DefKind;
32use rustc_middle::ty::*;
33use rustc_span::def_id::DefId;
34use rustc_span::{DUMMY_SP, Span};
35use std::borrow::Cow;
36
37pub type Predicates<'tcx> = Cow<'tcx, [(Clause<'tcx>, Span)]>;
38
39pub fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> Predicates<'_> {
42 let mut result = Cow::Borrowed(tcx.explicit_predicates_of(def_id).predicates);
43 let inferred_outlives = tcx.inferred_outlives_of(def_id);
44 if !inferred_outlives.is_empty() {
45 result.to_mut().extend(
46 inferred_outlives
47 .iter()
48 .map(|(clause, span)| ((*clause).upcast(tcx), *span)),
49 );
50 }
51 result
52}
53
54fn add_destruct_bounds<'tcx>(
56 tcx: TyCtxt<'tcx>,
57 def_id: DefId,
58 predicates: &mut Vec<(Clause<'tcx>, Span)>,
59) {
60 let def_kind = tcx.def_kind(def_id);
61 if matches!(def_kind, DefKind::Closure) {
62 return;
65 }
66 let destruct_trait = tcx.lang_items().destruct_trait().unwrap();
68 let extra_bounds = tcx
69 .generics_of(def_id)
70 .own_params
71 .iter()
72 .filter(|param| matches!(param.kind, GenericParamDefKind::Type { .. }))
73 .map(|param| tcx.mk_param_from_def(param))
74 .map(|ty| Binder::dummy(TraitRef::new(tcx, destruct_trait, [ty])))
75 .map(|tref| tref.upcast(tcx))
76 .map(|clause| (clause, DUMMY_SP));
77 predicates.extend(extra_bounds);
78}
79
80pub fn required_predicates<'tcx>(
92 tcx: TyCtxt<'tcx>,
93 def_id: DefId,
94 options: BoundsOptions,
95) -> Predicates<'tcx> {
96 use DefKind::*;
97 let def_kind = tcx.def_kind(def_id);
98 let mut predicates = match def_kind {
99 AssocConst
100 | AssocFn
101 | AssocTy
102 | Const
103 | Enum
104 | Fn
105 | ForeignTy
106 | Impl { .. }
107 | OpaqueTy
108 | Static { .. }
109 | Struct
110 | TyAlias
111 | Union => predicates_defined_on(tcx, def_id),
112 Trait | TraitAlias => Default::default(),
114 _ => Default::default(),
116 };
117 if !matches!(def_kind, AssocTy)
120 && let Some(trait_def_id) = tcx.trait_of_assoc(def_id)
121 {
122 let self_clause = self_predicate(tcx, trait_def_id).upcast(tcx);
123 predicates.to_mut().insert(0, (self_clause, DUMMY_SP));
124 }
125 if options.resolve_destruct && !matches!(def_kind, Trait | TraitAlias) {
126 add_destruct_bounds(tcx, def_id, predicates.to_mut());
129 }
130 if options.prune_sized {
131 prune_sized_predicates(tcx, &mut predicates);
132 }
133 predicates
134}
135
136pub fn self_predicate<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> PolyTraitRef<'tcx> {
138 Binder::dummy(TraitRef::identity(tcx, def_id))
140}
141
142pub fn implied_predicates<'tcx>(
156 tcx: TyCtxt<'tcx>,
157 def_id: DefId,
158 options: BoundsOptions,
159) -> Predicates<'tcx> {
160 use DefKind::*;
161 let parent = tcx.opt_parent(def_id);
162 let mut predicates = match tcx.def_kind(def_id) {
163 Trait | TraitAlias => {
165 let mut predicates = predicates_defined_on(tcx, def_id);
166 if options.resolve_destruct {
167 if !matches!(
170 tcx.as_lang_item(def_id),
171 Some(
172 LangItem::Destruct
173 | LangItem::Sized
174 | LangItem::MetaSized
175 | LangItem::PointeeSized
176 | LangItem::DiscriminantKind
177 | LangItem::PointeeTrait
178 | LangItem::Tuple
179 )
180 ) {
181 add_destruct_bounds(tcx, def_id, predicates.to_mut());
182 }
183 }
184 predicates
185 }
186 AssocTy if matches!(tcx.def_kind(parent.unwrap()), Trait) => {
187 let mut predicates = Cow::Borrowed(tcx.explicit_item_bounds(def_id).skip_binder());
189 if options.resolve_destruct {
190 let destruct_trait = tcx.lang_items().destruct_trait().unwrap();
192 let ty =
193 Ty::new_projection(tcx, def_id, GenericArgs::identity_for_item(tcx, def_id));
194 let tref = Binder::dummy(TraitRef::new(tcx, destruct_trait, [ty]));
195 predicates.to_mut().push((tref.upcast(tcx), DUMMY_SP));
196 }
197 predicates
198 }
199 _ => Predicates::default(),
200 };
201 if options.prune_sized {
202 prune_sized_predicates(tcx, &mut predicates);
203 }
204 predicates
205}
206
207pub fn normalize<'tcx, T>(tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>, value: T) -> T
209where
210 T: TypeFoldable<TyCtxt<'tcx>> + Clone,
211{
212 use rustc_infer::infer::TyCtxtInferExt;
213 use rustc_middle::traits::ObligationCause;
214 use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
215 let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
216 infcx
217 .at(&ObligationCause::dummy(), param_env)
218 .query_normalize(value.clone())
219 .map(|x| x.value)
221 .unwrap_or(value)
222}
223
224pub fn erase_free_regions<'tcx, T>(tcx: TyCtxt<'tcx>, value: T) -> T
228where
229 T: TypeFoldable<TyCtxt<'tcx>>,
230{
231 use rustc_middle::ty;
232 struct RegionEraserVisitor<'tcx> {
233 tcx: TyCtxt<'tcx>,
234 depth: u32,
235 }
236
237 impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RegionEraserVisitor<'tcx> {
238 fn cx(&self) -> TyCtxt<'tcx> {
239 self.tcx
240 }
241
242 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
243 ty.super_fold_with(self)
244 }
245
246 fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
247 where
248 T: TypeFoldable<TyCtxt<'tcx>>,
249 {
250 let t = self.tcx.anonymize_bound_vars(t);
251 self.depth += 1;
252 let t = t.super_fold_with(self);
253 self.depth -= 1;
254 t
255 }
256
257 fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
258 match r.kind() {
261 ty::ReBound(BoundVarIndexKind::Bound(dbid), _) if dbid.as_u32() < self.depth => r,
262 _ => self.tcx.lifetimes.re_erased,
263 }
264 }
265 }
266 value.fold_with(&mut RegionEraserVisitor { tcx, depth: 0 })
267}
268
269pub fn erase_and_norm<'tcx, T>(tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>, x: T) -> T
272where
273 T: TypeFoldable<TyCtxt<'tcx>> + Copy,
274{
275 erase_free_regions(
276 tcx,
277 tcx.try_normalize_erasing_regions(typing_env, x)
278 .unwrap_or(x),
279 )
280}
281
282pub fn normalize_bound_val<'tcx, T>(
287 tcx: TyCtxt<'tcx>,
288 typing_env: TypingEnv<'tcx>,
289 x: Binder<'tcx, T>,
290) -> Binder<'tcx, T>
291where
292 T: TypeFoldable<TyCtxt<'tcx>> + Copy,
293{
294 Binder::dummy(erase_and_norm(tcx, typing_env, x.skip_binder()))
295}
296
297pub fn is_sized_related_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
299 use rustc_hir::lang_items::LangItem;
300 let lang_item = tcx.as_lang_item(def_id);
301 matches!(
302 lang_item,
303 Some(LangItem::PointeeSized | LangItem::MetaSized | LangItem::Sized)
304 )
305}
306
307fn prune_sized_predicates<'tcx>(tcx: TyCtxt<'tcx>, generic_predicates: &mut Predicates<'tcx>) {
310 let predicates: Vec<(Clause<'tcx>, rustc_span::Span)> = generic_predicates
311 .iter()
312 .filter(|(clause, _)| {
313 clause.as_trait_clause().is_some_and(|trait_predicate| {
314 !is_sized_related_trait(tcx, trait_predicate.skip_binder().def_id())
315 })
316 })
317 .copied()
318 .collect();
319 if predicates.len() != generic_predicates.len() {
320 *generic_predicates.to_mut() = predicates;
321 }
322}
323
324pub trait ToPolyTraitRef<'tcx> {
325 fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>;
326}
327
328impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> {
329 fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> {
330 self.map_bound_ref(|trait_pred| trait_pred.trait_ref)
331 }
332}