-
Notifications
You must be signed in to change notification settings - Fork 13k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use PredicateObligation
s instead of Predicate
s
#69745
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,10 @@ | ||
use smallvec::smallvec; | ||
|
||
use crate::traits::{Obligation, ObligationCause, PredicateObligation}; | ||
use rustc_data_structures::fx::FxHashSet; | ||
use rustc_middle::ty::outlives::Component; | ||
use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, TyCtxt, WithConstness}; | ||
use rustc_span::Span; | ||
|
||
pub fn anonymize_predicate<'tcx>( | ||
tcx: TyCtxt<'tcx>, | ||
|
@@ -87,7 +89,7 @@ impl<T: AsRef<ty::Predicate<'tcx>>> Extend<T> for PredicateSet<'tcx> { | |
/// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that | ||
/// `T: Foo`, then we know that `T: 'static`. | ||
pub struct Elaborator<'tcx> { | ||
stack: Vec<ty::Predicate<'tcx>>, | ||
stack: Vec<PredicateObligation<'tcx>>, | ||
visited: PredicateSet<'tcx>, | ||
} | ||
|
||
|
@@ -112,35 +114,60 @@ pub fn elaborate_predicates<'tcx>( | |
) -> Elaborator<'tcx> { | ||
let mut visited = PredicateSet::new(tcx); | ||
predicates.retain(|pred| visited.insert(pred)); | ||
Elaborator { stack: predicates, visited } | ||
let obligations: Vec<_> = | ||
predicates.into_iter().map(|predicate| predicate_obligation(predicate, None)).collect(); | ||
Comment on lines
+117
to
+118
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, this is |
||
elaborate_obligations(tcx, obligations) | ||
} | ||
|
||
pub fn elaborate_obligations<'tcx>( | ||
tcx: TyCtxt<'tcx>, | ||
mut obligations: Vec<PredicateObligation<'tcx>>, | ||
) -> Elaborator<'tcx> { | ||
let mut visited = PredicateSet::new(tcx); | ||
obligations.retain(|obligation| visited.insert(&obligation.predicate)); | ||
Elaborator { stack: obligations, visited } | ||
} | ||
|
||
fn predicate_obligation<'tcx>( | ||
predicate: ty::Predicate<'tcx>, | ||
span: Option<Span>, | ||
) -> PredicateObligation<'tcx> { | ||
let mut cause = ObligationCause::dummy(); | ||
if let Some(span) = span { | ||
cause.span = span; | ||
} | ||
Obligation { cause, param_env: ty::ParamEnv::empty(), recursion_depth: 0, predicate } | ||
} | ||
nikomatsakis marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
impl Elaborator<'tcx> { | ||
pub fn filter_to_traits(self) -> FilterToTraits<Self> { | ||
FilterToTraits::new(self) | ||
} | ||
|
||
fn elaborate(&mut self, predicate: &ty::Predicate<'tcx>) { | ||
fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) { | ||
let tcx = self.visited.tcx; | ||
match *predicate { | ||
match obligation.predicate { | ||
ty::Predicate::Trait(ref data, _) => { | ||
// Get predicates declared on the trait. | ||
let predicates = tcx.super_predicates_of(data.def_id()); | ||
|
||
let predicates = predicates | ||
.predicates | ||
.iter() | ||
.map(|(pred, _)| pred.subst_supertrait(tcx, &data.to_poly_trait_ref())); | ||
debug!("super_predicates: data={:?} predicates={:?}", data, predicates.clone()); | ||
let obligations = predicates.predicates.iter().map(|(pred, span)| { | ||
predicate_obligation( | ||
pred.subst_supertrait(tcx, &data.to_poly_trait_ref()), | ||
Some(*span), | ||
) | ||
}); | ||
debug!("super_predicates: data={:?} predicates={:?}", data, &obligations); | ||
|
||
// Only keep those bounds that we haven't already seen. | ||
// This is necessary to prevent infinite recursion in some | ||
// cases. One common case is when people define | ||
// `trait Sized: Sized { }` rather than `trait Sized { }`. | ||
let visited = &mut self.visited; | ||
let predicates = predicates.filter(|pred| visited.insert(pred)); | ||
let obligations = | ||
obligations.filter(|obligation| visited.insert(&obligation.predicate)); | ||
|
||
self.stack.extend(predicates); | ||
self.stack.extend(obligations); | ||
} | ||
ty::Predicate::WellFormed(..) => { | ||
// Currently, we do not elaborate WF predicates, | ||
|
@@ -221,25 +248,26 @@ impl Elaborator<'tcx> { | |
None | ||
} | ||
}) | ||
.filter(|p| visited.insert(p)), | ||
.filter(|p| visited.insert(p)) | ||
.map(|p| predicate_obligation(p, None)), | ||
); | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl Iterator for Elaborator<'tcx> { | ||
type Item = ty::Predicate<'tcx>; | ||
type Item = PredicateObligation<'tcx>; | ||
|
||
fn size_hint(&self) -> (usize, Option<usize>) { | ||
(self.stack.len(), None) | ||
} | ||
|
||
fn next(&mut self) -> Option<ty::Predicate<'tcx>> { | ||
fn next(&mut self) -> Option<Self::Item> { | ||
// Extract next item from top-most stack frame, if any. | ||
if let Some(pred) = self.stack.pop() { | ||
self.elaborate(&pred); | ||
Some(pred) | ||
if let Some(obligation) = self.stack.pop() { | ||
self.elaborate(&obligation); | ||
Some(obligation) | ||
} else { | ||
None | ||
} | ||
|
@@ -282,12 +310,12 @@ impl<I> FilterToTraits<I> { | |
} | ||
} | ||
|
||
impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> { | ||
impl<'tcx, I: Iterator<Item = PredicateObligation<'tcx>>> Iterator for FilterToTraits<I> { | ||
type Item = ty::PolyTraitRef<'tcx>; | ||
|
||
fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> { | ||
while let Some(pred) = self.base_iterator.next() { | ||
if let ty::Predicate::Trait(data, _) = pred { | ||
while let Some(obligation) = self.base_iterator.next() { | ||
if let ty::Predicate::Trait(data, _) = obligation.predicate { | ||
return Some(data.to_poly_trait_ref()); | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -297,7 +297,9 @@ pub fn normalize_param_env_or_error<'tcx>( | |
); | ||
|
||
let mut predicates: Vec<_> = | ||
util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.to_vec()).collect(); | ||
util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.to_vec()) | ||
.map(|obligation| obligation.predicate) | ||
.collect(); | ||
Comment on lines
-300
to
+302
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tempted to try and find every allocation in the trait system and rewrite it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you going to be doing it or should I try and do some of it now? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you want to play around with it, feel free to! I was mostly considering taking this over in case you don't have time for it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I won't have time to look at There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looking at this in closer detail, I think I might be able to simplify this a bit. |
||
|
||
debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -312,19 +312,18 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { | |
let item = self.item; | ||
|
||
if let Elaborate::All = elaborate { | ||
let predicates = obligations.iter().map(|obligation| obligation.predicate).collect(); | ||
let implied_obligations = traits::elaborate_predicates(tcx, predicates); | ||
let implied_obligations = implied_obligations.map(|pred| { | ||
let implied_obligations = traits::util::elaborate_obligations(tcx, obligations.clone()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At a glance this seems wasteful but it's not worse than it was before. Presumably we can avoid this clone altogether, but I haven't checked. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The only reason I didn't strip them outright was because of |
||
let implied_obligations = implied_obligations.map(|obligation| { | ||
let mut cause = cause.clone(); | ||
extend_cause_with_original_assoc_item_obligation( | ||
tcx, | ||
trait_ref, | ||
item, | ||
&mut cause, | ||
&pred, | ||
&obligation.predicate, | ||
tcx.associated_items(trait_ref.def_id).in_definition_order().copied(), | ||
); | ||
traits::Obligation::new(cause, param_env, pred) | ||
traits::Obligation::new(cause, param_env, obligation.predicate) | ||
}); | ||
self.out.extend(implied_obligations); | ||
} | ||
|
@@ -613,11 +612,14 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { | |
substs: SubstsRef<'tcx>, | ||
) -> Vec<traits::PredicateObligation<'tcx>> { | ||
let predicates = self.infcx.tcx.predicates_of(def_id).instantiate(self.infcx.tcx, substs); | ||
let cause = self.cause(traits::ItemObligation(def_id)); | ||
predicates | ||
.predicates | ||
.into_iter() | ||
.map(|pred| traits::Obligation::new(cause.clone(), self.param_env, pred)) | ||
.zip(predicates.spans.into_iter()) | ||
.map(|(pred, span)| { | ||
let cause = self.cause(traits::BindingObligation(def_id, span)); | ||
traits::Obligation::new(cause, self.param_env, pred) | ||
}) | ||
.filter(|pred| !pred.has_escaping_bound_vars()) | ||
.collect() | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh I wonder if it's stuff like this - this is very wasteful and unlikely to be needed.