chalk_ir/
cast.rs

1//! Upcasts, to avoid writing out wrapper types.
2
3use crate::*;
4use std::marker::PhantomData;
5
6/// The `Cast` trait is used to make annoying upcasts between
7/// logically equivalent types that imply wrappers. For example, one
8/// could convert a `DomainGoal` into a `Goal` by doing:
9///
10/// ```ignore
11/// let goal: Goal = domain_goal.cast();
12/// ```
13///
14/// This is equivalent to the more explicit:
15///
16/// ```ignore
17/// let goal: Goal = Goal::DomainGoal(domain_goal)
18/// ```
19///
20/// Another useful trick is the `casted()` iterator adapter, which
21/// casts each element in the iterator as it is produced (you must
22/// have the `Caster` trait in scope for that).
23///
24/// # Invariant
25///
26/// `Cast` imposes a key invariant. You can only implement `T:
27/// Cast<U>` if both `T` and `U` have the same semantic meaning. Also,
28/// as part of this, they should always use the same set of free
29/// variables (the `Canonical` implementation, for example, relies on
30/// that).
31///
32/// # Iterators
33///
34/// If you import the `Caster` trait, you can also write `.casted()` on an
35/// iterator chain to cast every instance within.
36///
37/// # Implementing Cast
38///
39/// Do not implement `Cast` directly. Instead, implement `CastTo`.
40/// This split setup allows us to write `foo.cast::<T>()` to mean
41/// "cast to T".
42pub trait Cast: Sized {
43    /// Cast a value to type `U` using `CastTo`.
44    fn cast<U>(self, interner: U::Interner) -> U
45    where
46        Self: CastTo<U>,
47        U: HasInterner,
48    {
49        self.cast_to(interner)
50    }
51}
52
53impl<T> Cast for T {}
54
55/// The "helper" trait for `cast` that actually implements the
56/// transformations. You can also use this if you want to have
57/// functions that take (e.g.) an `impl CastTo<Goal<_>>` or something
58/// like that.
59pub trait CastTo<T: HasInterner>: Sized {
60    /// Cast a value to type `T`.
61    fn cast_to(self, interner: T::Interner) -> T;
62}
63
64macro_rules! reflexive_impl {
65    (for($($t:tt)*) $u:ty) => {
66        impl<$($t)*> CastTo<$u> for $u {
67            fn cast_to(self, _interner: <$u as HasInterner>::Interner) -> $u {
68                self
69            }
70        }
71    };
72    ($u:ty) => {
73        impl CastTo<$u> for $u {
74            fn cast_to(self, interner: <$u as HasInterner>::Interner) -> $u {
75                self
76            }
77        }
78    };
79}
80
81reflexive_impl!(for(I: Interner) TyKind<I>);
82reflexive_impl!(for(I: Interner) LifetimeData<I>);
83reflexive_impl!(for(I: Interner) ConstData<I>);
84reflexive_impl!(for(I: Interner) TraitRef<I>);
85reflexive_impl!(for(I: Interner) DomainGoal<I>);
86reflexive_impl!(for(I: Interner) Goal<I>);
87reflexive_impl!(for(I: Interner) WhereClause<I>);
88reflexive_impl!(for(I: Interner) ProgramClause<I>);
89reflexive_impl!(for(I: Interner) QuantifiedWhereClause<I>);
90reflexive_impl!(for(I: Interner) VariableKind<I>);
91reflexive_impl!(for(I: Interner) VariableKinds<I>);
92reflexive_impl!(for(I: Interner) CanonicalVarKind<I>);
93reflexive_impl!(for(I: Interner) CanonicalVarKinds<I>);
94reflexive_impl!(for(I: Interner) Constraint<I>);
95
96impl<I: Interner> CastTo<WhereClause<I>> for TraitRef<I> {
97    fn cast_to(self, _interner: I) -> WhereClause<I> {
98        WhereClause::Implemented(self)
99    }
100}
101
102impl<I: Interner> CastTo<WhereClause<I>> for AliasEq<I> {
103    fn cast_to(self, _interner: I) -> WhereClause<I> {
104        WhereClause::AliasEq(self)
105    }
106}
107
108impl<I: Interner> CastTo<WhereClause<I>> for LifetimeOutlives<I> {
109    fn cast_to(self, _interner: I) -> WhereClause<I> {
110        WhereClause::LifetimeOutlives(self)
111    }
112}
113
114impl<I: Interner> CastTo<WhereClause<I>> for TypeOutlives<I> {
115    fn cast_to(self, _interner: I) -> WhereClause<I> {
116        WhereClause::TypeOutlives(self)
117    }
118}
119
120impl<T, I> CastTo<DomainGoal<I>> for T
121where
122    T: CastTo<WhereClause<I>>,
123    I: Interner,
124{
125    fn cast_to(self, interner: I) -> DomainGoal<I> {
126        DomainGoal::Holds(self.cast(interner))
127    }
128}
129
130impl<T, I: Interner> CastTo<Goal<I>> for T
131where
132    T: CastTo<DomainGoal<I>>,
133{
134    fn cast_to(self, interner: I) -> Goal<I> {
135        GoalData::DomainGoal(self.cast(interner)).intern(interner)
136    }
137}
138
139impl<I: Interner> CastTo<DomainGoal<I>> for Normalize<I> {
140    fn cast_to(self, _interner: I) -> DomainGoal<I> {
141        DomainGoal::Normalize(self)
142    }
143}
144
145impl<I: Interner> CastTo<DomainGoal<I>> for WellFormed<I> {
146    fn cast_to(self, _interner: I) -> DomainGoal<I> {
147        DomainGoal::WellFormed(self)
148    }
149}
150
151impl<I: Interner> CastTo<DomainGoal<I>> for FromEnv<I> {
152    fn cast_to(self, _interner: I) -> DomainGoal<I> {
153        DomainGoal::FromEnv(self)
154    }
155}
156
157impl<I: Interner> CastTo<Goal<I>> for EqGoal<I> {
158    fn cast_to(self, interner: I) -> Goal<I> {
159        GoalData::EqGoal(self).intern(interner)
160    }
161}
162
163impl<I: Interner> CastTo<Goal<I>> for SubtypeGoal<I> {
164    fn cast_to(self, interner: I) -> Goal<I> {
165        GoalData::SubtypeGoal(self).intern(interner)
166    }
167}
168
169impl<I: Interner, T: HasInterner<Interner = I> + CastTo<Goal<I>>> CastTo<Goal<I>> for Binders<T> {
170    fn cast_to(self, interner: I) -> Goal<I> {
171        GoalData::Quantified(
172            QuantifierKind::ForAll,
173            self.map(|bound| bound.cast(interner)),
174        )
175        .intern(interner)
176    }
177}
178
179impl<I: Interner> CastTo<TyKind<I>> for AliasTy<I> {
180    fn cast_to(self, _interner: I) -> TyKind<I> {
181        TyKind::Alias(self)
182    }
183}
184
185impl<I: Interner> CastTo<GenericArg<I>> for Ty<I> {
186    fn cast_to(self, interner: I) -> GenericArg<I> {
187        GenericArg::new(interner, GenericArgData::Ty(self))
188    }
189}
190
191impl<I: Interner> CastTo<GenericArg<I>> for Lifetime<I> {
192    fn cast_to(self, interner: I) -> GenericArg<I> {
193        GenericArg::new(interner, GenericArgData::Lifetime(self))
194    }
195}
196
197impl<I: Interner> CastTo<GenericArg<I>> for Const<I> {
198    fn cast_to(self, interner: I) -> GenericArg<I> {
199        GenericArg::new(interner, GenericArgData::Const(self))
200    }
201}
202
203impl<I: Interner> CastTo<GenericArg<I>> for GenericArg<I> {
204    fn cast_to(self, _interner: I) -> GenericArg<I> {
205        self
206    }
207}
208
209impl<T, I> CastTo<ProgramClause<I>> for T
210where
211    T: CastTo<DomainGoal<I>>,
212    I: Interner,
213{
214    fn cast_to(self, interner: I) -> ProgramClause<I> {
215        let implication = ProgramClauseImplication {
216            consequence: self.cast(interner),
217            conditions: Goals::empty(interner),
218            constraints: Constraints::empty(interner),
219            priority: ClausePriority::High,
220        };
221
222        ProgramClauseData(Binders::empty(interner, implication.shifted_in(interner)))
223            .intern(interner)
224    }
225}
226
227impl<I, T> CastTo<ProgramClause<I>> for Binders<T>
228where
229    I: Interner,
230    T: HasInterner<Interner = I> + CastTo<DomainGoal<I>>,
231{
232    fn cast_to(self, interner: I) -> ProgramClause<I> {
233        ProgramClauseData(self.map(|bound| ProgramClauseImplication {
234            consequence: bound.cast(interner),
235            conditions: Goals::empty(interner),
236            constraints: Constraints::empty(interner),
237            priority: ClausePriority::High,
238        }))
239        .intern(interner)
240    }
241}
242
243impl<T, U> CastTo<Option<U>> for Option<T>
244where
245    T: CastTo<U>,
246    U: HasInterner,
247{
248    fn cast_to(self, interner: U::Interner) -> Option<U> {
249        self.map(|v| v.cast(interner))
250    }
251}
252
253impl<T, U, I> CastTo<InEnvironment<U>> for InEnvironment<T>
254where
255    T: HasInterner<Interner = I> + CastTo<U>,
256    U: HasInterner<Interner = I>,
257    I: Interner,
258{
259    fn cast_to(self, interner: U::Interner) -> InEnvironment<U> {
260        self.map(|v| v.cast(interner))
261    }
262}
263
264impl<T, U, E> CastTo<Result<U, E>> for Result<T, E>
265where
266    T: CastTo<U>,
267    U: HasInterner,
268{
269    fn cast_to(self, interner: U::Interner) -> Result<U, E> {
270        self.map(|v| v.cast(interner))
271    }
272}
273
274impl<T> HasInterner for Option<T>
275where
276    T: HasInterner,
277{
278    type Interner = T::Interner;
279}
280
281impl<T, E> HasInterner for Result<T, E>
282where
283    T: HasInterner,
284{
285    type Interner = T::Interner;
286}
287
288impl<T, U> CastTo<Canonical<U>> for Canonical<T>
289where
290    T: CastTo<U> + HasInterner,
291    U: HasInterner<Interner = T::Interner>,
292{
293    fn cast_to(self, interner: T::Interner) -> Canonical<U> {
294        // Subtle point: It should be ok to re-use the binders here,
295        // because `cast()` never introduces new inference variables,
296        // nor changes the "substance" of the type we are working
297        // with. It just introduces new wrapper types.
298        Canonical {
299            value: self.value.cast(interner),
300            binders: self.binders.cast(interner),
301        }
302    }
303}
304
305impl<T, U> CastTo<Vec<U>> for Vec<T>
306where
307    T: CastTo<U> + HasInterner,
308    U: HasInterner,
309{
310    fn cast_to(self, interner: U::Interner) -> Vec<U> {
311        self.into_iter().casted(interner).collect()
312    }
313}
314
315impl<T> CastTo<T> for &T
316where
317    T: Clone + HasInterner,
318{
319    fn cast_to(self, _interner: T::Interner) -> T {
320        self.clone()
321    }
322}
323
324/// An iterator that casts each element to some other type.
325pub struct Casted<IT, U: HasInterner> {
326    interner: U::Interner,
327    iterator: IT,
328    _cast: PhantomData<U>,
329}
330
331impl<IT: Iterator, U> Iterator for Casted<IT, U>
332where
333    IT::Item: CastTo<U>,
334    U: HasInterner,
335{
336    type Item = U;
337
338    fn next(&mut self) -> Option<Self::Item> {
339        self.iterator.next().map(|item| item.cast_to(self.interner))
340    }
341
342    fn size_hint(&self) -> (usize, Option<usize>) {
343        self.iterator.size_hint()
344    }
345}
346
347/// An iterator adapter that casts each element we are iterating over
348/// to some other type.
349pub trait Caster: Iterator + Sized {
350    /// Cast each element in this iterator.
351    fn casted<U>(self, interner: U::Interner) -> Casted<Self, U>
352    where
353        Self::Item: CastTo<U>,
354        U: HasInterner,
355    {
356        Casted {
357            interner,
358            iterator: self,
359            _cast: PhantomData,
360        }
361    }
362}
363
364impl<I> Caster for I where I: Iterator {}