rustc_middle/ty/consts/
valtree.rs
1use 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::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
127#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
131#[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable, Lift)]
132pub struct Value<'tcx> {
133 pub ty: Ty<'tcx>,
134 pub valtree: ValTree<'tcx>,
135}
136
137impl<'tcx> Value<'tcx> {
138 #[inline]
143 pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option<u128> {
144 let (ty::Bool | ty::Char | ty::Uint(_) | ty::Int(_) | ty::Float(_)) = self.ty.kind() else {
145 return None;
146 };
147 let scalar = self.valtree.try_to_scalar_int()?;
148 let input = typing_env.with_post_analysis_normalized(tcx).as_query_input(self.ty);
149 let size = tcx.layout_of(input).ok()?.size;
150 Some(scalar.to_bits(size))
151 }
152
153 pub fn try_to_bool(self) -> Option<bool> {
154 if !self.ty.is_bool() {
155 return None;
156 }
157 self.valtree.try_to_scalar_int()?.try_to_bool().ok()
158 }
159
160 pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
161 if !self.ty.is_usize() {
162 return None;
163 }
164 self.valtree.try_to_scalar_int().map(|s| s.to_target_usize(tcx))
165 }
166
167 pub fn try_to_raw_bytes(self, tcx: TyCtxt<'tcx>) -> Option<&'tcx [u8]> {
170 match self.ty.kind() {
171 ty::Ref(_, inner_ty, _) => match inner_ty.kind() {
172 ty::Str => {}
174 ty::Slice(slice_ty) if *slice_ty == tcx.types.u8 => {}
176 _ => return None,
178 },
179 ty::Array(array_ty, _) if *array_ty == tcx.types.u8 => {}
181 _ => return None,
183 }
184
185 Some(tcx.arena.alloc_from_iter(
186 self.valtree.unwrap_branch().into_iter().map(|v| v.unwrap_leaf().to_u8()),
187 ))
188 }
189}
190
191impl<'tcx> rustc_type_ir::inherent::ValueConst<TyCtxt<'tcx>> for Value<'tcx> {
192 fn ty(self) -> Ty<'tcx> {
193 self.ty
194 }
195
196 fn valtree(self) -> ValTree<'tcx> {
197 self.valtree
198 }
199}