rustc_middle/ty/consts/
valtree.rs1use std::fmt;
2use std::ops::Deref;
3
4use rustc_data_structures::intern::Interned;
5use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
6
7use super::ScalarInt;
8use crate::mir::interpret::{ErrorHandled, Scalar};
9use crate::ty::{self, Ty, TyCtxt};
10
11#[derive(Clone, Debug, Hash, Eq, PartialEq)]
24#[derive(HashStable, TyEncodable, TyDecodable)]
25pub enum ValTreeKind<'tcx> {
26 Leaf(ScalarInt),
30
31 Branch(Box<[ValTree<'tcx>]>),
41}
42
43impl<'tcx> ValTreeKind<'tcx> {
44 #[inline]
45 pub fn unwrap_leaf(&self) -> ScalarInt {
46 match self {
47 Self::Leaf(s) => *s,
48 _ => bug!("expected leaf, got {:?}", self),
49 }
50 }
51
52 #[inline]
53 pub fn unwrap_branch(&self) -> &[ValTree<'tcx>] {
54 match self {
55 Self::Branch(branch) => &**branch,
56 _ => bug!("expected branch, got {:?}", self),
57 }
58 }
59
60 pub fn try_to_scalar(&self) -> Option<Scalar> {
61 self.try_to_scalar_int().map(Scalar::Int)
62 }
63
64 pub fn try_to_scalar_int(&self) -> Option<ScalarInt> {
65 match self {
66 Self::Leaf(s) => Some(*s),
67 Self::Branch(_) => None,
68 }
69 }
70
71 pub fn try_to_branch(&self) -> Option<&[ValTree<'tcx>]> {
72 match self {
73 Self::Branch(branch) => Some(&**branch),
74 Self::Leaf(_) => None,
75 }
76 }
77}
78
79#[derive(Copy, Clone, Hash, Eq, PartialEq)]
85#[derive(HashStable)]
86pub struct ValTree<'tcx>(pub(crate) Interned<'tcx, ValTreeKind<'tcx>>);
87
88impl<'tcx> ValTree<'tcx> {
89 pub fn zst(tcx: TyCtxt<'tcx>) -> Self {
91 tcx.consts.valtree_zst
92 }
93
94 pub fn is_zst(self) -> bool {
95 matches!(*self, ValTreeKind::Branch(box []))
96 }
97
98 pub fn from_raw_bytes(tcx: TyCtxt<'tcx>, bytes: &[u8]) -> Self {
99 let branches = bytes.iter().map(|&b| Self::from_scalar_int(tcx, b.into()));
100 Self::from_branches(tcx, branches)
101 }
102
103 pub fn from_branches(tcx: TyCtxt<'tcx>, branches: impl IntoIterator<Item = Self>) -> Self {
104 tcx.intern_valtree(ValTreeKind::Branch(branches.into_iter().collect()))
105 }
106
107 pub fn from_scalar_int(tcx: TyCtxt<'tcx>, i: ScalarInt) -> Self {
108 tcx.intern_valtree(ValTreeKind::Leaf(i))
109 }
110}
111
112impl<'tcx> Deref for ValTree<'tcx> {
113 type Target = &'tcx ValTreeKind<'tcx>;
114
115 #[inline]
116 fn deref(&self) -> &&'tcx ValTreeKind<'tcx> {
117 &self.0.0
118 }
119}
120
121impl fmt::Debug for ValTree<'_> {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 (**self).fmt(f)
124 }
125}
126
127pub type ConstToValTreeResult<'tcx> = Result<Result<ValTree<'tcx>, Ty<'tcx>>, ErrorHandled>;
132
133#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
137#[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable, Lift)]
138pub struct Value<'tcx> {
139 pub ty: Ty<'tcx>,
140 pub valtree: ValTree<'tcx>,
141}
142
143impl<'tcx> Value<'tcx> {
144 #[inline]
149 pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option<u128> {
150 let (ty::Bool | ty::Char | ty::Uint(_) | ty::Int(_) | ty::Float(_)) = self.ty.kind() else {
151 return None;
152 };
153 let scalar = self.valtree.try_to_scalar_int()?;
154 let input = typing_env.with_post_analysis_normalized(tcx).as_query_input(self.ty);
155 let size = tcx.layout_of(input).ok()?.size;
156 Some(scalar.to_bits(size))
157 }
158
159 pub fn try_to_bool(self) -> Option<bool> {
160 if !self.ty.is_bool() {
161 return None;
162 }
163 self.valtree.try_to_scalar_int()?.try_to_bool().ok()
164 }
165
166 pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
167 if !self.ty.is_usize() {
168 return None;
169 }
170 self.valtree.try_to_scalar_int().map(|s| s.to_target_usize(tcx))
171 }
172
173 pub fn try_to_raw_bytes(self, tcx: TyCtxt<'tcx>) -> Option<&'tcx [u8]> {
176 match self.ty.kind() {
177 ty::Ref(_, inner_ty, _) => match inner_ty.kind() {
178 ty::Str => {}
180 ty::Slice(slice_ty) if *slice_ty == tcx.types.u8 => {}
182 _ => return None,
184 },
185 ty::Array(array_ty, _) if *array_ty == tcx.types.u8 => {}
187 _ => return None,
189 }
190
191 Some(tcx.arena.alloc_from_iter(
192 self.valtree.unwrap_branch().into_iter().map(|v| v.unwrap_leaf().to_u8()),
193 ))
194 }
195}
196
197impl<'tcx> rustc_type_ir::inherent::ValueConst<TyCtxt<'tcx>> for Value<'tcx> {
198 fn ty(self) -> Ty<'tcx> {
199 self.ty
200 }
201
202 fn valtree(self) -> ValTree<'tcx> {
203 self.valtree
204 }
205}