1use std::marker::PhantomData;
2
3use smallvec::smallvec;
4
5use crate::data_structures::HashSet;
6use crate::inherent::*;
7use crate::lang_items::SolverTraitLangItem;
8use crate::outlives::{Component, push_outlives_components};
9use crate::{self as ty, Interner, Unnormalized, Upcast as _};
10
11pub struct Elaborator<I: Interner, O> {
18 cx: I,
19 stack: Vec<O>,
20 visited: HashSet<ty::Binder<I, ty::PredicateKind<I>>>,
21 mode: Filter,
22 elaborate_sized: ElaborateSized,
23}
24
25enum Filter {
26 All,
27 OnlySelf,
28}
29
30#[derive(#[automatically_derived]
impl ::core::cmp::Eq for ElaborateSized {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::cmp::PartialEq for ElaborateSized {
#[inline]
fn eq(&self, other: &ElaborateSized) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq)]
31enum ElaborateSized {
32 Yes,
33 No,
34}
35
36pub trait Elaboratable<I: Interner> {
38 fn predicate(&self) -> I::Predicate;
39
40 fn child(&self, clause: I::Clause) -> Self;
42
43 fn child_with_derived_cause(
46 &self,
47 clause: I::Clause,
48 span: I::Span,
49 parent_trait_pred: ty::Binder<I, ty::TraitPredicate<I>>,
50 index: usize,
51 ) -> Self;
52}
53
54pub struct ClauseWithSupertraitSpan<I: Interner> {
55 pub clause: I::Clause,
56 pub supertrait_span: I::Span,
58}
59impl<I: Interner> ClauseWithSupertraitSpan<I> {
60 pub fn new(clause: I::Clause, span: I::Span) -> Self {
61 ClauseWithSupertraitSpan { clause, supertrait_span: span }
62 }
63}
64impl<I: Interner> Elaboratable<I> for ClauseWithSupertraitSpan<I> {
65 fn predicate(&self) -> <I as Interner>::Predicate {
66 self.clause.as_predicate()
67 }
68
69 fn child(&self, clause: <I as Interner>::Clause) -> Self {
70 ClauseWithSupertraitSpan { clause, supertrait_span: self.supertrait_span }
71 }
72
73 fn child_with_derived_cause(
74 &self,
75 clause: <I as Interner>::Clause,
76 supertrait_span: <I as Interner>::Span,
77 _parent_trait_pred: crate::Binder<I, crate::TraitPredicate<I>>,
78 _index: usize,
79 ) -> Self {
80 ClauseWithSupertraitSpan { clause, supertrait_span }
81 }
82}
83
84pub fn elaborate<I: Interner, O: Elaboratable<I>>(
85 cx: I,
86 obligations: impl IntoIterator<Item = O>,
87) -> Elaborator<I, O> {
88 let mut elaborator = Elaborator {
89 cx,
90 stack: Vec::new(),
91 visited: HashSet::default(),
92 mode: Filter::All,
93 elaborate_sized: ElaborateSized::No,
94 };
95 elaborator.extend_deduped(obligations);
96 elaborator
97}
98
99impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> {
100 fn extend_deduped(&mut self, obligations: impl IntoIterator<Item = O>) {
102 self.stack.extend(
107 obligations.into_iter().filter(|o| {
108 self.visited.insert(self.cx.anonymize_bound_vars(o.predicate().kind()))
109 }),
110 );
111 }
112
113 pub fn filter_only_self(mut self) -> Self {
116 self.mode = Filter::OnlySelf;
117 self
118 }
119
120 pub fn elaborate_sized(mut self) -> Self {
123 self.elaborate_sized = ElaborateSized::Yes;
124 self
125 }
126
127 fn elaborate(&mut self, elaboratable: &O) {
128 let cx = self.cx;
129
130 let Some(clause) = elaboratable.predicate().as_clause() else {
132 return;
133 };
134
135 if self.elaborate_sized == ElaborateSized::No
142 && let Some(did) = clause.as_trait_clause().map(|c| c.def_id())
143 && self.cx.is_trait_lang_item(did, SolverTraitLangItem::Sized)
144 {
145 return;
146 }
147
148 let bound_clause = clause.kind();
149 match bound_clause.skip_binder() {
150 ty::ClauseKind::Trait(data) => {
151 if data.polarity != ty::PredicatePolarity::Positive {
153 return;
154 }
155
156 let map_to_child_clause =
157 |(index, (clause, span)): (usize, (I::Clause, I::Span))| {
158 elaboratable.child_with_derived_cause(
159 clause.instantiate_supertrait(cx, bound_clause.rebind(data.trait_ref)),
160 span,
161 bound_clause.rebind(data),
162 index,
163 )
164 };
165
166 match self.mode {
168 Filter::All => self.extend_deduped(
169 cx.explicit_implied_predicates_of(data.def_id().into())
170 .iter_identity()
171 .map(Unnormalized::skip_norm_wip)
172 .enumerate()
173 .map(map_to_child_clause),
174 ),
175 Filter::OnlySelf => self.extend_deduped(
176 cx.explicit_super_predicates_of(data.def_id())
177 .iter_identity()
178 .map(Unnormalized::skip_norm_wip)
179 .enumerate()
180 .map(map_to_child_clause),
181 ),
182 };
183 }
184 ty::ClauseKind::HostEffect(data) => self.extend_deduped(
186 cx.explicit_implied_const_bounds(data.def_id().into()).iter_identity().map(
187 |trait_ref| {
188 elaboratable.child(
189 trait_ref
190 .to_host_effect_clause(cx, data.constness)
191 .skip_norm_wip()
192 .instantiate_supertrait(cx, bound_clause.rebind(data.trait_ref)),
193 )
194 },
195 ),
196 ),
197 ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => {
198 if r_min.is_bound() {
213 return;
214 }
215
216 let mut components = ::smallvec::SmallVec::new()smallvec![];
217 push_outlives_components(cx, ty_max, &mut components);
218 self.extend_deduped(
219 components
220 .into_iter()
221 .filter_map(|component| elaborate_component_to_clause(cx, component, r_min))
222 .map(|clause| elaboratable.child(bound_clause.rebind(clause).upcast(cx))),
223 );
224 }
225 ty::ClauseKind::RegionOutlives(..) => {
226 }
228 ty::ClauseKind::WellFormed(..) => {
229 }
232 ty::ClauseKind::Projection(..) => {
233 }
235 ty::ClauseKind::ConstEvaluatable(..) => {
236 }
239 ty::ClauseKind::ConstArgHasType(..) => {
240 }
242 ty::ClauseKind::UnstableFeature(_) => {
243 }
245 }
246 }
247}
248
249fn elaborate_component_to_clause<I: Interner>(
250 cx: I,
251 component: Component<I>,
252 outlives_region: I::Region,
253) -> Option<ty::ClauseKind<I>> {
254 match component {
255 Component::Region(r) => {
256 if r.is_bound() {
257 None
258 } else {
259 Some(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r, outlives_region)))
260 }
261 }
262
263 Component::Param(p) => {
264 let ty = Ty::new_param(cx, p);
265 Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, outlives_region)))
266 }
267
268 Component::Placeholder(p) => {
269 let ty = Ty::new_placeholder(cx, p);
270 Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, outlives_region)))
271 }
272
273 Component::UnresolvedInferenceVariable(_) => None,
274
275 Component::Alias(alias_ty) => {
276 Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
279 alias_ty.to_ty(cx),
280 outlives_region,
281 )))
282 }
283
284 Component::EscapingAlias(_) => {
285 None
288 }
289 }
290}
291
292impl<I: Interner, O: Elaboratable<I>> Iterator for Elaborator<I, O> {
293 type Item = O;
294
295 fn size_hint(&self) -> (usize, Option<usize>) {
296 (self.stack.len(), None)
297 }
298
299 fn next(&mut self) -> Option<Self::Item> {
300 if let Some(obligation) = self.stack.pop() {
302 self.elaborate(&obligation);
303 Some(obligation)
304 } else {
305 None
306 }
307 }
308}
309
310pub fn supertrait_def_ids<I: Interner>(
319 cx: I,
320 trait_def_id: I::TraitId,
321) -> impl Iterator<Item = I::TraitId> {
322 let mut set = HashSet::default();
323 let mut stack = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[trait_def_id]))vec![trait_def_id];
324
325 set.insert(trait_def_id);
326
327 std::iter::from_fn(move || {
328 let trait_def_id = stack.pop()?;
329
330 for (predicate, _) in cx
331 .explicit_super_predicates_of(trait_def_id)
332 .iter_identity()
333 .map(Unnormalized::skip_norm_wip)
334 {
335 if let ty::ClauseKind::Trait(data) = predicate.kind().skip_binder()
336 && set.insert(data.def_id())
337 {
338 stack.push(data.def_id());
339 }
340 }
341
342 Some(trait_def_id)
343 })
344}
345
346pub fn supertraits<I: Interner>(
347 cx: I,
348 trait_ref: ty::Binder<I, ty::TraitRef<I>>,
349) -> FilterToTraits<I, Elaborator<I, I::Clause>> {
350 elaborate(cx, [trait_ref.upcast(cx)]).filter_only_self().filter_to_traits()
351}
352
353impl<I: Interner> Elaborator<I, I::Clause> {
354 fn filter_to_traits(self) -> FilterToTraits<I, Self> {
355 FilterToTraits { _cx: PhantomData, base_iterator: self }
356 }
357}
358
359pub struct FilterToTraits<I: Interner, It: Iterator<Item = I::Clause>> {
362 _cx: PhantomData<I>,
363 base_iterator: It,
364}
365
366impl<I: Interner, It: Iterator<Item = I::Clause>> Iterator for FilterToTraits<I, It> {
367 type Item = ty::Binder<I, ty::TraitRef<I>>;
368
369 fn next(&mut self) -> Option<ty::Binder<I, ty::TraitRef<I>>> {
370 while let Some(pred) = self.base_iterator.next() {
371 if let Some(data) = pred.as_trait_clause() {
372 return Some(data.map_bound(|t| t.trait_ref));
373 }
374 }
375 None
376 }
377
378 fn size_hint(&self) -> (usize, Option<usize>) {
379 let (_, upper) = self.base_iterator.size_hint();
380 (0, upper)
381 }
382}
383
384pub fn elaborate_outlives_assumptions<I: Interner>(
385 cx: I,
386 assumptions: impl IntoIterator<Item = ty::OutlivesPredicate<I, I::GenericArg>>,
387) -> HashSet<ty::OutlivesPredicate<I, I::GenericArg>> {
388 let mut collected = HashSet::default();
389
390 for ty::OutlivesPredicate(arg1, r2) in assumptions {
391 collected.insert(ty::OutlivesPredicate(arg1, r2));
392 match arg1.kind() {
393 ty::GenericArgKind::Type(ty1) => {
396 let mut components = ::smallvec::SmallVec::new()smallvec![];
397 push_outlives_components(cx, ty1, &mut components);
398 for c in components {
399 match c {
400 Component::Region(r1) => {
401 if !r1.is_bound() {
402 collected.insert(ty::OutlivesPredicate(r1.into(), r2));
403 }
404 }
405
406 Component::Param(p) => {
407 let ty = Ty::new_param(cx, p);
408 collected.insert(ty::OutlivesPredicate(ty.into(), r2));
409 }
410
411 Component::Placeholder(p) => {
412 let ty = Ty::new_placeholder(cx, p);
413 collected.insert(ty::OutlivesPredicate(ty.into(), r2));
414 }
415
416 Component::Alias(alias_ty) => {
417 collected.insert(ty::OutlivesPredicate(alias_ty.to_ty(cx).into(), r2));
418 }
419
420 Component::UnresolvedInferenceVariable(_) | Component::EscapingAlias(_) => {
421 }
422 }
423 }
424 }
425 ty::GenericArgKind::Lifetime(_) => {}
427 ty::GenericArgKind::Const(_) => {}
429 }
430 }
431
432 collected
433}