1use std::fmt;
2use std::ops::Deref;
3
4use rustc_abi::{FIRST_VARIANT, VariantIdx};
5use rustc_data_structures::intern::Interned;
6use rustc_hir::def::Namespace;
7use rustc_macros::{
8 Lift, StableHash, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, extension,
9};
10use rustc_span::bug;
11
12use super::ScalarInt;
13use crate::mir::interpret::{ErrorHandled, Scalar};
14use crate::ty::print::{FmtPrinter, PrettyPrinter};
15use crate::ty::{self, Ty, TyCtxt, ValTreeKind};
16
17pub trait ValTreeKindExt<'tcx> {
fn try_to_scalar(&self)
-> Option<Scalar>;
}
impl<'tcx> ValTreeKindExt<'tcx> for ty::ValTreeKind<TyCtxt<'tcx>> {
fn try_to_scalar(&self) -> Option<Scalar> {
self.try_to_leaf().map(Scalar::Int)
}
}#[extension(pub trait ValTreeKindExt<'tcx>)]
18impl<'tcx> ty::ValTreeKind<TyCtxt<'tcx>> {
19 fn try_to_scalar(&self) -> Option<Scalar> {
20 self.try_to_leaf().map(Scalar::Int)
21 }
22}
23
24#[derive(#[automatically_derived]
impl<'tcx> ::core::marker::Copy for ValTree<'tcx> { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl<'tcx> ::core::clone::TrivialClone for ValTree<'tcx> { }
#[automatically_derived]
impl<'tcx> ::core::clone::Clone for ValTree<'tcx> {
#[inline]
fn clone(&self) -> ValTree<'tcx> {
let _:
::core::clone::AssertParamIsClone<Interned<'tcx,
ty::ValTreeKind<TyCtxt<'tcx>>>>;
*self
}
}Clone, #[automatically_derived]
impl<'tcx> ::core::hash::Hash for ValTree<'tcx> {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.0, state)
}
}Hash, #[automatically_derived]
impl<'tcx> ::core::cmp::Eq for ValTree<'tcx> {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _:
::core::cmp::AssertParamIsEq<Interned<'tcx,
ty::ValTreeKind<TyCtxt<'tcx>>>>;
}
}Eq, #[automatically_derived]
impl<'tcx> ::core::marker::StructuralPartialEq for ValTree<'tcx> { }
#[automatically_derived]
impl<'tcx> ::core::cmp::PartialEq for ValTree<'tcx> {
#[inline]
fn eq(&self, other: &ValTree<'tcx>) -> bool { self.0 == other.0 }
}PartialEq)]
30#[derive(const _: () =
{
impl<'tcx> ::rustc_data_structures::stable_hash::StableHash for
ValTree<'tcx> {
#[inline]
fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
__hcx: &mut __Hcx,
__hasher:
&mut ::rustc_data_structures::stable_hash::StableHasher) {
match *self {
ValTree(ref __binding_0) => {
{ __binding_0.stable_hash(__hcx, __hasher); }
}
}
}
}
};StableHash)]
31pub struct ValTree<'tcx>(pub(crate) Interned<'tcx, ty::ValTreeKind<TyCtxt<'tcx>>>);
34
35impl<'tcx> ValTree<'tcx> {
36 pub fn zst(tcx: TyCtxt<'tcx>) -> Self {
38 tcx.consts.valtree_zst
39 }
40
41 pub fn is_zst(self) -> bool {
42 #[allow(non_exhaustive_omitted_patterns)] match *self {
ty::ValTreeKind::Branch(consts) if consts.is_empty() => true,
_ => false,
}matches!(*self, ty::ValTreeKind::Branch(consts) if consts.is_empty())
43 }
44
45 pub fn from_raw_bytes(tcx: TyCtxt<'tcx>, bytes: &[u8]) -> Self {
46 let branches = bytes.iter().map(|&b| {
47 ty::Const::new_value(tcx, Self::from_scalar_int(tcx, b.into()), tcx.types.u8)
48 });
49 Self::from_branches(tcx, branches)
50 }
51
52 pub fn from_branches(
53 tcx: TyCtxt<'tcx>,
54 branches: impl IntoIterator<Item = ty::Const<'tcx>>,
55 ) -> Self {
56 tcx.intern_valtree(ty::ValTreeKind::Branch(
57 tcx.mk_const_list_from_iter(branches.into_iter()),
58 ))
59 }
60
61 pub fn from_scalar_int(tcx: TyCtxt<'tcx>, i: ScalarInt) -> Self {
62 tcx.intern_valtree(ty::ValTreeKind::Leaf(i))
63 }
64}
65
66impl<'tcx> Deref for ValTree<'tcx> {
67 type Target = &'tcx ty::ValTreeKind<TyCtxt<'tcx>>;
68
69 #[inline]
70 fn deref(&self) -> &&'tcx ty::ValTreeKind<TyCtxt<'tcx>> {
71 &self.0.0
72 }
73}
74
75impl fmt::Debug for ValTree<'_> {
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 (**self).fmt(f)
78 }
79}
80
81impl<'tcx> rustc_type_ir::inherent::IntoKind for ty::ValTree<'tcx> {
82 type Kind = ty::ValTreeKind<TyCtxt<'tcx>>;
83
84 fn kind(self) -> Self::Kind {
85 *self.0
86 }
87}
88
89pub type ConstToValTreeResult<'tcx> = Result<Result<ValTree<'tcx>, Ty<'tcx>>, ErrorHandled>;
94
95#[derive(#[automatically_derived]
impl<'tcx> ::core::marker::Copy for Value<'tcx> { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl<'tcx> ::core::clone::TrivialClone for Value<'tcx> { }
#[automatically_derived]
impl<'tcx> ::core::clone::Clone for Value<'tcx> {
#[inline]
fn clone(&self) -> Value<'tcx> {
let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
let _: ::core::clone::AssertParamIsClone<ValTree<'tcx>>;
*self
}
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for Value<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "Value", "ty",
&self.ty, "valtree", &&self.valtree)
}
}Debug, #[automatically_derived]
impl<'tcx> ::core::hash::Hash for Value<'tcx> {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.ty, state);
::core::hash::Hash::hash(&self.valtree, state)
}
}Hash, #[automatically_derived]
impl<'tcx> ::core::cmp::Eq for Value<'tcx> {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<Ty<'tcx>>;
let _: ::core::cmp::AssertParamIsEq<ValTree<'tcx>>;
}
}Eq, #[automatically_derived]
impl<'tcx> ::core::marker::StructuralPartialEq for Value<'tcx> { }
#[automatically_derived]
impl<'tcx> ::core::cmp::PartialEq for Value<'tcx> {
#[inline]
fn eq(&self, other: &Value<'tcx>) -> bool {
self.ty == other.ty && self.valtree == other.valtree
}
}PartialEq)]
101#[derive(const _: () =
{
impl<'tcx> ::rustc_data_structures::stable_hash::StableHash for
Value<'tcx> {
#[inline]
fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
__hcx: &mut __Hcx,
__hasher:
&mut ::rustc_data_structures::stable_hash::StableHasher) {
match *self {
Value { ty: ref __binding_0, valtree: ref __binding_1 } => {
{ __binding_0.stable_hash(__hcx, __hasher); }
{ __binding_1.stable_hash(__hcx, __hasher); }
}
}
}
}
};StableHash, const _: () =
{
impl<'tcx, __E: ::rustc_middle::ty::codec::TyEncoder<'tcx>>
::rustc_serialize::Encodable<__E> for Value<'tcx> {
fn encode(&self, __encoder: &mut __E) {
let Value { ty: ref __binding_0, valtree: ref __binding_1 } =
*self;
::rustc_serialize::Encodable::<__E>::encode(__binding_0,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_1,
__encoder);
}
}
};TyEncodable, const _: () =
{
impl<'tcx, __D: ::rustc_middle::ty::codec::TyDecoder<'tcx>>
::rustc_serialize::Decodable<__D> for Value<'tcx> {
fn decode(__decoder: &mut __D) -> Self {
Value {
ty: ::rustc_serialize::Decodable::decode(__decoder),
valtree: ::rustc_serialize::Decodable::decode(__decoder),
}
}
}
};TyDecodable, const _: () =
{
impl<'tcx>
::rustc_middle::ty::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>>
for Value<'tcx> {
fn try_fold_with<__F: ::rustc_middle::ty::FallibleTypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(self,
__folder: &mut __F) -> Result<Self, __F::Error> {
Ok(match self {
Value { ty: __binding_0, valtree: __binding_1 } => {
Value {
ty: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_0,
__folder)?,
valtree: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_1,
__folder)?,
}
}
})
}
fn fold_with<__F: ::rustc_middle::ty::TypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(self,
__folder: &mut __F) -> Self {
match self {
Value { ty: __binding_0, valtree: __binding_1 } => {
Value {
ty: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_0,
__folder),
valtree: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_1,
__folder),
}
}
}
}
}
};TypeFoldable, const _: () =
{
impl<'tcx>
::rustc_middle::ty::TypeVisitable<::rustc_middle::ty::TyCtxt<'tcx>>
for Value<'tcx> {
fn visit_with<__V: ::rustc_middle::ty::TypeVisitor<::rustc_middle::ty::TyCtxt<'tcx>>>(&self,
__visitor: &mut __V) -> __V::Result {
match *self {
Value { ty: ref __binding_0, valtree: ref __binding_1 } => {
{
match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_0,
__visitor)) {
::core::ops::ControlFlow::Continue(()) => {}
::core::ops::ControlFlow::Break(r) => {
return ::rustc_middle::ty::VisitorResult::from_residual(r);
}
}
}
{
match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_1,
__visitor)) {
::core::ops::ControlFlow::Continue(()) => {}
::core::ops::ControlFlow::Break(r) => {
return ::rustc_middle::ty::VisitorResult::from_residual(r);
}
}
}
}
}
<__V::Result as ::rustc_middle::ty::VisitorResult>::output()
}
}
};TypeVisitable, const _: () =
{
impl<'tcx, '__lifted>
::rustc_middle::ty::Lift<::rustc_middle::ty::TyCtxt<'__lifted>>
for Value<'tcx> {
type Lifted = Value<'__lifted>;
fn lift_to_interner(self,
__tcx: ::rustc_middle::ty::TyCtxt<'__lifted>)
-> Value<'__lifted> {
match self {
Value { ty: __binding_0, valtree: __binding_1 } => {
Value {
ty: __tcx.lift(__binding_0),
valtree: __tcx.lift(__binding_1),
}
}
}
}
}
};Lift)]
102pub struct Value<'tcx> {
103 pub ty: Ty<'tcx>,
104 pub valtree: ValTree<'tcx>,
105}
106
107impl<'tcx> Value<'tcx> {
108 #[inline]
113 pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option<u128> {
114 let (ty::Bool | ty::Char | ty::Uint(_) | ty::Int(_) | ty::Float(_)) = self.ty.kind() else {
115 return None;
116 };
117 let scalar = self.try_to_leaf()?;
118 let input = typing_env.with_post_analysis_normalized(tcx).as_query_input(self.ty);
119 let size = tcx.layout_of(input).ok()?.size;
120 Some(scalar.to_bits(size))
121 }
122
123 pub fn try_to_bool(self) -> Option<bool> {
124 if !self.ty.is_bool() {
125 return None;
126 }
127 self.try_to_leaf()?.try_to_bool().ok()
128 }
129
130 pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
131 if !self.ty.is_usize() {
132 return None;
133 }
134 self.try_to_leaf().map(|s| s.to_target_usize(tcx))
135 }
136
137 pub fn try_to_raw_bytes(self, tcx: TyCtxt<'tcx>) -> Option<&'tcx [u8]> {
140 match self.ty.kind() {
141 ty::Ref(_, inner_ty, _) => match inner_ty.kind() {
142 ty::Str => {}
144 ty::Slice(_) => {}
146 _ => return None,
148 },
149 ty::Array(_, _) => {}
151 _ => return None,
153 }
154
155 let iterator = self.to_branch().into_iter().map(|ct| {
157 (*ct)
158 .try_to_value()
159 .and_then(|value| (value.ty == tcx.types.u8).then_some(value))
160 .and_then(|value| value.try_to_leaf().map(|leaf| leaf.to_u8()))
161 });
162 let bytes: Vec<u8> = iterator.collect::<Option<Vec<u8>>>()?;
164
165 Some(tcx.arena.alloc_from_iter(bytes))
166 }
167
168 #[inline]
171 pub fn to_leaf(self) -> ScalarInt {
172 match &**self.valtree {
173 ValTreeKind::Leaf(s) => *s,
174 ValTreeKind::Branch(..) => bug_impl(None, format_args!("expected leaf, got {0:?}", self),
Location::caller())bug!("expected leaf, got {:?}", self),
175 }
176 }
177
178 #[inline]
181 pub fn to_branch(self) -> &'tcx [ty::Const<'tcx>] {
182 match &**self.valtree {
183 ValTreeKind::Branch(branch) => &**branch,
184 ValTreeKind::Leaf(..) => bug_impl(None, format_args!("expected branch, got {0:?}", self),
Location::caller())bug!("expected branch, got {:?}", self),
185 }
186 }
187
188 pub fn try_to_leaf(self) -> Option<ScalarInt> {
190 match &**self.valtree {
191 ValTreeKind::Leaf(s) => Some(*s),
192 ValTreeKind::Branch(_) => None,
193 }
194 }
195
196 pub fn try_to_scalar(&self) -> Option<Scalar> {
198 self.try_to_leaf().map(Scalar::Int)
199 }
200
201 pub fn try_to_branch(self) -> Option<&'tcx [ty::Const<'tcx>]> {
203 match &**self.valtree {
204 ValTreeKind::Branch(branch) => Some(&**branch),
205 ValTreeKind::Leaf(_) => None,
206 }
207 }
208
209 pub fn destructure_adt_const(&self) -> ty::DestructuredAdtConst<'tcx> {
211 let fields = self.to_branch();
212
213 let (variant, fields) = match self.ty.kind() {
214 ty::Adt(def, _) if def.variants().is_empty() => {
215 bug_impl(None, format_args!("unreachable"), Location::caller())bug!("unreachable")
216 }
217 ty::Adt(def, _) if def.is_enum() => {
218 let (head, rest) = fields.split_first().unwrap();
219 (VariantIdx::from_u32(head.to_leaf().to_u32()), rest)
220 }
221 ty::Adt(_, _) => (FIRST_VARIANT, fields),
222 _ => bug_impl(None,
format_args!("destructure_adt_const called on non-ADT type: {0:?}",
self.ty), Location::caller())bug!("destructure_adt_const called on non-ADT type: {:?}", self.ty),
223 };
224
225 ty::DestructuredAdtConst { variant, fields }
226 }
227}
228
229impl<'tcx> rustc_type_ir::inherent::ValueConst<TyCtxt<'tcx>> for Value<'tcx> {
230 fn ty(self) -> Ty<'tcx> {
231 self.ty
232 }
233
234 fn valtree(self) -> ValTree<'tcx> {
235 self.valtree
236 }
237}
238
239impl<'tcx> fmt::Display for Value<'tcx> {
240 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241 ty::tls::with(move |tcx| {
242 let mut p = FmtPrinter::new(tcx, Namespace::ValueNS);
243 p.pretty_print_const_valtree(tcx.lift(*self), true)?;
244 f.write_str(&p.into_buffer())
245 })
246 }
247}