Auto merge of #110031 - compiler-errors:generic-elaboration, r=b-naber
Make elaboration generic over input Combines all the `elaborate_*` family of functions into just one, which is an iterator over the same type that you pass in (e.g. elaborating `Predicate` gives `Predicate`s, elaborating `Obligation`s gives `Obligation`s, etc.)
This commit is contained in:
commit
f8ed97ecc1
22 changed files with 163 additions and 164 deletions
|
@ -1,7 +1,7 @@
|
|||
use smallvec::smallvec;
|
||||
|
||||
use crate::infer::outlives::components::{push_outlives_components, Component};
|
||||
use crate::traits::{self, Obligation, ObligationCause, PredicateObligation};
|
||||
use crate::traits::{self, Obligation, PredicateObligation};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
|
||||
use rustc_middle::ty::{self, ToPredicate, TyCtxt};
|
||||
use rustc_span::symbol::Ident;
|
||||
|
@ -66,99 +66,129 @@ impl<'tcx> Extend<ty::Predicate<'tcx>> for PredicateSet<'tcx> {
|
|||
/// if we know that `T: Ord`, the elaborator would deduce that `T: PartialOrd`
|
||||
/// 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<PredicateObligation<'tcx>>,
|
||||
pub struct Elaborator<'tcx, O> {
|
||||
stack: Vec<O>,
|
||||
visited: PredicateSet<'tcx>,
|
||||
}
|
||||
|
||||
pub fn elaborate_trait_ref<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
) -> impl Iterator<Item = ty::Predicate<'tcx>> {
|
||||
elaborate_predicates(tcx, std::iter::once(trait_ref.without_const().to_predicate(tcx)))
|
||||
/// Describes how to elaborate an obligation into a sub-obligation.
|
||||
///
|
||||
/// For [`Obligation`], a sub-obligation is combined with the current obligation's
|
||||
/// param-env and cause code. For [`ty::Predicate`], none of this is needed, since
|
||||
/// there is no param-env or cause code to copy over.
|
||||
pub trait Elaboratable<'tcx> {
|
||||
fn predicate(&self) -> ty::Predicate<'tcx>;
|
||||
|
||||
// Makes a new `Self` but with a different predicate.
|
||||
fn child(&self, predicate: ty::Predicate<'tcx>) -> Self;
|
||||
|
||||
// Makes a new `Self` but with a different predicate and a different cause
|
||||
// code (if `Self` has one).
|
||||
fn child_with_derived_cause(
|
||||
&self,
|
||||
predicate: ty::Predicate<'tcx>,
|
||||
span: Span,
|
||||
parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
index: usize,
|
||||
) -> Self;
|
||||
}
|
||||
|
||||
pub fn elaborate_trait_refs<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
|
||||
) -> impl Iterator<Item = ty::Predicate<'tcx>> {
|
||||
let predicates = trait_refs.map(move |trait_ref| trait_ref.without_const().to_predicate(tcx));
|
||||
elaborate_predicates(tcx, predicates)
|
||||
impl<'tcx> Elaboratable<'tcx> for PredicateObligation<'tcx> {
|
||||
fn predicate(&self) -> ty::Predicate<'tcx> {
|
||||
self.predicate
|
||||
}
|
||||
|
||||
fn child(&self, predicate: ty::Predicate<'tcx>) -> Self {
|
||||
Obligation {
|
||||
cause: self.cause.clone(),
|
||||
param_env: self.param_env,
|
||||
recursion_depth: 0,
|
||||
predicate,
|
||||
}
|
||||
}
|
||||
|
||||
fn child_with_derived_cause(
|
||||
&self,
|
||||
predicate: ty::Predicate<'tcx>,
|
||||
span: Span,
|
||||
parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
index: usize,
|
||||
) -> Self {
|
||||
let cause = self.cause.clone().derived_cause(parent_trait_pred, |derived| {
|
||||
traits::ImplDerivedObligation(Box::new(traits::ImplDerivedObligationCause {
|
||||
derived,
|
||||
impl_or_alias_def_id: parent_trait_pred.def_id(),
|
||||
impl_def_predicate_index: Some(index),
|
||||
span,
|
||||
}))
|
||||
});
|
||||
Obligation { cause, param_env: self.param_env, recursion_depth: 0, predicate }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn elaborate_predicates<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
|
||||
) -> impl Iterator<Item = ty::Predicate<'tcx>> {
|
||||
elaborate_obligations(
|
||||
tcx,
|
||||
predicates
|
||||
.map(|predicate| {
|
||||
Obligation::new(
|
||||
tcx,
|
||||
// We'll dump the cause/param-env later
|
||||
ObligationCause::dummy(),
|
||||
ty::ParamEnv::empty(),
|
||||
predicate,
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
.map(|obl| obl.predicate)
|
||||
impl<'tcx> Elaboratable<'tcx> for ty::Predicate<'tcx> {
|
||||
fn predicate(&self) -> ty::Predicate<'tcx> {
|
||||
*self
|
||||
}
|
||||
|
||||
fn child(&self, predicate: ty::Predicate<'tcx>) -> Self {
|
||||
predicate
|
||||
}
|
||||
|
||||
fn child_with_derived_cause(
|
||||
&self,
|
||||
predicate: ty::Predicate<'tcx>,
|
||||
_span: Span,
|
||||
_parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
_index: usize,
|
||||
) -> Self {
|
||||
predicate
|
||||
}
|
||||
}
|
||||
|
||||
pub fn elaborate_predicates_with_span<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
predicates: impl Iterator<Item = (ty::Predicate<'tcx>, Span)>,
|
||||
) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> {
|
||||
elaborate_obligations(
|
||||
tcx,
|
||||
predicates
|
||||
.map(|(predicate, span)| {
|
||||
Obligation::new(
|
||||
tcx,
|
||||
// We'll dump the cause/param-env later
|
||||
ObligationCause::dummy_with_span(span),
|
||||
ty::ParamEnv::empty(),
|
||||
predicate,
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
.map(|obl| (obl.predicate, obl.cause.span))
|
||||
impl<'tcx> Elaboratable<'tcx> for (ty::Predicate<'tcx>, Span) {
|
||||
fn predicate(&self) -> ty::Predicate<'tcx> {
|
||||
self.0
|
||||
}
|
||||
|
||||
fn child(&self, predicate: ty::Predicate<'tcx>) -> Self {
|
||||
(predicate, self.1)
|
||||
}
|
||||
|
||||
fn child_with_derived_cause(
|
||||
&self,
|
||||
predicate: ty::Predicate<'tcx>,
|
||||
_span: Span,
|
||||
_parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
_index: usize,
|
||||
) -> Self {
|
||||
(predicate, self.1)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn elaborate_obligations<'tcx>(
|
||||
pub fn elaborate<'tcx, O: Elaboratable<'tcx>>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
obligations: Vec<PredicateObligation<'tcx>>,
|
||||
) -> Elaborator<'tcx> {
|
||||
obligations: impl IntoIterator<Item = O>,
|
||||
) -> Elaborator<'tcx, O> {
|
||||
let mut elaborator = Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx) };
|
||||
elaborator.extend_deduped(obligations);
|
||||
elaborator
|
||||
}
|
||||
|
||||
fn predicate_obligation<'tcx>(
|
||||
predicate: ty::Predicate<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
) -> PredicateObligation<'tcx> {
|
||||
Obligation { cause, param_env, recursion_depth: 0, predicate }
|
||||
}
|
||||
|
||||
impl<'tcx> Elaborator<'tcx> {
|
||||
fn extend_deduped(&mut self, obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>) {
|
||||
impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
|
||||
fn extend_deduped(&mut self, obligations: impl IntoIterator<Item = O>) {
|
||||
// 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;
|
||||
self.stack.extend(obligations.into_iter().filter(|o| self.visited.insert(o.predicate)));
|
||||
self.stack.extend(obligations.into_iter().filter(|o| self.visited.insert(o.predicate())));
|
||||
}
|
||||
|
||||
fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
|
||||
fn elaborate(&mut self, elaboratable: &O) {
|
||||
let tcx = self.visited.tcx;
|
||||
|
||||
let bound_predicate = obligation.predicate.kind();
|
||||
let bound_predicate = elaboratable.predicate().kind();
|
||||
match bound_predicate.skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(data)) => {
|
||||
// Get predicates declared on the trait.
|
||||
|
@ -170,24 +200,11 @@ impl<'tcx> Elaborator<'tcx> {
|
|||
if data.constness == ty::BoundConstness::NotConst {
|
||||
pred = pred.without_const(tcx);
|
||||
}
|
||||
|
||||
let cause = obligation.cause.clone().derived_cause(
|
||||
bound_predicate.rebind(data),
|
||||
|derived| {
|
||||
traits::ImplDerivedObligation(Box::new(
|
||||
traits::ImplDerivedObligationCause {
|
||||
derived,
|
||||
impl_or_alias_def_id: data.def_id(),
|
||||
impl_def_predicate_index: Some(index),
|
||||
span,
|
||||
},
|
||||
))
|
||||
},
|
||||
);
|
||||
predicate_obligation(
|
||||
elaboratable.child_with_derived_cause(
|
||||
pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
|
||||
obligation.param_env,
|
||||
cause,
|
||||
span,
|
||||
bound_predicate.rebind(data),
|
||||
index,
|
||||
)
|
||||
});
|
||||
debug!(?data, ?obligations, "super_predicates");
|
||||
|
@ -290,13 +307,7 @@ impl<'tcx> Elaborator<'tcx> {
|
|||
.map(|predicate_kind| {
|
||||
bound_predicate.rebind(predicate_kind).to_predicate(tcx)
|
||||
})
|
||||
.map(|predicate| {
|
||||
predicate_obligation(
|
||||
predicate,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
)
|
||||
}),
|
||||
.map(|predicate| elaboratable.child(predicate)),
|
||||
);
|
||||
}
|
||||
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
|
||||
|
@ -313,8 +324,8 @@ impl<'tcx> Elaborator<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Iterator for Elaborator<'tcx> {
|
||||
type Item = PredicateObligation<'tcx>;
|
||||
impl<'tcx, O: Elaboratable<'tcx>> Iterator for Elaborator<'tcx, O> {
|
||||
type Item = O;
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(self.stack.len(), None)
|
||||
|
@ -339,17 +350,21 @@ pub fn supertraits<'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
|
||||
FilterToTraits::new(elaborate_trait_ref(tcx, trait_ref))
|
||||
let pred: ty::Predicate<'tcx> = trait_ref.to_predicate(tcx);
|
||||
FilterToTraits::new(elaborate(tcx, [pred]))
|
||||
}
|
||||
|
||||
pub fn transitive_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
|
||||
) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
|
||||
FilterToTraits::new(elaborate_trait_refs(tcx, trait_refs))
|
||||
FilterToTraits::new(elaborate(
|
||||
tcx,
|
||||
trait_refs.map(|trait_ref| -> ty::Predicate<'tcx> { trait_ref.to_predicate(tcx) }),
|
||||
))
|
||||
}
|
||||
|
||||
/// A specialized variant of `elaborate_trait_refs` that only elaborates trait references that may
|
||||
/// A specialized variant of `elaborate` that only elaborates trait references that may
|
||||
/// define the given associated type `assoc_name`. It uses the
|
||||
/// `super_predicates_that_define_assoc_type` query to avoid enumerating super-predicates that
|
||||
/// aren't related to `assoc_item`. This is used when resolving types like `Self::Item` or
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue