1use std::marker::PhantomData;
2
3use smallvec::smallvec;
4
5use crate::data_structures::HashSet;
6use crate::inherent::*;
7use crate::outlives::{Component, push_outlives_components};
8use crate::{self as ty, Interner, Upcast as _};
9
10pub struct Elaborator<I: Interner, O> {
17 cx: I,
18 stack: Vec<O>,
19 visited: HashSet<ty::Binder<I, ty::PredicateKind<I>>>,
20 mode: Filter,
21}
22
23enum Filter {
24 All,
25 OnlySelf,
26}
27
28pub trait Elaboratable<I: Interner> {
30 fn predicate(&self) -> I::Predicate;
31
32 fn child(&self, clause: I::Clause) -> Self;
34
35 fn child_with_derived_cause(
38 &self,
39 clause: I::Clause,
40 span: I::Span,
41 parent_trait_pred: ty::Binder<I, ty::TraitPredicate<I>>,
42 index: usize,
43 ) -> Self;
44}
45
46pub struct ClauseWithSupertraitSpan<I: Interner> {
47 pub pred: I::Predicate,
48 pub supertrait_span: I::Span,
50}
51impl<I: Interner> ClauseWithSupertraitSpan<I> {
52 pub fn new(pred: I::Predicate, span: I::Span) -> Self {
53 ClauseWithSupertraitSpan { pred, supertrait_span: span }
54 }
55}
56impl<I: Interner> Elaboratable<I> for ClauseWithSupertraitSpan<I> {
57 fn predicate(&self) -> <I as Interner>::Predicate {
58 self.pred
59 }
60
61 fn child(&self, clause: <I as Interner>::Clause) -> Self {
62 ClauseWithSupertraitSpan {
63 pred: clause.as_predicate(),
64 supertrait_span: self.supertrait_span,
65 }
66 }
67
68 fn child_with_derived_cause(
69 &self,
70 clause: <I as Interner>::Clause,
71 supertrait_span: <I as Interner>::Span,
72 _parent_trait_pred: crate::Binder<I, crate::TraitPredicate<I>>,
73 _index: usize,
74 ) -> Self {
75 ClauseWithSupertraitSpan { pred: clause.as_predicate(), supertrait_span }
76 }
77}
78
79pub fn elaborate<I: Interner, O: Elaboratable<I>>(
80 cx: I,
81 obligations: impl IntoIterator<Item = O>,
82) -> Elaborator<I, O> {
83 let mut elaborator =
84 Elaborator { cx, stack: Vec::new(), visited: HashSet::default(), mode: Filter::All };
85 elaborator.extend_deduped(obligations);
86 elaborator
87}
88
89impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> {
90 fn extend_deduped(&mut self, obligations: impl IntoIterator<Item = O>) {
91 self.stack.extend(
96 obligations.into_iter().filter(|o| {
97 self.visited.insert(self.cx.anonymize_bound_vars(o.predicate().kind()))
98 }),
99 );
100 }
101
102 pub fn filter_only_self(mut self) -> Self {
105 self.mode = Filter::OnlySelf;
106 self
107 }
108
109 fn elaborate(&mut self, elaboratable: &O) {
110 let cx = self.cx;
111
112 let Some(clause) = elaboratable.predicate().as_clause() else {
114 return;
115 };
116
117 let bound_clause = clause.kind();
118 match bound_clause.skip_binder() {
119 ty::ClauseKind::Trait(data) => {
120 if data.polarity != ty::PredicatePolarity::Positive {
122 return;
123 }
124
125 let map_to_child_clause =
126 |(index, (clause, span)): (usize, (I::Clause, I::Span))| {
127 elaboratable.child_with_derived_cause(
128 clause.instantiate_supertrait(cx, bound_clause.rebind(data.trait_ref)),
129 span,
130 bound_clause.rebind(data),
131 index,
132 )
133 };
134
135 match self.mode {
137 Filter::All => self.extend_deduped(
138 cx.explicit_implied_predicates_of(data.def_id())
139 .iter_identity()
140 .enumerate()
141 .map(map_to_child_clause),
142 ),
143 Filter::OnlySelf => self.extend_deduped(
144 cx.explicit_super_predicates_of(data.def_id())
145 .iter_identity()
146 .enumerate()
147 .map(map_to_child_clause),
148 ),
149 };
150 }
151 ty::ClauseKind::HostEffect(data) => self.extend_deduped(
153 cx.explicit_implied_const_bounds(data.def_id()).iter_identity().map(|trait_ref| {
154 elaboratable.child(
155 trait_ref
156 .to_host_effect_clause(cx, data.constness)
157 .instantiate_supertrait(cx, bound_clause.rebind(data.trait_ref)),
158 )
159 }),
160 ),
161 ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => {
162 if r_min.is_bound() {
177 return;
178 }
179
180 let mut components = smallvec![];
181 push_outlives_components(cx, ty_max, &mut components);
182 self.extend_deduped(
183 components
184 .into_iter()
185 .filter_map(|component| elaborate_component_to_clause(cx, component, r_min))
186 .map(|clause| elaboratable.child(bound_clause.rebind(clause).upcast(cx))),
187 );
188 }
189 ty::ClauseKind::RegionOutlives(..) => {
190 }
192 ty::ClauseKind::WellFormed(..) => {
193 }
196 ty::ClauseKind::Projection(..) => {
197 }
199 ty::ClauseKind::ConstEvaluatable(..) => {
200 }
203 ty::ClauseKind::ConstArgHasType(..) => {
204 }
206 }
207 }
208}
209
210fn elaborate_component_to_clause<I: Interner>(
211 cx: I,
212 component: Component<I>,
213 outlives_region: I::Region,
214) -> Option<ty::ClauseKind<I>> {
215 match component {
216 Component::Region(r) => {
217 if r.is_bound() {
218 None
219 } else {
220 Some(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r, outlives_region)))
221 }
222 }
223
224 Component::Param(p) => {
225 let ty = Ty::new_param(cx, p);
226 Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, outlives_region)))
227 }
228
229 Component::Placeholder(p) => {
230 let ty = Ty::new_placeholder(cx, p);
231 Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, outlives_region)))
232 }
233
234 Component::UnresolvedInferenceVariable(_) => None,
235
236 Component::Alias(alias_ty) => {
237 Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
240 alias_ty.to_ty(cx),
241 outlives_region,
242 )))
243 }
244
245 Component::EscapingAlias(_) => {
246 None
249 }
250 }
251}
252
253impl<I: Interner, O: Elaboratable<I>> Iterator for Elaborator<I, O> {
254 type Item = O;
255
256 fn size_hint(&self) -> (usize, Option<usize>) {
257 (self.stack.len(), None)
258 }
259
260 fn next(&mut self) -> Option<Self::Item> {
261 if let Some(obligation) = self.stack.pop() {
263 self.elaborate(&obligation);
264 Some(obligation)
265 } else {
266 None
267 }
268 }
269}
270
271pub fn supertrait_def_ids<I: Interner>(
280 cx: I,
281 trait_def_id: I::DefId,
282) -> impl Iterator<Item = I::DefId> {
283 let mut set = HashSet::default();
284 let mut stack = vec![trait_def_id];
285
286 set.insert(trait_def_id);
287
288 std::iter::from_fn(move || {
289 let trait_def_id = stack.pop()?;
290
291 for (predicate, _) in cx.explicit_super_predicates_of(trait_def_id).iter_identity() {
292 if let ty::ClauseKind::Trait(data) = predicate.kind().skip_binder() {
293 if set.insert(data.def_id()) {
294 stack.push(data.def_id());
295 }
296 }
297 }
298
299 Some(trait_def_id)
300 })
301}
302
303pub fn supertraits<I: Interner>(
304 cx: I,
305 trait_ref: ty::Binder<I, ty::TraitRef<I>>,
306) -> FilterToTraits<I, Elaborator<I, I::Clause>> {
307 elaborate(cx, [trait_ref.upcast(cx)]).filter_only_self().filter_to_traits()
308}
309
310impl<I: Interner> Elaborator<I, I::Clause> {
311 fn filter_to_traits(self) -> FilterToTraits<I, Self> {
312 FilterToTraits { _cx: PhantomData, base_iterator: self }
313 }
314}
315
316pub struct FilterToTraits<I: Interner, It: Iterator<Item = I::Clause>> {
319 _cx: PhantomData<I>,
320 base_iterator: It,
321}
322
323impl<I: Interner, It: Iterator<Item = I::Clause>> Iterator for FilterToTraits<I, It> {
324 type Item = ty::Binder<I, ty::TraitRef<I>>;
325
326 fn next(&mut self) -> Option<ty::Binder<I, ty::TraitRef<I>>> {
327 while let Some(pred) = self.base_iterator.next() {
328 if let Some(data) = pred.as_trait_clause() {
329 return Some(data.map_bound(|t| t.trait_ref));
330 }
331 }
332 None
333 }
334
335 fn size_hint(&self) -> (usize, Option<usize>) {
336 let (_, upper) = self.base_iterator.size_hint();
337 (0, upper)
338 }
339}