pub extern_prelude: FxHashMap<Symbol, bool>,
}
-#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash)]
pub enum AssocItemContainer {
TraitContainer(DefId),
ImplContainer(DefId),
Reservation,
}
-#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
+#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash)]
pub struct AssocItem {
pub def_id: DefId,
#[stable_hasher(project(name))]
pub fn_has_self_parameter: bool,
}
-#[derive(Copy, Clone, PartialEq, Debug, HashStable)]
+#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash)]
pub enum AssocKind {
Const,
Fn,
}
}
-#[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable, HashStable, Hash)]
pub enum Visibility {
/// Visible everywhere (including in other crates).
Public,
}
#[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,
}
}
}
impl<T> WithOptConstParam<T> {
/// Creates a new `WithOptConstParam` setting `const_param_did` to `None`.
+ #[inline(always)]
pub fn unknown(did: T) -> WithOptConstParam<T> {
WithOptConstParam { did, const_param_did: None }
}
}
impl WithOptConstParam<LocalDefId> {
+ /// Returns `Some((did, param_did))` if `def_id` is a const argument,
+ /// `None` otherwise.
+ #[inline(always)]
+ pub fn try_lookup(did: LocalDefId, tcx: TyCtxt<'_>) -> Option<(LocalDefId, DefId)> {
+ tcx.opt_const_param_of(did).map(|param_did| (did, param_did))
+ }
+
+ /// In case `self` is unknown but `self.did` is a const argument, this returns
+ /// a `WithOptConstParam` with the correct `const_param_did`.
+ #[inline(always)]
+ pub fn try_upgrade(self, tcx: TyCtxt<'_>) -> Option<WithOptConstParam<LocalDefId>> {
+ if self.const_param_did.is_none() {
+ if let const_param_did @ Some(_) = tcx.opt_const_param_of(self.did) {
+ return Some(WithOptConstParam { did: self.did, const_param_did });
+ }
+ }
+
+ None
+ }
+
pub fn to_global(self) -> WithOptConstParam<DefId> {
WithOptConstParam { did: self.did.to_def_id(), const_param_did: self.const_param_did }
}