}
#[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> {
}
}
-impl<'tcx> Predicate<'tcx> {
- pub fn kint(self, tcx: TyCtxt<'tcx>) -> &'tcx PredicateKint<'tcx> {
- // I am efficient
- tcx.intern_predicate_kint(match *self.kind() {
- PredicateKind::Trait(binder, data) => {
- if let Some(simpl) = binder.no_bound_vars() {
- PredicateKint::Trait(simpl, data)
- } else {
- let inner = tcx
- .intern_predicate_kint(PredicateKint::Trait(*binder.skip_binder(), data));
- PredicateKint::ForAll(Binder::bind(inner))
- }
- }
- PredicateKind::RegionOutlives(binder) => {
- if let Some(simpl) = binder.no_bound_vars() {
- PredicateKint::RegionOutlives(simpl)
- } else {
- let inner = tcx.intern_predicate_kint(PredicateKint::RegionOutlives(
- *binder.skip_binder(),
- ));
- PredicateKint::ForAll(Binder::bind(inner))
- }
- }
- PredicateKind::TypeOutlives(binder) => {
- if let Some(simpl) = binder.no_bound_vars() {
- PredicateKint::TypeOutlives(simpl)
- } else {
- let inner = tcx
- .intern_predicate_kint(PredicateKint::TypeOutlives(*binder.skip_binder()));
- PredicateKint::ForAll(Binder::bind(inner))
- }
- }
- PredicateKind::Projection(binder) => {
- if let Some(simpl) = binder.no_bound_vars() {
- PredicateKint::Projection(simpl)
- } else {
- let inner =
- tcx.intern_predicate_kint(PredicateKint::Projection(*binder.skip_binder()));
- PredicateKint::ForAll(Binder::bind(inner))
- }
- }
- PredicateKind::WellFormed(arg) => PredicateKint::WellFormed(arg),
- PredicateKind::ObjectSafe(def_id) => PredicateKint::ObjectSafe(def_id),
- PredicateKind::ClosureKind(def_id, substs, kind) => {
- PredicateKint::ClosureKind(def_id, substs, kind)
- }
- PredicateKind::Subtype(binder) => {
- if let Some(simpl) = binder.no_bound_vars() {
- PredicateKint::Subtype(simpl)
- } else {
- let inner =
- tcx.intern_predicate_kint(PredicateKint::Subtype(*binder.skip_binder()));
- PredicateKint::ForAll(Binder::bind(inner))
- }
- }
- PredicateKind::ConstEvaluatable(def, substs) => {
- PredicateKint::ConstEvaluatable(def, substs)
- }
- PredicateKind::ConstEquate(l, r) => PredicateKint::ConstEquate(l, r),
- })
- }
+#[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(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-#[derive(TypeFoldable)]
-pub enum PredicateKint<'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.
/// `T1 <: T2`
Subtype(SubtypePredicate<'tcx>),
- /// Constant initializer must evaluate successfully.
- ConstEvaluatable(DefId, SubstsRef<'tcx>),
-
- /// Constants must be equal. The first component is the const that is expected.
- ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>),
-
- /// `for<'a>: ...`
- ForAll(Binder<&'tcx PredicateKint<'tcx>>),
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
-#[derive(HashStable, TypeFoldable)]
-pub enum PredicateKind<'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),
-
- /// `where 'a: 'b`
- RegionOutlives(PolyRegionOutlivesPredicate<'tcx>),
-
- /// `where T: 'a`
- TypeOutlives(PolyTypeOutlivesPredicate<'tcx>),
-
- /// `where <T as TraitRef>::Name == X`, approximately.
- /// See the `ProjectionPredicate` struct for details.
- Projection(PolyProjectionPredicate<'tcx>),
-
- /// No syntax: `T` well-formed.
- WellFormed(GenericArg<'tcx>),
-
- /// Trait must be object-safe.
- ObjectSafe(DefId),
-
- /// No direct syntax. May be thought of as `where T: FnFoo<...>`
- /// for some substitutions `...` and `T` being a closure type.
- /// Satisfied (or refuted) once we know the closure's kind.
- ClosureKind(DefId, SubstsRef<'tcx>, ClosureKind),
-
- /// `T1 <: T2`
- Subtype(PolySubtypePredicate<'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 ToPredicate<'tcx> for PredicateKint<'tcx> {
+impl ToPredicate<'tcx> for PredicateAtom<'tcx> {
#[inline(always)]
fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
- let (predicate, in_binder) = if let PredicateKint::ForAll(binder) = self {
- (*binder.skip_binder(), true)
- } else {
- (self, false)
- };
-
- macro_rules! bind {
- ($expr:expr) => {
- match $expr {
- expr => {
- if in_binder {
- Binder::bind(expr)
- } else {
- Binder::dummy(expr)
- }
- }
- }
- };
- }
-
- match *predicate {
- PredicateKint::ForAll(_) => bug!("unexpected PredicateKint: {:?}", self),
- PredicateKint::Trait(data, ct) => PredicateKind::Trait(bind!(data), ct),
- PredicateKint::RegionOutlives(data) => PredicateKind::RegionOutlives(bind!(data)),
- PredicateKint::TypeOutlives(data) => PredicateKind::TypeOutlives(bind!(data)),
- PredicateKint::Projection(data) => PredicateKind::Projection(bind!(data)),
- PredicateKint::WellFormed(arg) => {
- if in_binder {
- bug!("unexpected ForAll: {:?}", self)
- } else {
- PredicateKind::WellFormed(arg)
- }
- }
- PredicateKint::ObjectSafe(def_id) => {
- if in_binder {
- bug!("unexpected ForAll: {:?}", self)
- } else {
- PredicateKind::ObjectSafe(def_id)
- }
- }
- PredicateKint::ClosureKind(def_id, substs, kind) => {
- if in_binder {
- bug!("unexpected ForAll: {:?}", self)
- } else {
- PredicateKind::ClosureKind(def_id, substs, kind)
- }
- }
- PredicateKint::Subtype(data) => PredicateKind::Subtype(bind!(data)),
- PredicateKint::ConstEvaluatable(def_id, substs) => {
- if in_binder {
- bug!("unexpected ForAll: {:?}", self)
- } else {
- PredicateKind::ConstEvaluatable(def_id, substs)
- }
- }
- PredicateKint::ConstEquate(l, r) => {
- if in_binder {
- bug!("unexpected ForAll: {:?}", self)
- } else {
- PredicateKind::ConstEquate(l, r)
- }
- }
- }
- .to_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::PredicateKind::Trait(
- ty::Binder::dummy(ty::TraitPredicate { trait_ref: *self.value }),
- self.constness,
- )
- .to_predicate(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,
}
}
}