}
#[cfg(target_arch = "x86_64")]
-static_assert_size!(PredicateInner<'_>, 40);
+static_assert_size!(PredicateInner<'_>, 48);
#[derive(Clone, Copy, Lift)]
pub struct Predicate<'tcx> {
pub fn kind(self) -> &'tcx PredicateKind<'tcx> {
&self.inner.kind
}
+
+ /// Returns the inner `PredicateAtom`.
+ ///
+ /// Note that this method panics in case this predicate has unbound variables.
+ pub fn skip_binders(self) -> PredicateAtom<'tcx> {
+ match self.kind() {
+ &PredicateKind::ForAll(binder) => binder.skip_binder().skip_binders(),
+ &ty::PredicateKind::Atom(atom) => atom,
+ }
+ }
+
+ /// Returns the inner `PredicateAtom`.
+ ///
+ /// Note that this method does not check if predicate has unbound variables,
+ /// rebinding the returned atom potentially causes the previously bound variables
+ /// to end up at the wrong binding level.
+ pub fn skip_binders_unchecked(self) -> PredicateAtom<'tcx> {
+ match self.kind() {
+ &PredicateKind::ForAll(binder) => binder.skip_binder().skip_binders(),
+ &ty::PredicateKind::Atom(atom) => atom,
+ }
+ }
+
+ pub fn bound_atom(self, tcx: TyCtxt<'tcx>) -> Binder<PredicateAtom<'tcx>> {
+ match self.kind() {
+ &PredicateKind::ForAll(binder) => binder.map_bound(|inner| match inner.kind() {
+ ty::PredicateKind::ForAll(_) => bug!("unexpect forall"),
+ &ty::PredicateKind::Atom(atom) => atom,
+ }),
+ &ty::PredicateKind::Atom(atom) => Binder::wrap_nonbinding(tcx, atom),
+ }
+ }
+
+ /// Wraps `self` with the given qualifier if this predicate has any unbound variables.
+ pub fn potentially_quantified(
+ self,
+ tcx: TyCtxt<'tcx>,
+ qualifier: impl FnOnce(Binder<Predicate<'tcx>>) -> PredicateKind<'tcx>,
+ ) -> Predicate<'tcx> {
+ if self.has_escaping_bound_vars() {
+ qualifier(Binder::bind(self)).to_predicate(tcx)
+ } else {
+ self
+ }
+ }
}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
#[derive(HashStable, TypeFoldable)]
pub enum PredicateKind<'tcx> {
+ /// `for<'a>: ...`
+ ForAll(Binder<Predicate<'tcx>>),
+
+ Atom(PredicateAtom<'tcx>),
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(HashStable, TypeFoldable)]
+pub enum PredicateAtom<'tcx> {
/// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be
/// the `Self` type of the trait reference and `A`, `B`, and `C`
/// would be the type parameters.
/// A trait predicate will have `Constness::Const` if it originates
/// from a bound on a `const fn` without the `?const` opt-out (e.g.,
/// `const fn foobar<Foo: Bar>() {}`).
- Trait(PolyTraitPredicate<'tcx>, Constness),
+ Trait(TraitPredicate<'tcx>, Constness),
/// `where 'a: 'b`
- RegionOutlives(PolyRegionOutlivesPredicate<'tcx>),
+ RegionOutlives(RegionOutlivesPredicate<'tcx>),
/// `where T: 'a`
- TypeOutlives(PolyTypeOutlivesPredicate<'tcx>),
+ TypeOutlives(TypeOutlivesPredicate<'tcx>),
/// `where <T as TraitRef>::Name == X`, approximately.
/// See the `ProjectionPredicate` struct for details.
- Projection(PolyProjectionPredicate<'tcx>),
+ Projection(ProjectionPredicate<'tcx>),
/// No syntax: `T` well-formed.
WellFormed(GenericArg<'tcx>),
ClosureKind(DefId, SubstsRef<'tcx>, ClosureKind),
/// `T1 <: T2`
- Subtype(PolySubtypePredicate<'tcx>),
+ Subtype(SubtypePredicate<'tcx>),
/// Constant initializer must evaluate successfully.
ConstEvaluatable(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
// substitution code expects equal binding levels in the values
// from the substitution and the value being substituted into, and
// this trick achieves that).
-
- let substs = &trait_ref.skip_binder().substs;
- let kind = self.kind();
- let new = match kind {
- &PredicateKind::Trait(ref binder, constness) => {
- PredicateKind::Trait(binder.map_bound(|data| data.subst(tcx, substs)), constness)
- }
- PredicateKind::Subtype(binder) => {
- PredicateKind::Subtype(binder.map_bound(|data| data.subst(tcx, substs)))
- }
- PredicateKind::RegionOutlives(binder) => {
- PredicateKind::RegionOutlives(binder.map_bound(|data| data.subst(tcx, substs)))
- }
- PredicateKind::TypeOutlives(binder) => {
- PredicateKind::TypeOutlives(binder.map_bound(|data| data.subst(tcx, substs)))
- }
- PredicateKind::Projection(binder) => {
- PredicateKind::Projection(binder.map_bound(|data| data.subst(tcx, substs)))
- }
- &PredicateKind::WellFormed(data) => PredicateKind::WellFormed(data.subst(tcx, substs)),
- &PredicateKind::ObjectSafe(trait_def_id) => PredicateKind::ObjectSafe(trait_def_id),
- &PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
- PredicateKind::ClosureKind(closure_def_id, closure_substs.subst(tcx, substs), kind)
- }
- &PredicateKind::ConstEvaluatable(def_id, const_substs) => {
- PredicateKind::ConstEvaluatable(def_id, const_substs.subst(tcx, substs))
- }
- PredicateKind::ConstEquate(c1, c2) => {
- PredicateKind::ConstEquate(c1.subst(tcx, substs), c2.subst(tcx, substs))
- }
- };
-
- if new != *kind { new.to_predicate(tcx) } else { self }
+ let substs = trait_ref.skip_binder().substs;
+ let pred = self.skip_binders();
+ let new = pred.subst(tcx, substs);
+ if new != pred {
+ new.to_predicate(tcx).potentially_quantified(tcx, PredicateKind::ForAll)
+ } else {
+ self
+ }
}
}
}
}
-impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<TraitRef<'tcx>> {
- fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
- ty::PredicateKind::Trait(
- ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.value }),
- self.constness,
- )
- .to_predicate(tcx)
+impl ToPredicate<'tcx> for PredicateAtom<'tcx> {
+ #[inline(always)]
+ fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+ tcx.mk_predicate(ty::PredicateKind::Atom(*self))
}
}
-impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&TraitRef<'tcx>> {
- fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
- ty::PredicateKind::Trait(
- ty::Binder::dummy(ty::TraitPredicate { trait_ref: *self.value }),
- self.constness,
- )
- .to_predicate(tcx)
+impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<TraitRef<'tcx>> {
+ fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+ ty::PredicateAtom::Trait(ty::TraitPredicate { trait_ref: self.value }, self.constness)
+ .to_predicate(tcx)
}
}
impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<PolyTraitRef<'tcx>> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
- ty::PredicateKind::Trait(self.value.to_poly_trait_predicate(), self.constness)
- .to_predicate(tcx)
+ ConstnessAnd {
+ value: self.value.map_bound(|trait_ref| ty::TraitPredicate { trait_ref }),
+ constness: self.constness,
+ }
+ .to_predicate(tcx)
}
}
-impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&PolyTraitRef<'tcx>> {
+impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<PolyTraitPredicate<'tcx>> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
- ty::PredicateKind::Trait(self.value.to_poly_trait_predicate(), self.constness)
+ if let Some(pred) = self.value.no_bound_vars() {
+ ty::PredicateAtom::Trait(pred, self.constness).to_predicate(tcx)
+ } else {
+ ty::PredicateKind::ForAll(
+ self.value.map_bound(|pred| {
+ ty::PredicateAtom::Trait(pred, self.constness).to_predicate(tcx)
+ }),
+ )
.to_predicate(tcx)
+ }
}
}
impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
- PredicateKind::RegionOutlives(self).to_predicate(tcx)
+ if let Some(outlives) = self.no_bound_vars() {
+ PredicateAtom::RegionOutlives(outlives).to_predicate(tcx)
+ } else {
+ ty::PredicateKind::ForAll(
+ self.map_bound(|outlives| {
+ PredicateAtom::RegionOutlives(outlives).to_predicate(tcx)
+ }),
+ )
+ .to_predicate(tcx)
+ }
}
}
impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
- PredicateKind::TypeOutlives(self).to_predicate(tcx)
+ if let Some(outlives) = self.no_bound_vars() {
+ PredicateAtom::TypeOutlives(outlives).to_predicate(tcx)
+ } else {
+ ty::PredicateKind::ForAll(
+ self.map_bound(|outlives| PredicateAtom::TypeOutlives(outlives).to_predicate(tcx)),
+ )
+ .to_predicate(tcx)
+ }
}
}
impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
- PredicateKind::Projection(self).to_predicate(tcx)
+ if let Some(proj) = self.no_bound_vars() {
+ PredicateAtom::Projection(proj).to_predicate(tcx)
+ } else {
+ ty::PredicateKind::ForAll(
+ self.map_bound(|proj| PredicateAtom::Projection(proj).to_predicate(tcx)),
+ )
+ .to_predicate(tcx)
+ }
}
}
impl<'tcx> Predicate<'tcx> {
pub fn to_opt_poly_trait_ref(self) -> Option<PolyTraitRef<'tcx>> {
- match self.kind() {
- &PredicateKind::Trait(ref t, _) => Some(t.to_poly_trait_ref()),
- PredicateKind::Projection(..)
- | PredicateKind::Subtype(..)
- | PredicateKind::RegionOutlives(..)
- | PredicateKind::WellFormed(..)
- | PredicateKind::ObjectSafe(..)
- | PredicateKind::ClosureKind(..)
- | PredicateKind::TypeOutlives(..)
- | PredicateKind::ConstEvaluatable(..)
- | PredicateKind::ConstEquate(..) => None,
+ match self.skip_binders() {
+ PredicateAtom::Trait(t, _) => Some(ty::Binder::bind(t.trait_ref)),
+ PredicateAtom::Projection(..)
+ | PredicateAtom::Subtype(..)
+ | PredicateAtom::RegionOutlives(..)
+ | PredicateAtom::WellFormed(..)
+ | PredicateAtom::ObjectSafe(..)
+ | PredicateAtom::ClosureKind(..)
+ | PredicateAtom::TypeOutlives(..)
+ | PredicateAtom::ConstEvaluatable(..)
+ | PredicateAtom::ConstEquate(..) => None,
}
}
pub fn to_opt_type_outlives(self) -> Option<PolyTypeOutlivesPredicate<'tcx>> {
- match self.kind() {
- &PredicateKind::TypeOutlives(data) => Some(data),
- PredicateKind::Trait(..)
- | PredicateKind::Projection(..)
- | PredicateKind::Subtype(..)
- | PredicateKind::RegionOutlives(..)
- | PredicateKind::WellFormed(..)
- | PredicateKind::ObjectSafe(..)
- | PredicateKind::ClosureKind(..)
- | PredicateKind::ConstEvaluatable(..)
- | PredicateKind::ConstEquate(..) => None,
+ match self.skip_binders() {
+ PredicateAtom::TypeOutlives(data) => Some(ty::Binder::bind(data)),
+ PredicateAtom::Trait(..)
+ | PredicateAtom::Projection(..)
+ | PredicateAtom::Subtype(..)
+ | PredicateAtom::RegionOutlives(..)
+ | PredicateAtom::WellFormed(..)
+ | PredicateAtom::ObjectSafe(..)
+ | PredicateAtom::ClosureKind(..)
+ | PredicateAtom::ConstEvaluatable(..)
+ | PredicateAtom::ConstEquate(..) => None,
}
}
}