Skip to content

Commit 90423a7

Browse files
Uplift elaboration
1 parent 58aad3c commit 90423a7

File tree

11 files changed

+437
-369
lines changed

11 files changed

+437
-369
lines changed
+4-345
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
use smallvec::smallvec;
2-
31
use crate::traits::{self, Obligation, ObligationCauseCode, PredicateObligation};
42
use rustc_data_structures::fx::FxHashSet;
53
use rustc_middle::ty::ToPolyTraitRef;
6-
use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
4+
use rustc_middle::ty::{self, TyCtxt};
75
use rustc_span::symbol::Ident;
86
use rustc_span::Span;
9-
use rustc_type_ir::outlives::{push_outlives_components, Component};
7+
pub use rustc_type_ir::elaborate::*;
108

119
pub fn anonymize_predicate<'tcx>(
1210
tcx: TyCtxt<'tcx>,
@@ -64,50 +62,9 @@ impl<'tcx> Extend<ty::Predicate<'tcx>> for PredicateSet<'tcx> {
6462
}
6563
}
6664

67-
///////////////////////////////////////////////////////////////////////////
68-
// `Elaboration` iterator
69-
///////////////////////////////////////////////////////////////////////////
70-
71-
/// "Elaboration" is the process of identifying all the predicates that
72-
/// are implied by a source predicate. Currently, this basically means
73-
/// walking the "supertraits" and other similar assumptions. For example,
74-
/// if we know that `T: Ord`, the elaborator would deduce that `T: PartialOrd`
75-
/// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that
76-
/// `T: Foo`, then we know that `T: 'static`.
77-
pub struct Elaborator<'tcx, O> {
78-
stack: Vec<O>,
79-
visited: PredicateSet<'tcx>,
80-
mode: Filter,
81-
}
82-
83-
enum Filter {
84-
All,
85-
OnlySelf,
86-
}
87-
88-
/// Describes how to elaborate an obligation into a sub-obligation.
89-
///
9065
/// For [`Obligation`], a sub-obligation is combined with the current obligation's
91-
/// param-env and cause code. For [`ty::Predicate`], none of this is needed, since
92-
/// there is no param-env or cause code to copy over.
93-
pub trait Elaboratable<'tcx> {
94-
fn predicate(&self) -> ty::Predicate<'tcx>;
95-
96-
// Makes a new `Self` but with a different clause that comes from elaboration.
97-
fn child(&self, clause: ty::Clause<'tcx>) -> Self;
98-
99-
// Makes a new `Self` but with a different clause and a different cause
100-
// code (if `Self` has one, such as [`PredicateObligation`]).
101-
fn child_with_derived_cause(
102-
&self,
103-
clause: ty::Clause<'tcx>,
104-
span: Span,
105-
parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
106-
index: usize,
107-
) -> Self;
108-
}
109-
110-
impl<'tcx> Elaboratable<'tcx> for PredicateObligation<'tcx> {
66+
/// param-env and cause code.
67+
impl<'tcx> Elaboratable<TyCtxt<'tcx>> for PredicateObligation<'tcx> {
11168
fn predicate(&self) -> ty::Predicate<'tcx> {
11269
self.predicate
11370
}
@@ -145,270 +102,6 @@ impl<'tcx> Elaboratable<'tcx> for PredicateObligation<'tcx> {
145102
}
146103
}
147104

