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