]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_middle/ty/mod.rs
introduce PredicateAtom
[rust.git] / src / librustc_middle / ty / mod.rs
index b8f95501262474d672ecfc6d44fba030d77a4fce..0ff475fb288a6fa24c75e10d2dca11ffd7fff41a 100644 (file)
@@ -1018,7 +1018,7 @@ pub fn instantiate_supertrait(
 }
 
 #[cfg(target_arch = "x86_64")]
-static_assert_size!(PredicateInner<'_>, 40);
+static_assert_size!(PredicateInner<'_>, 48);
 
 #[derive(Clone, Copy, Lift)]
 pub struct Predicate<'tcx> {
@@ -1048,6 +1048,51 @@ impl<'tcx> 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> {
@@ -1065,72 +1110,18 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
     }
 }
 
-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.
@@ -1164,52 +1155,6 @@ pub enum PredicateKint<'tcx> {
     /// `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>),
 
@@ -1217,16 +1162,6 @@ pub enum PredicateKind<'tcx> {
     ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>),
 }
 
-impl<'tcx> PredicateKint<'tcx> {
-    /// Skips `PredicateKint::ForAll`.
-    pub fn ignore_qualifiers(&'tcx self) -> Binder<&'tcx PredicateKint<'tcx>> {
-        match self {
-            &PredicateKint::ForAll(binder) => binder,
-            pred => Binder::dummy(pred),
-        }
-    }
-}
-
 /// The crate outlives map is computed during typeck and contains the
 /// outlives of every item in the local crate. You should not use it
 /// directly, because to do so will make your pass dependent on the
@@ -1311,22 +1246,14 @@ pub fn subst_supertrait(
         // 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 = match self.kint(tcx) {
-            PredicateKint::ForAll(binder) => *binder.skip_binder(),
-            kind => kind,
-        };
-
-        let new = kind.subst(tcx, substs);
-
-        let rebound = if new.has_escaping_bound_vars() {
-            PredicateKint::ForAll(Binder::bind(tcx.intern_predicate_kint(new)))
+        let pred = self.skip_binders();
+        let new = pred.subst(tcx, substs);
+        if new != pred {
+            new.to_predicate(tcx).potentially_quantified(tcx, PredicateKind::ForAll)
         } else {
-            new
-        };
-
-        if rebound != *kind { rebound.to_predicate(tcx) } else { self }
+            self
+        }
     }
 }
 
@@ -1451,152 +1378,114 @@ fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
     }
 }
 
-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::PredicateKint::Trait(ty::TraitPredicate { trait_ref: self.value }, self.constness)
+    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> {
-        if let Some(trait_ref) = self.value.no_bound_vars() {
-            ty::PredicateKint::Trait(ty::TraitPredicate { trait_ref }, self.constness)
-        } else {
-            ty::PredicateKint::ForAll(self.value.map_bound(|trait_ref| {
-                tcx.intern_predicate_kint(ty::PredicateKint::Trait(
-                    ty::TraitPredicate { trait_ref },
-                    self.constness,
-                ))
-            }))
+        ConstnessAnd {
+            value: self.value.map_bound(|trait_ref| ty::TraitPredicate { trait_ref }),
+            constness: self.constness,
         }
         .to_predicate(tcx)
     }
 }
 
+impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<PolyTraitPredicate<'tcx>> {
+    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+        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> {
         if let Some(outlives) = self.no_bound_vars() {
-            PredicateKint::RegionOutlives(outlives)
+            PredicateAtom::RegionOutlives(outlives).to_predicate(tcx)
         } else {
-            ty::PredicateKint::ForAll(self.map_bound(|outlives| {
-                tcx.intern_predicate_kint(PredicateKint::RegionOutlives(outlives))
-            }))
+            ty::PredicateKind::ForAll(
+                self.map_bound(|outlives| {
+                    PredicateAtom::RegionOutlives(outlives).to_predicate(tcx)
+                }),
+            )
+            .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,
         }
     }
 }