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, TyDecodable, TyEncodable};
6use rustc_type_ir::walk::TypeWalker;
7use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
8
9use crate::ty::{self, Ty, TyCtxt};
10
11mod int;
12mod kind;
13mod valtree;
14
15pub use int::*;
16pub use kind::*;
17use rustc_span::{DUMMY_SP, ErrorGuaranteed};
18pub use valtree::*;
19
20pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>;
21pub type UnevaluatedConst<'tcx> = ir::UnevaluatedConst<TyCtxt<'tcx>>;
22
23#[cfg(target_pointer_width = "64")]
24rustc_data_structures::static_assert_size!(ConstKind<'_>, 24);
25
26#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)]
27#[rustc_pass_by_value]
28pub struct Const<'tcx>(pub(super) Interned<'tcx, WithCachedTypeInfo<ConstKind<'tcx>>>);
29
30impl<'tcx> rustc_type_ir::inherent::IntoKind for Const<'tcx> {
31    type Kind = ConstKind<'tcx>;
32
33    fn kind(self) -> ConstKind<'tcx> {
34        self.kind()
35    }
36}
37
38impl<'tcx> rustc_type_ir::Flags for Const<'tcx> {
39    fn flags(&self) -> TypeFlags {
40        self.0.flags
41    }
42
43    fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex {
44        self.0.outer_exclusive_binder
45    }
46}
47
48impl<'tcx> Const<'tcx> {
49    #[inline]
50    pub fn kind(self) -> ConstKind<'tcx> {
51        let a: &ConstKind<'tcx> = self.0.0;
52        *a
53    }
54
55    // FIXME(compiler-errors): Think about removing this.
56    #[inline]
57    pub fn flags(self) -> TypeFlags {
58        self.0.flags
59    }
60
61    // FIXME(compiler-errors): Think about removing this.
62    #[inline]
63    pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex {
64        self.0.outer_exclusive_binder
65    }
66
67    #[inline]
68    pub fn new(tcx: TyCtxt<'tcx>, kind: ty::ConstKind<'tcx>) -> Const<'tcx> {
69        tcx.mk_ct_from_kind(kind)
70    }
71
72    #[inline]
73    pub fn new_param(tcx: TyCtxt<'tcx>, param: ty::ParamConst) -> Const<'tcx> {
74        Const::new(tcx, ty::ConstKind::Param(param))
75    }
76
77    #[inline]
78    pub fn new_var(tcx: TyCtxt<'tcx>, infer: ty::ConstVid) -> Const<'tcx> {
79        Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Var(infer)))
80    }
81
82    #[inline]
83    pub fn new_fresh(tcx: TyCtxt<'tcx>, fresh: u32) -> Const<'tcx> {
84        Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Fresh(fresh)))
85    }
86
87    #[inline]
88    pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst) -> Const<'tcx> {
89        Const::new(tcx, ty::ConstKind::Infer(infer))
90    }
91
92    #[inline]
93    pub fn new_bound(
94        tcx: TyCtxt<'tcx>,
95        debruijn: ty::DebruijnIndex,
96        bound_const: ty::BoundConst,
97    ) -> Const<'tcx> {
98        Const::new(tcx, ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_const))
99    }
100
101    #[inline]
102    pub fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: ty::BoundVar) -> Const<'tcx> {
103        Const::new(
104            tcx,
105            ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, ty::BoundConst { var }),
106        )
107    }
108
109    #[inline]
110    pub fn new_placeholder(
111        tcx: TyCtxt<'tcx>,
112        placeholder: ty::PlaceholderConst<'tcx>,
113    ) -> Const<'tcx> {
114        Const::new(tcx, ty::ConstKind::Placeholder(placeholder))
115    }
116
117    #[inline]
118    pub fn new_unevaluated(tcx: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Const<'tcx> {
119        tcx.debug_assert_args_compatible(uv.def, uv.args);
120        Const::new(tcx, ty::ConstKind::Unevaluated(uv))
121    }
122
123    #[inline]
124    pub fn new_value(tcx: TyCtxt<'tcx>, valtree: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
125        Const::new(tcx, ty::ConstKind::Value(ty::Value { ty, valtree }))
126    }
127
128    #[inline]
129    pub fn new_expr(tcx: TyCtxt<'tcx>, expr: ty::Expr<'tcx>) -> Const<'tcx> {
130        Const::new(tcx, ty::ConstKind::Expr(expr))
131    }
132
133    #[inline]
134    pub fn new_error(tcx: TyCtxt<'tcx>, e: ty::ErrorGuaranteed) -> Const<'tcx> {
135        Const::new(tcx, ty::ConstKind::Error(e))
136    }
137
138    /// Like [Ty::new_error] but for constants.
139    #[track_caller]
140    pub fn new_misc_error(tcx: TyCtxt<'tcx>) -> Const<'tcx> {
141        Const::new_error_with_message(
142            tcx,
143            DUMMY_SP,
144            "ty::ConstKind::Error constructed but no error reported",
145        )
146    }
147
148    /// Like [Ty::new_error_with_message] but for constants.
149    #[track_caller]
150    pub fn new_error_with_message<S: Into<MultiSpan>>(
151        tcx: TyCtxt<'tcx>,
152        span: S,
153        msg: impl Into<Cow<'static, str>>,
154    ) -> Const<'tcx> {
155        let reported = tcx.dcx().span_delayed_bug(span, msg);
156        Const::new_error(tcx, reported)
157    }
158
159    pub fn is_trivially_wf(self) -> bool {
160        match self.kind() {
161            ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(_) | ty::ConstKind::Bound(..) => {
162                true
163            }
164            ty::ConstKind::Infer(_)
165            | ty::ConstKind::Unevaluated(..)
166            | ty::ConstKind::Value(_)
167            | ty::ConstKind::Error(_)
168            | ty::ConstKind::Expr(_) => false,
169        }
170    }
171}
172
173impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
174    fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst) -> Self {
175        Const::new_infer(tcx, infer)
176    }
177
178    fn new_var(tcx: TyCtxt<'tcx>, vid: ty::ConstVid) -> Self {
179        Const::new_var(tcx, vid)
180    }
181
182    fn new_bound(
183        interner: TyCtxt<'tcx>,
184        debruijn: ty::DebruijnIndex,
185        bound_const: ty::BoundConst,
186    ) -> Self {
187        Const::new_bound(interner, debruijn, bound_const)
188    }
189
190    fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
191        Const::new_bound(tcx, debruijn, ty::BoundConst { var })
192    }
193
194    fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: rustc_type_ir::BoundVar) -> Self {
195        Const::new_canonical_bound(tcx, var)
196    }
197
198    fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderConst<'tcx>) -> Self {
199        Const::new_placeholder(tcx, placeholder)
200    }
201
202    fn new_unevaluated(interner: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Self {
203        Const::new_unevaluated(interner, uv)
204    }
205
206    fn new_expr(interner: TyCtxt<'tcx>, expr: ty::Expr<'tcx>) -> Self {
207        Const::new_expr(interner, expr)
208    }
209
210    fn new_error(interner: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self {
211        Const::new_error(interner, guar)
212    }
213}
214
215impl<'tcx> Const<'tcx> {
216    /// Creates a constant with the given integer value and interns it.
217    #[inline]
218    pub fn from_bits(
219        tcx: TyCtxt<'tcx>,
220        bits: u128,
221        typing_env: ty::TypingEnv<'tcx>,
222        ty: Ty<'tcx>,
223    ) -> Self {
224        let size = tcx
225            .layout_of(typing_env.as_query_input(ty))
226            .unwrap_or_else(|e| panic!("could not compute layout for {ty:?}: {e:?}"))
227            .size;
228        ty::Const::new_value(
229            tcx,
230            ty::ValTree::from_scalar_int(tcx, ScalarInt::try_from_uint(bits, size).unwrap()),
231            ty,
232        )
233    }
234
235    #[inline]
236    /// Creates an interned zst constant.
237    pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
238        ty::Const::new_value(tcx, ty::ValTree::zst(tcx), ty)
239    }
240
241    #[inline]
242    /// Creates an interned bool constant.
243    pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
244        Self::from_bits(tcx, v as u128, ty::TypingEnv::fully_monomorphized(), tcx.types.bool)
245    }
246
247    #[inline]
248    /// Creates an interned usize constant.
249    pub fn from_target_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
250        Self::from_bits(tcx, n as u128, ty::TypingEnv::fully_monomorphized(), tcx.types.usize)
251    }
252
253    /// Panics if `self.kind != ty::ConstKind::Value`.
254    pub fn to_value(self) -> ty::Value<'tcx> {
255        match self.kind() {
256            ty::ConstKind::Value(cv) => cv,
257            _ => bug!("expected ConstKind::Value, got {:?}", self.kind()),
258        }
259    }
260
261    /// Attempts to convert to a value.
262    ///
263    /// Note that this does not evaluate the constant.
264    pub fn try_to_value(self) -> Option<ty::Value<'tcx>> {
265        match self.kind() {
266            ty::ConstKind::Value(cv) => Some(cv),
267            _ => None,
268        }
269    }
270
271    /// Convenience method to extract the value of a usize constant,
272    /// useful to get the length of an array type.
273    ///
274    /// Note that this does not evaluate the constant.
275    #[inline]
276    pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
277        self.try_to_value()?.try_to_target_usize(tcx)
278    }
279
280    pub fn is_ct_infer(self) -> bool {
281        matches!(self.kind(), ty::ConstKind::Infer(_))
282    }
283
284    /// Iterator that walks `self` and any types reachable from
285    /// `self`, in depth-first order. Note that just walks the types
286    /// that appear in `self`, it does not descend into the fields of
287    /// structs or variants. For example:
288    ///
289    /// ```text
290    /// isize => { isize }
291    /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
292    /// [isize] => { [isize], isize }
293    /// ```
294    pub fn walk(self) -> TypeWalker<TyCtxt<'tcx>> {
295        TypeWalker::new(self.into())
296    }
297}
298
299#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable, HashStable)]
300pub enum AnonConstKind {
301    /// `feature(generic_const_exprs)` anon consts are allowed to use arbitrary generic parameters in scope
302    GCE,
303    /// stable `min_const_generics` anon consts are not allowed to use any generic parameters
304    MCG,
305    /// anon consts used as the length of a repeat expr are syntactically allowed to use generic parameters
306    /// but must not depend on the actual instantiation. See #76200 for more information
307    RepeatExprCount,
308    /// anon consts outside of the type system, e.g. enum discriminants
309    NonTypeSystem,
310}