148-
impl<'tcx> Elaboratable<'tcx> for ty::Predicate<'tcx> {
149-
fn predicate(&self) -> ty::Predicate<'tcx> {
150-
*self
151-
}
152-
153-
fn child(&self, clause: ty::Clause<'tcx>) -> Self {
154-
clause.as_predicate()
155-
}
156-
157-
fn child_with_derived_cause(
158-
&self,
159-
clause: ty::Clause<'tcx>,
160-
_span: Span,
161-
_parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
162-
_index: usize,
163-
) -> Self {
164-
clause.as_predicate()
165-
}
166-
}
167-
168-
impl<'tcx> Elaboratable<'tcx> for (ty::Predicate<'tcx>, Span) {
169-
fn predicate(&self) -> ty::Predicate<'tcx> {
170-
self.0
171-
}
172-
173-
fn child(&self, clause: ty::Clause<'tcx>) -> Self {
174-
(clause.as_predicate(), self.1)
175-
}
176-
177-
fn child_with_derived_cause(
178-
&self,
179-
clause: ty::Clause<'tcx>,
180-
_span: Span,
181-
_parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
182-
_index: usize,
183-
) -> Self {
184-
(clause.as_predicate(), self.1)
185-
}
186-
}
187-
188-
impl<'tcx> Elaboratable<'tcx> for (ty::Clause<'tcx>, Span) {
189-
fn predicate(&self) -> ty::Predicate<'tcx> {
190-
self.0.as_predicate()
191-
}
192-
193-
fn child(&self, clause: ty::Clause<'tcx>) -> Self {
194-
(clause, self.1)
195-
}
196-
197-
fn child_with_derived_cause(
198-
&self,
199-
clause: ty::Clause<'tcx>,
200-
_span: Span,
201-
_parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
202-
_index: usize,
203-
) -> Self {
204-
(clause, self.1)
205-
}
206-
}
207-
208-
impl<'tcx> Elaboratable<'tcx> for ty::Clause<'tcx> {
209-
fn predicate(&self) -> ty::Predicate<'tcx> {
210-
self.as_predicate()
211-
}
212-
213-
fn child(&self, clause: ty::Clause<'tcx>) -> Self {
214-
clause
215-
}
216-
217-
fn child_with_derived_cause(
218-
&self,
219-
clause: ty::Clause<'tcx>,
220-
_span: Span,
221-
_parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
222-
_index: usize,
223-
) -> Self {
224-
clause
225-
}
226-
}
227-
228-
pub fn elaborate<'tcx, O: Elaboratable<'tcx>>(
229-
tcx: TyCtxt<'tcx>,
230-
obligations: impl IntoIterator<Item = O>,
231-
) -> Elaborator<'tcx, O> {
232-
let mut elaborator =
233-
Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx), mode: Filter::All };
234-
elaborator.extend_deduped(obligations);
235-
elaborator
236-
}
237-
238-
impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
239-
fn extend_deduped(&mut self, obligations: impl IntoIterator<Item = O>) {
240-
// Only keep those bounds that we haven't already seen.
241-
// This is necessary to prevent infinite recursion in some
242-
// cases. One common case is when people define
243-
// `trait Sized: Sized { }` rather than `trait Sized { }`.
244-
// let visited = &mut self.visited;
245-
self.stack.extend(obligations.into_iter().filter(|o| self.visited.insert(o.predicate())));
246-
}
247-
248-
/// Filter to only the supertraits of trait predicates, i.e. only the predicates
249-
/// that have `Self` as their self type, instead of all implied predicates.
250-
pub fn filter_only_self(mut self) -> Self {
251-
self.mode = Filter::OnlySelf;
252-
self
253-
}
254-
255-
fn elaborate(&mut self, elaboratable: &O) {
256-
let tcx = self.visited.tcx;
257-
258-
// We only elaborate clauses.
259-
let Some(clause) = elaboratable.predicate().as_clause() else {
260-
return;
261-
};
262-
263-
let bound_clause = clause.kind();
264-
match bound_clause.skip_binder() {
265-
ty::ClauseKind::Trait(data) => {
266-
// Negative trait bounds do not imply any supertrait bounds
267-
if data.polarity != ty::PredicatePolarity::Positive {
268-
return;
269-
}
270-
// Get predicates implied by the trait, or only super predicates if we only care about self predicates.
271-
let predicates = match self.mode {
272-
Filter::All => tcx.explicit_implied_predicates_of(data.def_id()),
273-
Filter::OnlySelf => tcx.explicit_super_predicates_of(data.def_id()),
274-
};
275-
276-
let obligations =
277-
predicates.predicates.iter().enumerate().map(|(index, &(clause, span))| {
278-
elaboratable.child_with_derived_cause(
279-
clause.instantiate_supertrait(tcx, bound_clause.rebind(data.trait_ref)),
280-
span,
281-
bound_clause.rebind(data),
282-
index,
283-
)
284-
});
285-
debug!(?data, ?obligations, "super_predicates");
286-
self.extend_deduped(obligations);
287-
}
288-
ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => {
289-
// We know that `T: 'a` for some type `T`. We can
290-
// often elaborate this. For example, if we know that
291-
// `[U]: 'a`, that implies that `U: 'a`. Similarly, if
292-
// we know `&'a U: 'b`, then we know that `'a: 'b` and
293-
// `U: 'b`.
294-
//
295-
// We can basically ignore bound regions here. So for
296-
// example `for<'c> Foo<'a,'c>: 'b` can be elaborated to
297-
// `'a: 'b`.
298-
299-
// Ignore `for<'a> T: 'a` -- we might in the future
300-
// consider this as evidence that `T: 'static`, but
301-
// I'm a bit wary of such constructions and so for now
302-
// I want to be conservative. --nmatsakis
303-
if r_min.is_bound() {
304-
return;
305-
}
306-
307-
let mut components = smallvec![];
308-
push_outlives_components(tcx, ty_max, &mut components);
309-
self.extend_deduped(
310-
components
311-
.into_iter()
312-
.filter_map(|component| match component {
313-
Component::Region(r) => {
314-
if r.is_bound() {
315-
None
316-
} else {
317-
Some(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
318-
r, r_min,
319-
)))
320-
}
321-
}
322-
323-
Component::Param(p) => {
324-
let ty = Ty::new_param(tcx, p.index, p.name);
325-
Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, r_min)))
326-
}
327-
328-
Component::Placeholder(p) => {
329-
let ty = Ty::new_placeholder(tcx, p);
330-
Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, r_min)))
331-
}
332-
333-
Component::UnresolvedInferenceVariable(_) => None,
334-
335-
Component::Alias(alias_ty) => {
336-
// We might end up here if we have `Foo<<Bar as Baz>::Assoc>: 'a`.
337-
// With this, we can deduce that `<Bar as Baz>::Assoc: 'a`.
338-
Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
339-
alias_ty.to_ty(tcx),
340-
r_min,
341-
)))
342-
}
343-
344-
Component::EscapingAlias(_) => {
345-
// We might be able to do more here, but we don't
346-
// want to deal with escaping vars right now.
347-
None
348-
}
349-
})
350-
.map(|clause| elaboratable.child(bound_clause.rebind(clause).upcast(tcx))),
351-
);
352-
}
353-
ty::ClauseKind::RegionOutlives(..) => {
354-
// Nothing to elaborate from `'a: 'b`.
355-
}
356-
ty::ClauseKind::WellFormed(..) => {
357-
// Currently, we do not elaborate WF predicates,
358-
// although we easily could.
359-
}
360-
ty::ClauseKind::Projection(..) => {
361-
// Nothing to elaborate in a projection predicate.
362-
}
363-
ty::ClauseKind::ConstEvaluatable(..) => {
364-
// Currently, we do not elaborate const-evaluatable
365-
// predicates.
366-
}
367-
ty::ClauseKind::ConstArgHasType(..) => {
368-
// Nothing to elaborate
369-
}
370-
}
371-
}
372-
}
373-
374-
impl<'tcx, O: Elaboratable<'tcx>> Iterator for Elaborator<'tcx, O> {
375-
type Item = O;
376-
377-
fn size_hint(&self) -> (usize, Option<usize>) {
378-
(self.stack.len(), None)
379-
}
380-
381-
fn next(&mut self) -> Option<Self::Item> {
382-
// Extract next item from top-most stack frame, if any.
383-
if let Some(obligation) = self.stack.pop() {
384-
self.elaborate(&obligation);
385-
Some(obligation)
386-
} else {
387-
None
388-
}
389-
}
390-
}
391-
392-
///////////////////////////////////////////////////////////////////////////
393-
// Supertrait iterator
394-
///////////////////////////////////////////////////////////////////////////
395-
396-
pub fn supertraits<'tcx>(
397-
tcx: TyCtxt<'tcx>,
398-
trait_ref: ty::PolyTraitRef<'tcx>,
399-
) -> FilterToTraits<Elaborator<'tcx, ty::Clause<'tcx>>> {
400-
elaborate(tcx, [trait_ref.upcast(tcx)]).filter_only_self().filter_to_traits()
401-
}
402-
403-
pub fn transitive_bounds<'tcx>(
404-
tcx: TyCtxt<'tcx>,
405-
trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
406-
) -> FilterToTraits<Elaborator<'tcx, ty::Clause<'tcx>>> {
407-
elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx)))
408-
.filter_only_self()
409-
.filter_to_traits()
410-
}
411-
412105
/// A specialized variant of `elaborate` that only elaborates trait references that may
413106
/// define the given associated item with the name `assoc_name`. It uses the
414107
/// `explicit_supertraits_containing_assoc_item` query to avoid enumerating super-predicates that
@@ -443,37 +136,3 @@ pub fn transitive_bounds_that_define_assoc_item<'tcx>(
443136
None
444137
})
445138
}
446-
447-
///////////////////////////////////////////////////////////////////////////
448-
// Other
449-
///////////////////////////////////////////////////////////////////////////
450-
451-
impl<'tcx> Elaborator<'tcx, ty::Clause<'tcx>> {
452-
fn filter_to_traits(self) -> FilterToTraits<Self> {
453-
FilterToTraits { base_iterator: self }
454-
}
455-
}
456-
457-
/// A filter around an iterator of predicates that makes it yield up
458-
/// just trait references.
459-
pub struct FilterToTraits<I> {
460-
base_iterator: I,
461-
}
462-
463-
impl<'tcx, I: Iterator<Item = ty::Clause<'tcx>>> Iterator for FilterToTraits<I> {
464-
type Item = ty::PolyTraitRef<'tcx>;
465-
466-
fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
467-
while let Some(pred) = self.base_iterator.next() {
468-
if let Some(data) = pred.as_trait_clause() {
469-
return Some(data.map_bound(|t| t.trait_ref));
470-
}
471-
}
472-
None
473-
}
474-
475-
fn size_hint(&self) -> (usize, Option<usize>) {
476-
let (_, upper) = self.base_iterator.size_hint();
477-
(0, upper)
478-
}
479-
}

0 commit comments

Comments
 (0)