Skip to main content

rustc_middle/ty/
consts.rs

1use rustc_macros::extension;
2use rustc_span::bug;
3use rustc_type_ir::walk::TypeWalker;
4use rustc_type_ir::{self as ir};
5
6use crate::mir::interpret::Scalar;
7use crate::ty::{self, Ty, TyCtxt};
8
9mod int;
10mod kind;
11mod lit;
12mod valtree;
13
14pub use int::*;
15pub use kind::*;
16pub use lit::*;
17pub use valtree::*;
18
19pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>;
20pub type AliasConst<'tcx> = ir::AliasConst<TyCtxt<'tcx>>;
21pub type AliasConstKind<'tcx> = ir::AliasConstKind<TyCtxt<'tcx>>;
22pub type Const<'tcx> = ir::Const<TyCtxt<'tcx>>;
23
24#[cfg(target_pointer_width = "64")]
25const _: [(); 32] = [(); ::std::mem::size_of::<ConstKind<'_>>()];rustc_data_structures::static_assert_size!(ConstKind<'_>, 32);
26
27pub trait ConstExt<'tcx> {
    #[doc =
    " Creates a constant with the given integer value and interns it."]
    fn from_bits(tcx: TyCtxt<'tcx>, bits: u128,
    typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>)
    -> Self;
    #[doc = " Creates an interned zst constant."]
    fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>)
    -> Self;
    fn new_value(tcx: TyCtxt<'tcx>, valtree: ty::ValTree<'tcx>, ty: Ty<'tcx>)
    -> Const<'tcx>;
    #[doc = " Creates an interned bool constant."]
    fn from_bool(tcx: TyCtxt<'tcx>, v: bool)
    -> Self;
    #[doc = " Creates an interned usize constant."]
    fn from_target_usize(tcx: TyCtxt<'tcx>, n: u64)
    -> Self;
    #[doc = " Panics if `self.kind != ty::ConstKind::Value`."]
    fn to_value(self)
    -> ty::Value<'tcx>;
    #[doc = " Attempts to convert to a value."]
    #[doc = ""]
    #[doc = " Note that this does not normalize the constant."]
    fn try_to_value(self)
    -> Option<ty::Value<'tcx>>;
    #[doc = " Converts to a `ValTreeKind::Leaf` value, `panic`\'ing"]
    #[doc = " if this constant is some other kind."]
    #[doc = ""]
    #[doc = " Note that this does not normalize the constant."]
    fn to_leaf(self)
    -> ScalarInt;
    #[doc = " Converts to a `ValTreeKind::Branch` value, `panic`\'ing"]
    #[doc = " if this constant is some other kind."]
    #[doc = ""]
    #[doc = " Note that this does not normalize the constant."]
    fn to_branch(self)
    -> &'tcx [ty::Const<'tcx>];
    #[doc = " Attempts to convert to a `ValTreeKind::Leaf` value."]
    #[doc = ""]
    #[doc = " Note that this does not normalize the constant."]
    fn try_to_leaf(self)
    -> Option<ScalarInt>;
    #[doc = " Attempts to convert to a `ValTreeKind::Leaf` value."]
    #[doc = ""]
    #[doc = " Note that this does not normalize the constant."]
    fn try_to_scalar(self)
    -> Option<Scalar>;
    #[doc = " Attempts to convert to a `ValTreeKind::Branch` value."]
    #[doc = ""]
    #[doc = " Note that this does not normalize the constant."]
    fn try_to_branch(self)
    -> Option<&'tcx [ty::Const<'tcx>]>;
    #[doc = " Convenience method to extract the value of a usize constant,"]
    #[doc = " useful to get the length of an array type."]
    #[doc = ""]
    #[doc = " Note that this does not evaluate the constant."]
    fn try_to_target_usize(self, tcx: TyCtxt<'tcx>)
    -> Option<u64>;
    #[doc = " Iterator that walks `self` and any types reachable from"]
    #[doc = " `self`, in depth-first order. Note that just walks the types"]
    #[doc = " that appear in `self`, it does not descend into the fields of"]
    #[doc = " structs or variants. For example:"]
    #[doc = ""]
    #[doc = " ```text"]
    #[doc = " isize => { isize }"]
    #[doc = " Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }"]
    #[doc = " [isize] => { [isize], isize }"]
    #[doc = " ```"]
    fn walk(self)
    -> TypeWalker<TyCtxt<'tcx>>;
}
impl<'tcx> ConstExt<'tcx> for Const<'tcx> {
    #[doc =
    " Creates a constant with the given integer value and interns it."]
    #[inline]
    fn from_bits(tcx: TyCtxt<'tcx>, bits: u128,
        typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>) -> Self {
        let size =
            tcx.layout_of(typing_env.as_query_input(ty)).unwrap_or_else(|e|
                        {
                            ::core::panicking::panic_fmt(format_args!("could not compute layout for {0:?}: {1:?}",
                                    ty, e));
                        }).size;
        let valtree =
            ty::ValTree::from_scalar_int(tcx,
                ScalarInt::try_from_uint(bits, size).unwrap());
        ty::Const::new_value(tcx, valtree, ty)
    }
    #[inline]
    #[doc = " Creates an interned zst constant."]
    fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
        ty::Const::new_value(tcx, ty::ValTree::zst(tcx), ty)
    }
    #[inline]
    fn new_value(tcx: TyCtxt<'tcx>, valtree: ty::ValTree<'tcx>, ty: Ty<'tcx>)
        -> Const<'tcx> {
        Const::new(tcx, ty::ConstKind::Value(ty::Value { ty, valtree }))
    }
    #[inline]
    #[doc = " Creates an interned bool constant."]
    fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
        Self::from_bits(tcx, v as u128, ty::TypingEnv::fully_monomorphized(),
            tcx.types.bool)
    }
    #[inline]
    #[doc = " Creates an interned usize constant."]
    fn from_target_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
        Self::from_bits(tcx, n as u128, ty::TypingEnv::fully_monomorphized(),
            tcx.types.usize)
    }
    #[doc = " Panics if `self.kind != ty::ConstKind::Value`."]
    fn to_value(self) -> ty::Value<'tcx> {
        match self.kind() {
            ty::ConstKind::Value(cv) => cv,
            _ =>
                ::rustc_span::macros::bug_impl(None,
                    format_args!("expected ConstKind::Value, got {0:?}",
                        self.kind()), Location::caller()),
        }
    }
    #[doc = " Attempts to convert to a value."]
    #[doc = ""]
    #[doc = " Note that this does not normalize the constant."]
    fn try_to_value(self) -> Option<ty::Value<'tcx>> {
        match self.kind() { ty::ConstKind::Value(cv) => Some(cv), _ => None, }
    }
    #[doc = " Converts to a `ValTreeKind::Leaf` value, `panic`\'ing"]
    #[doc = " if this constant is some other kind."]
    #[doc = ""]
    #[doc = " Note that this does not normalize the constant."]
    #[inline]
    fn to_leaf(self) -> ScalarInt { self.to_value().to_leaf() }
    #[doc = " Converts to a `ValTreeKind::Branch` value, `panic`\'ing"]
    #[doc = " if this constant is some other kind."]
    #[doc = ""]
    #[doc = " Note that this does not normalize the constant."]
    #[inline]
    fn to_branch(self) -> &'tcx [ty::Const<'tcx>] {
        self.to_value().to_branch()
    }
    #[doc = " Attempts to convert to a `ValTreeKind::Leaf` value."]
    #[doc = ""]
    #[doc = " Note that this does not normalize the constant."]
    fn try_to_leaf(self) -> Option<ScalarInt> {
        self.try_to_value()?.try_to_leaf()
    }
    #[doc = " Attempts to convert to a `ValTreeKind::Leaf` value."]
    #[doc = ""]
    #[doc = " Note that this does not normalize the constant."]
    fn try_to_scalar(self) -> Option<Scalar> {
        self.try_to_leaf().map(Scalar::Int)
    }
    #[doc = " Attempts to convert to a `ValTreeKind::Branch` value."]
    #[doc = ""]
    #[doc = " Note that this does not normalize the constant."]
    fn try_to_branch(self) -> Option<&'tcx [ty::Const<'tcx>]> {
        self.try_to_value()?.try_to_branch()
    }
    #[doc = " Convenience method to extract the value of a usize constant,"]
    #[doc = " useful to get the length of an array type."]
    #[doc = ""]
    #[doc = " Note that this does not evaluate the constant."]
    #[inline]
    fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
        self.try_to_value()?.try_to_target_usize(tcx)
    }
    #[doc = " Iterator that walks `self` and any types reachable from"]
    #[doc = " `self`, in depth-first order. Note that just walks the types"]
    #[doc = " that appear in `self`, it does not descend into the fields of"]
    #[doc = " structs or variants. For example:"]
    #[doc = ""]
    #[doc = " ```text"]
    #[doc = " isize => { isize }"]
    #[doc = " Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }"]
    #[doc = " [isize] => { [isize], isize }"]
    #[doc = " ```"]
    fn walk(self) -> TypeWalker<TyCtxt<'tcx>> { TypeWalker::new(self.into()) }
}#[extension(pub trait ConstExt<'tcx>)]
28impl<'tcx> Const<'tcx> {
29    /// Creates a constant with the given integer value and interns it.
30    #[inline]
31    fn from_bits(
32        tcx: TyCtxt<'tcx>,
33        bits: u128,
34        typing_env: ty::TypingEnv<'tcx>,
35        ty: Ty<'tcx>,
36    ) -> Self {
37        let size = tcx
38            .layout_of(typing_env.as_query_input(ty))
39            .unwrap_or_else(|e| panic!("could not compute layout for {ty:?}: {e:?}"))
40            .size;
41        let valtree =
42            ty::ValTree::from_scalar_int(tcx, ScalarInt::try_from_uint(bits, size).unwrap());
43        ty::Const::new_value(tcx, valtree, ty)
44    }
45
46    #[inline]
47    /// Creates an interned zst constant.
48    fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
49        ty::Const::new_value(tcx, ty::ValTree::zst(tcx), ty)
50    }
51
52    #[inline]
53    fn new_value(tcx: TyCtxt<'tcx>, valtree: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
54        Const::new(tcx, ty::ConstKind::Value(ty::Value { ty, valtree }))
55    }
56
57    #[inline]
58    /// Creates an interned bool constant.
59    fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
60        Self::from_bits(tcx, v as u128, ty::TypingEnv::fully_monomorphized(), tcx.types.bool)
61    }
62
63    #[inline]
64    /// Creates an interned usize constant.
65    fn from_target_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
66        Self::from_bits(tcx, n as u128, ty::TypingEnv::fully_monomorphized(), tcx.types.usize)
67    }
68
69    /// Panics if `self.kind != ty::ConstKind::Value`.
70    fn to_value(self) -> ty::Value<'tcx> {
71        match self.kind() {
72            ty::ConstKind::Value(cv) => cv,
73            _ => bug!("expected ConstKind::Value, got {:?}", self.kind()),
74        }
75    }
76
77    /// Attempts to convert to a value.
78    ///
79    /// Note that this does not normalize the constant.
80    fn try_to_value(self) -> Option<ty::Value<'tcx>> {
81        match self.kind() {
82            ty::ConstKind::Value(cv) => Some(cv),
83            _ => None,
84        }
85    }
86
87    /// Converts to a `ValTreeKind::Leaf` value, `panic`'ing
88    /// if this constant is some other kind.
89    ///
90    /// Note that this does not normalize the constant.
91    #[inline]
92    fn to_leaf(self) -> ScalarInt {
93        self.to_value().to_leaf()
94    }
95
96    /// Converts to a `ValTreeKind::Branch` value, `panic`'ing
97    /// if this constant is some other kind.
98    ///
99    /// Note that this does not normalize the constant.
100    #[inline]
101    fn to_branch(self) -> &'tcx [ty::Const<'tcx>] {
102        self.to_value().to_branch()
103    }
104
105    /// Attempts to convert to a `ValTreeKind::Leaf` value.
106    ///
107    /// Note that this does not normalize the constant.
108    fn try_to_leaf(self) -> Option<ScalarInt> {
109        self.try_to_value()?.try_to_leaf()
110    }
111
112    /// Attempts to convert to a `ValTreeKind::Leaf` value.
113    ///
114    /// Note that this does not normalize the constant.
115    fn try_to_scalar(self) -> Option<Scalar> {
116        self.try_to_leaf().map(Scalar::Int)
117    }
118
119    /// Attempts to convert to a `ValTreeKind::Branch` value.
120    ///
121    /// Note that this does not normalize the constant.
122    fn try_to_branch(self) -> Option<&'tcx [ty::Const<'tcx>]> {
123        self.try_to_value()?.try_to_branch()
124    }
125
126    /// Convenience method to extract the value of a usize constant,
127    /// useful to get the length of an array type.
128    ///
129    /// Note that this does not evaluate the constant.
130    #[inline]
131    fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
132        self.try_to_value()?.try_to_target_usize(tcx)
133    }
134
135    /// Iterator that walks `self` and any types reachable from
136    /// `self`, in depth-first order. Note that just walks the types
137    /// that appear in `self`, it does not descend into the fields of
138    /// structs or variants. For example:
139    ///
140    /// ```text
141    /// isize => { isize }
142    /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
143    /// [isize] => { [isize], isize }
144    /// ```
145    fn walk(self) -> TypeWalker<TyCtxt<'tcx>> {
146        TypeWalker::new(self.into())
147    }
148}