hax_frontend_exporter/
traits.rs

1use crate::prelude::*;
2
3#[cfg(feature = "rustc")]
4pub mod resolution;
5#[cfg(feature = "rustc")]
6mod utils;
7#[cfg(feature = "rustc")]
8pub use utils::{
9    Predicates, ToPolyTraitRef, erase_and_norm, erase_free_regions, implied_predicates, normalize,
10    predicates_defined_on, required_predicates, self_predicate,
11};
12
13#[cfg(feature = "rustc")]
14pub use resolution::PredicateSearcher;
15#[cfg(feature = "rustc")]
16use rustc_middle::ty;
17#[cfg(feature = "rustc")]
18use rustc_span::def_id::DefId as RDefId;
19
20#[cfg(feature = "rustc")]
21pub use utils::is_sized_related_trait;
22
23#[derive_group(Serializers)]
24#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, JsonSchema)]
25pub enum ImplExprPathChunk {
26    AssocItem {
27        /// Reference to the item, with generics (for GATs), e.g. the `T` and `T: Clone` `ImplExpr`
28        /// in the following example:
29        /// ```ignore
30        /// trait Foo {
31        ///     type Type<T: Clone>: Debug;
32        /// }
33        /// ```
34        item: ItemRef,
35        assoc_item: AssocItem,
36        /// The implemented predicate.
37        predicate: Binder<TraitPredicate>,
38        predicate_id: PredicateId,
39        /// The index of this predicate in the list returned by `implied_predicates`.
40        index: usize,
41    },
42    Parent {
43        /// The implemented predicate.
44        predicate: Binder<TraitPredicate>,
45        predicate_id: PredicateId,
46        /// The index of this predicate in the list returned by `implied_predicates`.
47        index: usize,
48    },
49}
50
51#[cfg(feature = "rustc")]
52impl<'tcx, S: UnderOwnerState<'tcx>> SInto<S, ImplExprPathChunk> for resolution::PathChunk<'tcx> {
53    fn sinto(&self, s: &S) -> ImplExprPathChunk {
54        match self {
55            resolution::PathChunk::AssocItem {
56                item,
57                generic_args,
58                predicate,
59                index,
60                ..
61            } => ImplExprPathChunk::AssocItem {
62                item: translate_item_ref(s, item.def_id, generic_args),
63                assoc_item: AssocItem::sfrom(s, item),
64                predicate: predicate.sinto(s),
65                predicate_id: <_ as SInto<_, Clause>>::sinto(predicate, s).id,
66                index: index.sinto(s),
67            },
68            resolution::PathChunk::Parent {
69                predicate, index, ..
70            } => ImplExprPathChunk::Parent {
71                predicate: predicate.sinto(s),
72                predicate_id: <_ as SInto<_, Clause>>::sinto(predicate, s).id,
73                index: index.sinto(s),
74            },
75        }
76    }
77}
78
79/// The source of a particular trait implementation. Most often this is either `Concrete` for a
80/// concrete `impl Trait for Type {}` item, or `LocalBound` for a context-bound `where T: Trait`.
81#[derive(AdtInto)]
82#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: resolution::ImplExprAtom<'tcx>, state: S as s)]
83#[derive_group(Serializers)]
84#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, JsonSchema)]
85pub enum ImplExprAtom {
86    /// A concrete `impl Trait for Type {}` item.
87    #[custom_arm(FROM_TYPE::Concrete { def_id, generics } => TO_TYPE::Concrete(
88        translate_item_ref(s, *def_id, generics),
89    ),)]
90    Concrete(ItemRef),
91    /// A context-bound clause like `where T: Trait`.
92    LocalBound {
93        #[not_in_source]
94        #[value({
95            let Self::LocalBound { predicate, .. } = self else { unreachable!() };
96            predicate.sinto(s).id
97        })]
98        predicate_id: PredicateId,
99        /// The nth (non-self) predicate found for this item. We use predicates from
100        /// `required_predicates` starting from the parentmost item.
101        index: usize,
102        r#trait: Binder<TraitRef>,
103        path: Vec<ImplExprPathChunk>,
104    },
105    /// The implicit `Self: Trait` clause present inside a `trait Trait {}` item.
106    // TODO: should we also get that clause for trait impls?
107    SelfImpl {
108        r#trait: Binder<TraitRef>,
109        path: Vec<ImplExprPathChunk>,
110    },
111    /// `dyn Trait` is a wrapped value with a virtual table for trait
112    /// `Trait`.  In other words, a value `dyn Trait` is a dependent
113    /// triple that gathers a type τ, a value of type τ and an
114    /// instance of type `Trait`.
115    /// `dyn Trait` implements `Trait` using a built-in implementation; this refers to that
116    /// built-in implementation.
117    Dyn,
118    /// A built-in trait whose implementation is computed by the compiler, such as `FnMut`. This
119    /// morally points to an invisible `impl` block; as such it contains the information we may
120    /// need from one.
121    Builtin {
122        /// Extra data for the given trait.
123        trait_data: BuiltinTraitData,
124        /// The `ImplExpr`s required to satisfy the implied predicates on the trait declaration.
125        /// E.g. since `FnMut: FnOnce`, a built-in `T: FnMut` impl would have an `ImplExpr` for `T:
126        /// FnOnce`.
127        impl_exprs: Vec<ImplExpr>,
128        /// The values of the associated types for this trait.
129        types: Vec<(DefId, Ty, Vec<ImplExpr>)>,
130    },
131    /// An error happened while resolving traits.
132    Error(String),
133}
134
135#[derive(AdtInto)]
136#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: resolution::BuiltinTraitData<'tcx>, state: S as s)]
137#[derive_group(Serializers)]
138#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, JsonSchema)]
139pub enum BuiltinTraitData {
140    /// A virtual `Drop` implementation.
141    /// `Drop` doesn't work like a real trait but we want to pretend it does. If a type has a
142    /// user-defined `impl Drop for X` we just use the `Concrete` variant, but if it doesn't we use
143    /// this variant to supply the data needed to know what code will run on drop.
144    Drop(DropData),
145    /// Some other builtin trait.
146    Other,
147}
148
149#[derive(AdtInto)]
150#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: resolution::DropData<'tcx>, state: S as s)]
151#[derive_group(Serializers)]
152#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, JsonSchema)]
153pub enum DropData {
154    /// A drop that does nothing, e.g. for scalars and pointers.
155    Noop,
156    /// An implicit `Drop` local clause, if the `resolve_drop_bounds` option is `false`. If that
157    /// option is `true`, we'll add `Drop` bounds to every type param, and use that to resolve
158    /// `Drop` impls of generics. If it's `false`, we use this variant to indicate that the drop
159    /// clause comes from a generic or associated type.
160    Implicit,
161    /// The implicit `Drop` impl that exists for every type without an explicit `Drop` impl. The
162    /// virtual impl is considered to have one `T: Drop` bound for each generic argument of the
163    /// target type; it then simply drops each field in order.
164    Glue {
165        /// The type we're generating glue for.
166        ty: Ty,
167        /// The `ImplExpr`s for the `T: Drop` bounds of the virtual impl. There is one for each
168        /// generic argument, in order.
169        impl_exprs: Vec<ImplExpr>,
170    },
171}
172
173/// An `ImplExpr` describes the full data of a trait implementation. Because of generics, this may
174/// need to combine several concrete trait implementation items. For example, `((1u8, 2u8),
175/// "hello").clone()` combines the generic implementation of `Clone` for `(A, B)` with the
176/// concrete implementations for `u8` and `&str`, represented as a tree.
177#[derive_group(Serializers)]
178#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, JsonSchema, AdtInto)]
179#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: resolution::ImplExpr<'tcx>, state: S as s)]
180pub struct ImplExpr {
181    /// The trait this is an impl for.
182    pub r#trait: Binder<TraitRef>,
183    /// The kind of implemention of the root of the tree.
184    pub r#impl: ImplExprAtom,
185}
186
187/// Given a clause `clause` in the context of some impl block `impl_did`, susbts correctly `Self`
188/// from `clause` and (1) derive a `Clause` and (2) resolve an `ImplExpr`.
189#[cfg(feature = "rustc")]
190pub fn super_clause_to_clause_and_impl_expr<'tcx, S: UnderOwnerState<'tcx>>(
191    s: &S,
192    impl_did: rustc_span::def_id::DefId,
193    clause: rustc_middle::ty::Clause<'tcx>,
194    span: rustc_span::Span,
195) -> Option<(Clause, ImplExpr, Span)> {
196    let tcx = s.base().tcx;
197    let impl_trait_ref = tcx
198        .impl_trait_ref(impl_did)
199        .map(|binder| rustc_middle::ty::Binder::dummy(binder.instantiate_identity()))?;
200    let original_predicate_id = {
201        // We don't want the id of the substituted clause id, but the
202        // original clause id (with, i.e., `Self`)
203        let s = &s.with_owner_id(impl_trait_ref.def_id());
204        clause.sinto(s).id
205    };
206    let new_clause = clause.instantiate_supertrait(tcx, impl_trait_ref);
207    let impl_expr = solve_trait(
208        s,
209        new_clause
210            .as_predicate()
211            .as_trait_clause()?
212            .to_poly_trait_ref(),
213    );
214    let mut new_clause_no_binder = new_clause.sinto(s);
215    new_clause_no_binder.id = original_predicate_id;
216    Some((new_clause_no_binder, impl_expr, span.sinto(s)))
217}
218
219/// This is the entrypoint of the solving.
220#[cfg(feature = "rustc")]
221#[tracing::instrument(level = "trace", skip(s))]
222pub fn solve_trait<'tcx, S: UnderOwnerState<'tcx>>(
223    s: &S,
224    trait_ref: rustc_middle::ty::PolyTraitRef<'tcx>,
225) -> ImplExpr {
226    let warn = |msg: &str| {
227        if !s.base().ty_alias_mode {
228            crate::warning!(s, "{}", msg)
229        }
230    };
231    if let Some(impl_expr) = s.with_cache(|cache| cache.impl_exprs.get(&trait_ref).cloned()) {
232        return impl_expr;
233    }
234    let resolved =
235        s.with_predicate_searcher(|pred_searcher| pred_searcher.resolve(&trait_ref, &warn));
236    let impl_expr = match resolved {
237        Ok(x) => x.sinto(s),
238        Err(e) => crate::fatal!(s, "{}", e),
239    };
240    s.with_cache(|cache| cache.impl_exprs.insert(trait_ref, impl_expr.clone()));
241    impl_expr
242}
243
244/// Translate a reference to an item, resolving the appropriate trait clauses as needed.
245#[cfg(feature = "rustc")]
246#[tracing::instrument(level = "trace", skip(s), ret)]
247pub fn translate_item_ref<'tcx, S: UnderOwnerState<'tcx>>(
248    s: &S,
249    def_id: RDefId,
250    generics: ty::GenericArgsRef<'tcx>,
251) -> ItemRef {
252    ItemRef::translate(s, def_id, generics)
253}
254
255/// Solve the trait obligations for a specific item use (for example, a method call, an ADT, etc.)
256/// in the current context. Just like generic args include generics of parent items, this includes
257/// impl exprs for parent items.
258#[cfg(feature = "rustc")]
259#[tracing::instrument(level = "trace", skip(s), ret)]
260pub fn solve_item_required_traits<'tcx, S: UnderOwnerState<'tcx>>(
261    s: &S,
262    def_id: RDefId,
263    generics: ty::GenericArgsRef<'tcx>,
264) -> Vec<ImplExpr> {
265    fn accumulate<'tcx, S: UnderOwnerState<'tcx>>(
266        s: &S,
267        def_id: RDefId,
268        generics: ty::GenericArgsRef<'tcx>,
269        impl_exprs: &mut Vec<ImplExpr>,
270    ) {
271        let tcx = s.base().tcx;
272        use rustc_hir::def::DefKind::*;
273        match tcx.def_kind(def_id) {
274            AssocTy | AssocFn | AssocConst | Closure | Ctor(..) | Variant => {
275                let parent = tcx.parent(def_id);
276                accumulate(s, parent, generics, impl_exprs);
277            }
278            _ => {}
279        }
280        let predicates = required_predicates(tcx, def_id, s.base().options.bounds_options);
281        impl_exprs.extend(solve_item_traits_inner(s, generics, predicates));
282    }
283    let mut impl_exprs = vec![];
284    accumulate(s, def_id, generics, &mut impl_exprs);
285    impl_exprs
286}
287
288/// Solve the trait obligations for implementing a trait (or for trait associated type bounds) in
289/// the current context.
290#[cfg(feature = "rustc")]
291#[tracing::instrument(level = "trace", skip(s), ret)]
292pub fn solve_item_implied_traits<'tcx, S: UnderOwnerState<'tcx>>(
293    s: &S,
294    def_id: RDefId,
295    generics: ty::GenericArgsRef<'tcx>,
296) -> Vec<ImplExpr> {
297    let predicates = implied_predicates(s.base().tcx, def_id, s.base().options.bounds_options);
298    solve_item_traits_inner(s, generics, predicates)
299}
300
301/// Apply the given generics to the provided clauses and resolve the trait references in the
302/// current context.
303#[cfg(feature = "rustc")]
304fn solve_item_traits_inner<'tcx, S: UnderOwnerState<'tcx>>(
305    s: &S,
306    generics: ty::GenericArgsRef<'tcx>,
307    predicates: utils::Predicates<'tcx>,
308) -> Vec<ImplExpr> {
309    let tcx = s.base().tcx;
310    let typing_env = s.typing_env();
311    predicates
312        .iter()
313        .map(|(clause, _span)| *clause)
314        .filter_map(|clause| clause.as_trait_clause())
315        .map(|clause| clause.to_poly_trait_ref())
316        // Substitute the item generics
317        .map(|trait_ref| ty::EarlyBinder::bind(trait_ref).instantiate(tcx, generics))
318        // We unfortunately don't have a way to normalize without erasing regions.
319        .map(|trait_ref| {
320            tcx.try_normalize_erasing_regions(typing_env, trait_ref)
321                .unwrap_or(trait_ref)
322        })
323        // Resolve
324        .map(|trait_ref| solve_trait(s, trait_ref))
325        .collect()
326}
327
328/// Retrieve the `Self: Trait` clause for a trait associated item.
329#[cfg(feature = "rustc")]
330pub fn self_clause_for_item<'tcx, S: UnderOwnerState<'tcx>>(
331    s: &S,
332    def_id: RDefId,
333    generics: rustc_middle::ty::GenericArgsRef<'tcx>,
334) -> Option<ImplExpr> {
335    let tcx = s.base().tcx;
336
337    let tr_def_id = tcx.trait_of_item(def_id)?;
338    // The "self" predicate in the context of the trait.
339    let self_pred = self_predicate(tcx, tr_def_id);
340    // Substitute to be in the context of the current item.
341    let generics = generics.truncate_to(tcx, tcx.generics_of(tr_def_id));
342    let self_pred = ty::EarlyBinder::bind(self_pred).instantiate(tcx, generics);
343
344    // Resolve
345    Some(solve_trait(s, self_pred))
346}