rustc_type_ir/
const_kind.rs

1use std::fmt;
2
3use derive_where::derive_where;
4#[cfg(feature = "nightly")]
5use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
6#[cfg(feature = "nightly")]
7use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
8use rustc_type_ir_macros::{
9    GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic,
10};
11
12use crate::{self as ty, BoundVarIndexKind, Interner};
13
14/// Represents a constant in Rust.
15#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
16#[derive(GenericTypeVisitable)]
17#[cfg_attr(
18    feature = "nightly",
19    derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
20)]
21pub enum ConstKind<I: Interner> {
22    /// A const generic parameter.
23    Param(I::ParamConst),
24
25    /// Infer the value of the const.
26    Infer(InferConst),
27
28    /// Bound const variable, used only when preparing a trait query.
29    Bound(BoundVarIndexKind, I::BoundConst),
30
31    /// A placeholder const - universally quantified higher-ranked const.
32    Placeholder(I::PlaceholderConst),
33
34    /// An unnormalized const item such as an anon const or assoc const or free const item.
35    /// Right now anything other than anon consts does not actually work properly but this
36    /// should
37    Unevaluated(ty::UnevaluatedConst<I>),
38
39    /// Used to hold computed value.
40    Value(I::ValueConst),
41
42    /// A placeholder for a const which could not be computed; this is
43    /// propagated to avoid useless error messages.
44    Error(I::ErrorGuaranteed),
45
46    /// Unevaluated non-const-item, used by `feature(generic_const_exprs)` to represent
47    /// const arguments such as `N + 1` or `foo(N)`
48    Expr(I::ExprConst),
49}
50
51impl<I: Interner> Eq for ConstKind<I> {}
52
53impl<I: Interner> fmt::Debug for ConstKind<I> {
54    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55        use ConstKind::*;
56
57        match self {
58            Param(param) => write!(f, "{param:?}"),
59            Infer(var) => write!(f, "{var:?}"),
60            Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var),
61            Placeholder(placeholder) => write!(f, "{placeholder:?}"),
62            Unevaluated(uv) => write!(f, "{uv:?}"),
63            Value(val) => write!(f, "{val:?}"),
64            Error(_) => write!(f, "{{const error}}"),
65            Expr(expr) => write!(f, "{expr:?}"),
66        }
67    }
68}
69
70/// An unevaluated (potentially generic) constant used in the type-system.
71#[derive_where(Clone, Copy, Debug, Hash, PartialEq; I: Interner)]
72#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
73#[cfg_attr(
74    feature = "nightly",
75    derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
76)]
77pub struct UnevaluatedConst<I: Interner> {
78    pub def: I::UnevaluatedConstId,
79    pub args: I::GenericArgs,
80}
81
82impl<I: Interner> Eq for UnevaluatedConst<I> {}
83
84impl<I: Interner> UnevaluatedConst<I> {
85    #[inline]
86    pub fn new(def: I::UnevaluatedConstId, args: I::GenericArgs) -> UnevaluatedConst<I> {
87        UnevaluatedConst { def, args }
88    }
89}
90
91rustc_index::newtype_index! {
92    /// A **`const`** **v**ariable **ID**.
93    #[encodable]
94    #[orderable]
95    #[debug_format = "?{}c"]
96    #[gate_rustc_only]
97    pub struct ConstVid {}
98}
99
100/// An inference variable for a const, for use in const generics.
101#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
102#[cfg_attr(feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext))]
103pub enum InferConst {
104    /// Infer the value of the const.
105    Var(ConstVid),
106    /// A fresh const variable. See `infer::freshen` for more details.
107    Fresh(u32),
108}
109
110impl fmt::Debug for InferConst {
111    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112        match self {
113            InferConst::Var(var) => write!(f, "{var:?}"),
114            InferConst::Fresh(var) => write!(f, "Fresh({var:?})"),
115        }
116    }
117}
118
119#[cfg(feature = "nightly")]
120impl<CTX> HashStable<CTX> for InferConst {
121    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
122        match self {
123            InferConst::Var(_) => {
124                panic!("const variables should not be hashed: {self:?}")
125            }
126            InferConst::Fresh(i) => i.hash_stable(hcx, hasher),
127        }
128    }
129}
130
131/// This datastructure is used to represent the value of constants used in the type system.
132///
133/// We explicitly choose a different datastructure from the way values are processed within
134/// CTFE, as in the type system equal values (according to their `PartialEq`) must also have
135/// equal representation (`==` on the rustc data structure, e.g. `ValTree`) and vice versa.
136/// Since CTFE uses `AllocId` to represent pointers, it often happens that two different
137/// `AllocId`s point to equal values. So we may end up with different representations for
138/// two constants whose value is `&42`. Furthermore any kind of struct that has padding will
139/// have arbitrary values within that padding, even if the values of the struct are the same.
140///
141/// `ValTree` does not have this problem with representation, as it only contains integers or
142/// lists of (nested) `ty::Const`s (which may indirectly contain more `ValTree`s).
143#[derive_where(Clone, Debug, Hash, Eq, PartialEq; I: Interner)]
144#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
145#[cfg_attr(
146    feature = "nightly",
147    derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
148)]
149pub enum ValTreeKind<I: Interner> {
150    /// integers, `bool`, `char` are represented as scalars.
151    /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values
152    /// of these types have the same representation.
153    Leaf(I::ScalarInt),
154
155    /// The fields of any kind of aggregate. Structs, tuples and arrays are represented by
156    /// listing their fields' values in order.
157    ///
158    /// Enums are represented by storing their variant index as a u32 field, followed by all
159    /// the fields of the variant.
160    ///
161    /// ZST types are represented as an empty slice.
162    // FIXME(mgca): Use a `List` here instead of a boxed slice
163    Branch(Box<[I::Const]>),
164}
165
166impl<I: Interner> ValTreeKind<I> {
167    /// Converts to a `ValTreeKind::Leaf` value, `panic`'ing
168    /// if this valtree is some other kind.
169    #[inline]
170    pub fn to_leaf(&self) -> I::ScalarInt {
171        match self {
172            ValTreeKind::Leaf(s) => *s,
173            ValTreeKind::Branch(..) => panic!("expected leaf, got {:?}", self),
174        }
175    }
176
177    /// Converts to a `ValTreeKind::Branch` value, `panic`'ing
178    /// if this valtree is some other kind.
179    #[inline]
180    pub fn to_branch(&self) -> &[I::Const] {
181        match self {
182            ValTreeKind::Branch(branch) => &**branch,
183            ValTreeKind::Leaf(..) => panic!("expected branch, got {:?}", self),
184        }
185    }
186
187    /// Attempts to convert to a `ValTreeKind::Leaf` value.
188    pub fn try_to_leaf(&self) -> Option<I::ScalarInt> {
189        match self {
190            ValTreeKind::Leaf(s) => Some(*s),
191            ValTreeKind::Branch(_) => None,
192        }
193    }
194
195    /// Attempts to convert to a `ValTreeKind::Branch` value.
196    pub fn try_to_branch(&self) -> Option<&[I::Const]> {
197        match self {
198            ValTreeKind::Branch(branch) => Some(&**branch),
199            ValTreeKind::Leaf(_) => None,
200        }
201    }
202}