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