Skip to main content

rustc_middle/ty/
consts.rs

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