rustc_middle/ty/consts/
valtree.rs1use std::fmt;
2use std::ops::Deref;
3
4use rustc_data_structures::intern::Interned;
5use rustc_hir::def::Namespace;
6use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
7
8use super::ScalarInt;
9use crate::mir::interpret::{ErrorHandled, Scalar};
10use crate::ty::print::{FmtPrinter, PrettyPrinter};
11use crate::ty::{self, Ty, TyCtxt};
12
13#[derive(Clone, Debug, Hash, Eq, PartialEq)]
26#[derive(HashStable, TyEncodable, TyDecodable)]
27pub enum ValTreeKind<'tcx> {
28 Leaf(ScalarInt),
32
33 Branch(Box<[ValTree<'tcx>]>),
43}
44
45impl<'tcx> ValTreeKind<'tcx> {
46 #[inline]
47 pub fn unwrap_leaf(&self) -> ScalarInt {
48 match self {
49 Self::Leaf(s) => *s,
50 _ => bug!("expected leaf, got {:?}", self),
51 }
52 }
53
54 #[inline]
55 pub fn unwrap_branch(&self) -> &[ValTree<'tcx>] {
56 match self {
57 Self::Branch(branch) => &**branch,
58 _ => bug!("expected branch, got {:?}", self),
59 }
60 }
61
62 pub fn try_to_scalar(&self) -> Option<Scalar> {
63 self.try_to_scalar_int().map(Scalar::Int)
64 }
65
66 pub fn try_to_scalar_int(&self) -> Option<ScalarInt> {
67 match self {
68 Self::Leaf(s) => Some(*s),
69 Self::Branch(_) => None,
70 }
71 }
72
73 pub fn try_to_branch(&self) -> Option<&[ValTree<'tcx>]> {
74 match self {
75 Self::Branch(branch) => Some(&**branch),
76 Self::Leaf(_) => None,
77 }
78 }
79}
80
81#[derive(Copy, Clone, Hash, Eq, PartialEq)]
87#[derive(HashStable)]
88pub struct ValTree<'tcx>(pub(crate) Interned<'tcx, ValTreeKind<'tcx>>);
89
90impl<'tcx> ValTree<'tcx> {
91 pub fn zst(tcx: TyCtxt<'tcx>) -> Self {
93 tcx.consts.valtree_zst
94 }
95
96 pub fn is_zst(self) -> bool {
97 matches!(*self, ValTreeKind::Branch(box []))
98 }
99
100 pub fn from_raw_bytes(tcx: TyCtxt<'tcx>, bytes: &[u8]) -> Self {
101 let branches = bytes.iter().map(|&b| Self::from_scalar_int(tcx, b.into()));
102 Self::from_branches(tcx, branches)
103 }
104
105 pub fn from_branches(tcx: TyCtxt<'tcx>, branches: impl IntoIterator<Item = Self>) -> Self {
106 tcx.intern_valtree(ValTreeKind::Branch(branches.into_iter().collect()))
107 }
108
109 pub fn from_scalar_int(tcx: TyCtxt<'tcx>, i: ScalarInt) -> Self {
110 tcx.intern_valtree(ValTreeKind::Leaf(i))
111 }
112}
113
114impl<'tcx> Deref for ValTree<'tcx> {
115 type Target = &'tcx ValTreeKind<'tcx>;
116
117 #[inline]
118 fn deref(&self) -> &&'tcx ValTreeKind<'tcx> {
119 &self.0.0
120 }
121}
122
123impl fmt::Debug for ValTree<'_> {
124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 (**self).fmt(f)
126 }
127}
128
129pub type ConstToValTreeResult<'tcx> = Result<Result<ValTree<'tcx>, Ty<'tcx>>, ErrorHandled>;
134
135#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
141#[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable, Lift)]
142pub struct Value<'tcx> {
143 pub ty: Ty<'tcx>,
144 pub valtree: ValTree<'tcx>,
145}
146
147impl<'tcx> Value<'tcx> {
148 #[inline]
153 pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option<u128> {
154 let (ty::Bool | ty::Char | ty::Uint(_) | ty::Int(_) | ty::Float(_)) = self.ty.kind() else {
155 return None;
156 };
157 let scalar = self.valtree.try_to_scalar_int()?;
158 let input = typing_env.with_post_analysis_normalized(tcx).as_query_input(self.ty);
159 let size = tcx.layout_of(input).ok()?.size;
160 Some(scalar.to_bits(size))
161 }
162
163 pub fn try_to_bool(self) -> Option<bool> {
164 if !self.ty.is_bool() {
165 return None;
166 }
167 self.valtree.try_to_scalar_int()?.try_to_bool().ok()
168 }
169
170 pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
171 if !self.ty.is_usize() {
172 return None;
173 }
174 self.valtree.try_to_scalar_int().map(|s| s.to_target_usize(tcx))
175 }
176
177 pub fn try_to_raw_bytes(self, tcx: TyCtxt<'tcx>) -> Option<&'tcx [u8]> {
180 match self.ty.kind() {
181 ty::Ref(_, inner_ty, _) => match inner_ty.kind() {
182 ty::Str => {}
184 ty::Slice(slice_ty) if *slice_ty == tcx.types.u8 => {}
186 _ => return None,
188 },
189 ty::Array(array_ty, _) if *array_ty == tcx.types.u8 => {}
191 _ => return None,
193 }
194
195 Some(tcx.arena.alloc_from_iter(
196 self.valtree.unwrap_branch().into_iter().map(|v| v.unwrap_leaf().to_u8()),
197 ))
198 }
199}
200
201impl<'tcx> rustc_type_ir::inherent::ValueConst<TyCtxt<'tcx>> for Value<'tcx> {
202 fn ty(self) -> Ty<'tcx> {
203 self.ty
204 }
205
206 fn valtree(self) -> ValTree<'tcx> {
207 self.valtree
208 }
209}
210
211impl<'tcx> fmt::Display for Value<'tcx> {
212 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213 ty::tls::with(move |tcx| {
214 let cv = tcx.lift(*self).unwrap();
215 let mut p = FmtPrinter::new(tcx, Namespace::ValueNS);
216 p.pretty_print_const_valtree(cv, true)?;
217 f.write_str(&p.into_buffer())
218 })
219 }
220}