| #[cfg(feature = "nightly")] |
| use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; |
| #[cfg(feature = "nightly")] |
| use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; |
| use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; |
| use std::fmt; |
| |
| use crate::{self as ty, DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx}; |
| |
| use self::ConstKind::*; |
| |
| /// Represents a constant in Rust. |
| #[derive(derivative::Derivative)] |
| #[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Eq(bound = ""))] |
| #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] |
| pub enum ConstKind<I: Interner> { |
| /// A const generic parameter. |
| Param(I::ParamConst), |
| |
| /// Infer the value of the const. |
| Infer(InferConst), |
| |
| /// Bound const variable, used only when preparing a trait query. |
| Bound(DebruijnIndex, I::BoundConst), |
| |
| /// A placeholder const - universally quantified higher-ranked const. |
| Placeholder(I::PlaceholderConst), |
| |
| /// An unnormalized const item such as an anon const or assoc const or free const item. |
| /// Right now anything other than anon consts does not actually work properly but this |
| /// should |
| Unevaluated(ty::UnevaluatedConst<I>), |
| |
| /// Used to hold computed value. |
| Value(I::ValueConst), |
| |
| /// A placeholder for a const which could not be computed; this is |
| /// propagated to avoid useless error messages. |
| Error(I::ErrorGuaranteed), |
| |
| /// Unevaluated non-const-item, used by `feature(generic_const_exprs)` to represent |
| /// const arguments such as `N + 1` or `foo(N)` |
| Expr(I::ExprConst), |
| } |
| |
| impl<I: Interner> PartialEq for ConstKind<I> { |
| fn eq(&self, other: &Self) -> bool { |
| match (self, other) { |
| (Param(l0), Param(r0)) => l0 == r0, |
| (Infer(l0), Infer(r0)) => l0 == r0, |
| (Bound(l0, l1), Bound(r0, r1)) => l0 == r0 && l1 == r1, |
| (Placeholder(l0), Placeholder(r0)) => l0 == r0, |
| (Unevaluated(l0), Unevaluated(r0)) => l0 == r0, |
| (Value(l0), Value(r0)) => l0 == r0, |
| (Error(l0), Error(r0)) => l0 == r0, |
| (Expr(l0), Expr(r0)) => l0 == r0, |
| _ => false, |
| } |
| } |
| } |
| |
| impl<I: Interner> fmt::Debug for ConstKind<I> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| WithInfcx::with_no_infcx(self).fmt(f) |
| } |
| } |
| |
| impl<I: Interner> DebugWithInfcx<I> for ConstKind<I> { |
| fn fmt<Infcx: InferCtxtLike<Interner = I>>( |
| this: WithInfcx<'_, Infcx, &Self>, |
| f: &mut core::fmt::Formatter<'_>, |
| ) -> core::fmt::Result { |
| use ConstKind::*; |
| |
| match this.data { |
| Param(param) => write!(f, "{param:?}"), |
| Infer(var) => write!(f, "{:?}", &this.wrap(var)), |
| Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var), |
| Placeholder(placeholder) => write!(f, "{placeholder:?}"), |
| Unevaluated(uv) => { |
| write!(f, "{:?}", &this.wrap(uv)) |
| } |
| Value(valtree) => write!(f, "{valtree:?}"), |
| Error(_) => write!(f, "{{const error}}"), |
| Expr(expr) => write!(f, "{:?}", &this.wrap(expr)), |
| } |
| } |
| } |
| |
| /// An unevaluated (potentially generic) constant used in the type-system. |
| #[derive(derivative::Derivative)] |
| #[derivative( |
| Clone(bound = ""), |
| Copy(bound = ""), |
| Hash(bound = ""), |
| PartialEq(bound = ""), |
| Eq(bound = "") |
| )] |
| #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] |
| #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] |
| pub struct UnevaluatedConst<I: Interner> { |
| pub def: I::DefId, |
| pub args: I::GenericArgs, |
| } |
| |
| impl<I: Interner> UnevaluatedConst<I> { |
| #[inline] |
| pub fn new(def: I::DefId, args: I::GenericArgs) -> UnevaluatedConst<I> { |
| UnevaluatedConst { def, args } |
| } |
| } |
| |
| impl<I: Interner> fmt::Debug for UnevaluatedConst<I> { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| WithInfcx::with_no_infcx(self).fmt(f) |
| } |
| } |
| impl<I: Interner> DebugWithInfcx<I> for UnevaluatedConst<I> { |
| fn fmt<Infcx: InferCtxtLike<Interner = I>>( |
| this: WithInfcx<'_, Infcx, &Self>, |
| f: &mut core::fmt::Formatter<'_>, |
| ) -> core::fmt::Result { |
| f.debug_struct("UnevaluatedConst") |
| .field("def", &this.data.def) |
| .field("args", &this.wrap(this.data.args)) |
| .finish() |
| } |
| } |
| |
| rustc_index::newtype_index! { |
| /// A **`const`** **v**ariable **ID**. |
| #[encodable] |
| #[orderable] |
| #[debug_format = "?{}c"] |
| #[gate_rustc_only] |
| pub struct ConstVid {} |
| } |
| |
| rustc_index::newtype_index! { |
| /// An **effect** **v**ariable **ID**. |
| /// |
| /// Handling effect infer variables happens separately from const infer variables |
| /// because we do not want to reuse any of the const infer machinery. If we try to |
| /// relate an effect variable with a normal one, we would ICE, which can catch bugs |
| /// where we are not correctly using the effect var for an effect param. Fallback |
| /// is also implemented on top of having separate effect and normal const variables. |
| #[encodable] |
| #[orderable] |
| #[debug_format = "?{}e"] |
| #[gate_rustc_only] |
| pub struct EffectVid {} |
| } |
| |
| /// An inference variable for a const, for use in const generics. |
| #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable))] |
| pub enum InferConst { |
| /// Infer the value of the const. |
| Var(ConstVid), |
| /// Infer the value of the effect. |
| /// |
| /// For why this is separate from the `Var` variant above, see the |
| /// documentation on `EffectVid`. |
| EffectVar(EffectVid), |
| /// A fresh const variable. See `infer::freshen` for more details. |
| Fresh(u32), |
| } |
| |
| impl fmt::Debug for InferConst { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| match self { |
| InferConst::Var(var) => write!(f, "{var:?}"), |
| InferConst::EffectVar(var) => write!(f, "{var:?}"), |
| InferConst::Fresh(var) => write!(f, "Fresh({var:?})"), |
| } |
| } |
| } |
| impl<I: Interner> DebugWithInfcx<I> for InferConst { |
| fn fmt<Infcx: InferCtxtLike<Interner = I>>( |
| this: WithInfcx<'_, Infcx, &Self>, |
| f: &mut core::fmt::Formatter<'_>, |
| ) -> core::fmt::Result { |
| match *this.data { |
| InferConst::Var(vid) => match this.infcx.universe_of_ct(vid) { |
| None => write!(f, "{:?}", this.data), |
| Some(universe) => write!(f, "?{}_{}c", vid.index(), universe.index()), |
| }, |
| InferConst::EffectVar(vid) => write!(f, "?{}e", vid.index()), |
| InferConst::Fresh(_) => { |
| unreachable!() |
| } |
| } |
| } |
| } |
| |
| #[cfg(feature = "nightly")] |
| impl<CTX> HashStable<CTX> for InferConst { |
| fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { |
| match self { |
| InferConst::Var(_) | InferConst::EffectVar(_) => { |
| panic!("const variables should not be hashed: {self:?}") |
| } |
| InferConst::Fresh(i) => i.hash_stable(hcx, hasher), |
| } |
| } |
| } |