rustc_middle/ty/
consts.rs

1use std::borrow::Cow;
2
3use rustc_data_structures::intern::Interned;
4use rustc_error_messages::MultiSpan;
5use rustc_macros::HashStable;
6use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
7
8use crate::ty::{self, Ty, TyCtxt};
9
10mod int;
11mod kind;
12mod valtree;
13
14pub use int::*;
15pub use kind::*;
16use rustc_span::{DUMMY_SP, ErrorGuaranteed};
17pub use valtree::*;
18
19pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>;
20pub type UnevaluatedConst<'tcx> = ir::UnevaluatedConst<TyCtxt<'tcx>>;
21
22#[cfg(target_pointer_width = "64")]
23rustc_data_structures::static_assert_size!(ConstKind<'_>, 24);
24
25#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)]
26#[rustc_pass_by_value]
27pub struct Const<'tcx>(pub(super) Interned<'tcx, WithCachedTypeInfo<ConstKind<'tcx>>>);
28
29impl<'tcx> rustc_type_ir::inherent::IntoKind for Const<'tcx> {
30    type Kind = ConstKind<'tcx>;
31
32    fn kind(self) -> ConstKind<'tcx> {
33        self.kind()
34    }
35}
36
37impl<'tcx> rustc_type_ir::Flags for Const<'tcx> {
38    fn flags(&self) -> TypeFlags {
39        self.0.flags
40    }
41
42    fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex {
43        self.0.outer_exclusive_binder
44    }
45}
46
47impl<'tcx> Const<'tcx> {
48    #[inline]
49    pub fn kind(self) -> ConstKind<'tcx> {
50        let a: &ConstKind<'tcx> = self.0.0;
51        *a
52    }
53
54    // FIXME(compiler-errors): Think about removing this.
55    #[inline]
56    pub fn flags(self) -> TypeFlags {
57        self.0.flags
58    }
59
60    // FIXME(compiler-errors): Think about removing this.
61    #[inline]
62    pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex {
63        self.0.outer_exclusive_binder
64    }
65
66    #[inline]
67    pub fn new(tcx: TyCtxt<'tcx>, kind: ty::ConstKind<'tcx>) -> Const<'tcx> {
68        tcx.mk_ct_from_kind(kind)
69    }
70
71    #[inline]
72    pub fn new_param(tcx: TyCtxt<'tcx>, param: ty::ParamConst) -> Const<'tcx> {
73        Const::new(tcx, ty::ConstKind::Param(param))
74    }
75
76    #[inline]
77    pub fn new_var(tcx: TyCtxt<'tcx>, infer: ty::ConstVid) -> Const<'tcx> {
78        Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Var(infer)))
79    }
80
81    #[inline]
82    pub fn new_fresh(tcx: TyCtxt<'tcx>, fresh: u32) -> Const<'tcx> {
83        Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Fresh(fresh)))
84    }
85
86    #[inline]
87    pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst) -> Const<'tcx> {
88        Const::new(tcx, ty::ConstKind::Infer(infer))
89    }
90
91    #[inline]
92    pub fn new_bound(
93        tcx: TyCtxt<'tcx>,
94        debruijn: ty::DebruijnIndex,
95        var: ty::BoundVar,
96    ) -> Const<'tcx> {
97        Const::new(tcx, ty::ConstKind::Bound(debruijn, var))
98    }
99
100    #[inline]
101    pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderConst) -> Const<'tcx> {
102        Const::new(tcx, ty::ConstKind::Placeholder(placeholder))
103    }
104
105    #[inline]
106    pub fn new_unevaluated(tcx: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Const<'tcx> {
107        tcx.debug_assert_args_compatible(uv.def, uv.args);
108        Const::new(tcx, ty::ConstKind::Unevaluated(uv))
109    }
110
111    #[inline]
112    pub fn new_value(tcx: TyCtxt<'tcx>, valtree: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
113        Const::new(tcx, ty::ConstKind::Value(ty::Value { ty, valtree }))
114    }
115
116    #[inline]
117    pub fn new_expr(tcx: TyCtxt<'tcx>, expr: ty::Expr<'tcx>) -> Const<'tcx> {
118        Const::new(tcx, ty::ConstKind::Expr(expr))
119    }
120
121    #[inline]
122    pub fn new_error(tcx: TyCtxt<'tcx>, e: ty::ErrorGuaranteed) -> Const<'tcx> {
123        Const::new(tcx, ty::ConstKind::Error(e))
124    }
125
126    /// Like [Ty::new_error] but for constants.
127    #[track_caller]
128    pub fn new_misc_error(tcx: TyCtxt<'tcx>) -> Const<'tcx> {
129        Const::new_error_with_message(
130            tcx,
131            DUMMY_SP,
132            "ty::ConstKind::Error constructed but no error reported",
133        )
134    }
135
136    /// Like [Ty::new_error_with_message] but for constants.
137    #[track_caller]
138    pub fn new_error_with_message<S: Into<MultiSpan>>(
139        tcx: TyCtxt<'tcx>,
140        span: S,
141        msg: impl Into<Cow<'static, str>>,
142    ) -> Const<'tcx> {
143        let reported = tcx.dcx().span_delayed_bug(span, msg);
144        Const::new_error(tcx, reported)
145    }
146}
147
148impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
149    fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst) -> Self {
150        Const::new_infer(tcx, infer)
151    }
152
153    fn new_var(tcx: TyCtxt<'tcx>, vid: ty::ConstVid) -> Self {
154        Const::new_var(tcx, vid)
155    }
156
157    fn new_bound(interner: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
158        Const::new_bound(interner, debruijn, var)
159    }
160
161    fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
162        Const::new_bound(tcx, debruijn, var)
163    }
164
165    fn new_unevaluated(interner: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Self {
166        Const::new_unevaluated(interner, uv)
167    }
168
169    fn new_expr(interner: TyCtxt<'tcx>, expr: ty::Expr<'tcx>) -> Self {
170        Const::new_expr(interner, expr)
171    }
172
173    fn new_error(interner: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self {
174        Const::new_error(interner, guar)
175    }
176}
177
178impl<'tcx> Const<'tcx> {
179    /// Creates a constant with the given integer value and interns it.
180    #[inline]
181    pub fn from_bits(
182        tcx: TyCtxt<'tcx>,
183        bits: u128,
184        typing_env: ty::TypingEnv<'tcx>,
185        ty: Ty<'tcx>,
186    ) -> Self {
187        let size = tcx
188            .layout_of(typing_env.as_query_input(ty))
189            .unwrap_or_else(|e| panic!("could not compute layout for {ty:?}: {e:?}"))
190            .size;
191        ty::Const::new_value(
192            tcx,
193            ty::ValTree::from_scalar_int(tcx, ScalarInt::try_from_uint(bits, size).unwrap()),
194            ty,
195        )
196    }
197
198    #[inline]
199    /// Creates an interned zst constant.
200    pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
201        ty::Const::new_value(tcx, ty::ValTree::zst(tcx), ty)
202    }
203
204    #[inline]
205    /// Creates an interned bool constant.
206    pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
207        Self::from_bits(tcx, v as u128, ty::TypingEnv::fully_monomorphized(), tcx.types.bool)
208    }
209
210    #[inline]
211    /// Creates an interned usize constant.
212    pub fn from_target_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
213        Self::from_bits(tcx, n as u128, ty::TypingEnv::fully_monomorphized(), tcx.types.usize)
214    }
215
216    /// Panics if `self.kind != ty::ConstKind::Value`.
217    pub fn to_value(self) -> ty::Value<'tcx> {
218        match self.kind() {
219            ty::ConstKind::Value(cv) => cv,
220            _ => bug!("expected ConstKind::Value, got {:?}", self.kind()),
221        }
222    }
223
224    /// Attempts to convert to a value.
225    ///
226    /// Note that this does not evaluate the constant.
227    pub fn try_to_value(self) -> Option<ty::Value<'tcx>> {
228        match self.kind() {
229            ty::ConstKind::Value(cv) => Some(cv),
230            _ => None,
231        }
232    }
233
234    /// Convenience method to extract the value of a usize constant,
235    /// useful to get the length of an array type.
236    ///
237    /// Note that this does not evaluate the constant.
238    #[inline]
239    pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
240        self.try_to_value()?.try_to_target_usize(tcx)
241    }
242
243    pub fn is_ct_infer(self) -> bool {
244        matches!(self.kind(), ty::ConstKind::Infer(_))
245    }
246}