Skip to main content

rustc_middle/ty/consts/
valtree.rs

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::consts::ConstExt;
15use crate::ty::print::{FmtPrinter, PrettyPrinter};
16use crate::ty::{self, Ty, TyCtxt, ValTreeKind};
17
18pub 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>)]
19impl<'tcx> ty::ValTreeKind<TyCtxt<'tcx>> {
20    fn try_to_scalar(&self) -> Option<Scalar> {
21        self.try_to_leaf().map(Scalar::Int)
22    }
23}
24
25/// An interned valtree. Use this rather than `ValTreeKind`, whenever possible.
26///
27/// See the docs of [`ty::ValTreeKind`] or the [dev guide] for an explanation of this type.
28///
29/// [dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html#valtrees
30#[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) -> Self {
        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: &Self) -> bool { self.0 == other.0 }
}PartialEq)]
31#[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)]
32// FIXME(mgca): Try not interning here. We already intern `ty::Const` which `ValTreeKind`
33// recurses through
34pub struct ValTree<'tcx>(pub(crate) Interned<'tcx, ty::ValTreeKind<TyCtxt<'tcx>>>);
35
36impl<'tcx> ValTree<'tcx> {
37    /// Returns the zero-sized valtree: `Branch([])`.
38    pub fn zst(tcx: TyCtxt<'tcx>) -> Self {
39        tcx.consts.valtree_zst
40    }
41
42    pub fn is_zst(self) -> bool {
43        #[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())
44    }
45
46    pub fn from_raw_bytes(tcx: TyCtxt<'tcx>, bytes: &[u8]) -> Self {
47        let branches = bytes.iter().map(|&b| {
48            ty::Const::new_value(tcx, Self::from_scalar_int(tcx, b.into()), tcx.types.u8)
49        });
50        Self::from_branches(tcx, branches)
51    }
52
53    pub fn from_branches(
54        tcx: TyCtxt<'tcx>,
55        branches: impl IntoIterator<Item = ty::Const<'tcx>>,
56    ) -> Self {
57        tcx.intern_valtree(ty::ValTreeKind::Branch(
58            tcx.mk_const_list_from_iter(branches.into_iter()),
59        ))
60    }
61
62    pub fn from_scalar_int(tcx: TyCtxt<'tcx>, i: ScalarInt) -> Self {
63        tcx.intern_valtree(ty::ValTreeKind::Leaf(i))
64    }
65}
66
67impl<'tcx> Deref for ValTree<'tcx> {
68    type Target = &'tcx ty::ValTreeKind<TyCtxt<'tcx>>;
69
70    #[inline]
71    fn deref(&self) -> &&'tcx ty::ValTreeKind<TyCtxt<'tcx>> {
72        &self.0.0
73    }
74}
75
76impl fmt::Debug for ValTree<'_> {
77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        (**self).fmt(f)
79    }
80}
81
82impl<'tcx> rustc_type_ir::inherent::IntoKind for ty::ValTree<'tcx> {
83    type Kind = ty::ValTreeKind<TyCtxt<'tcx>>;
84
85    fn kind(self) -> Self::Kind {
86        *self.0
87    }
88}
89
90/// `Ok(Err(ty))` indicates the constant was fine, but the valtree couldn't be constructed
91/// because the value contains something of type `ty` that is not valtree-compatible.
92/// The caller can then show an appropriate error; the query does not have the
93/// necessary context to give good user-facing errors for this case.
94pub type ConstToValTreeResult<'tcx> = Result<Result<ValTree<'tcx>, Ty<'tcx>>, ErrorHandled>;
95
96/// A type-level constant value.
97///
98/// Represents a typed, fully evaluated constant.
99/// Note that this is also used by pattern elaboration to represent values which cannot occur in types,
100/// such as raw pointers and floats.
101#[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) -> Self {
        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: &Self) -> bool {
        self.ty == other.ty && self.valtree == other.valtree
    }
}PartialEq)]
102#[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)]
103pub struct Value<'tcx> {
104    pub ty: Ty<'tcx>,
105    pub valtree: ValTree<'tcx>,
106}
107
108impl<'tcx> Value<'tcx> {
109    /// Attempts to extract the raw bits from the constant.
110    ///
111    /// Fails if the value can't be represented as bits (e.g. because it is a reference
112    /// or an aggregate).
113    #[inline]
114    pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option<u128> {
115        let (ty::Bool | ty::Char | ty::Uint(_) | ty::Int(_) | ty::Float(_)) = self.ty.kind() else {
116            return None;
117        };
118        let scalar = self.try_to_leaf()?;
119        let input = typing_env.with_post_analysis_normalized(tcx).as_query_input(self.ty);
120        let size = tcx.layout_of(input).ok()?.size;
121        Some(scalar.to_bits(size))
122    }
123
124    pub fn try_to_bool(self) -> Option<bool> {
125        if !self.ty.is_bool() {
126            return None;
127        }
128        self.try_to_leaf()?.try_to_bool().ok()
129    }
130
131    pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
132        if !self.ty.is_usize() {
133            return None;
134        }
135        self.try_to_leaf().map(|s| s.to_target_usize(tcx))
136    }
137
138    /// Get the values inside the ValTree as a slice of bytes. This only works for
139    /// constants with types &str, &[u8], or [u8; _].
140    pub fn try_to_raw_bytes(self, tcx: TyCtxt<'tcx>) -> Option<&'tcx [u8]> {
141        match self.ty.kind() {
142            ty::Ref(_, inner_ty, _) => match inner_ty.kind() {
143                // `&str` can be interpreted as raw bytes
144                ty::Str => {}
145                // `&[T]` can be interpreted as raw bytes if elements are `u8`
146                ty::Slice(_) => {}
147                // other `&_` can't be interpreted as raw bytes
148                _ => return None,
149            },
150            // `[T; N]` can be interpreted as raw bytes if elements are `u8`
151            ty::Array(_, _) => {}
152            // Otherwise, type cannot be interpreted as raw bytes
153            _ => return None,
154        }
155
156        // We create an iterator that yields `Option<u8>`
157        let iterator = self.to_branch().into_iter().map(|ct| {
158            (*ct)
159                .try_to_value()
160                .and_then(|value| (value.ty == tcx.types.u8).then_some(value))
161                .and_then(|value| value.try_to_leaf().map(|leaf| leaf.to_u8()))
162        });
163        // If there is `None` in the iterator, then the array is not a valid array of u8s and we return `None`
164        let bytes: Vec<u8> = iterator.collect::<Option<Vec<u8>>>()?;
165
166        Some(tcx.arena.alloc_from_iter(bytes))
167    }
168
169    /// Converts to a `ValTreeKind::Leaf` value, `panic`'ing
170    /// if this constant is some other kind.
171    #[inline]
172    pub fn to_leaf(self) -> ScalarInt {
173        match &**self.valtree {
174            ValTreeKind::Leaf(s) => *s,
175            ValTreeKind::Branch(..) => ::rustc_span::macros::bug_impl(None,
    format_args!("expected leaf, got {0:?}", self), Location::caller())bug!("expected leaf, got {:?}", self),
176        }
177    }
178
179    /// Converts to a `ValTreeKind::Branch` value, `panic`'ing
180    /// if this constant is some other kind.
181    #[inline]
182    pub fn to_branch(self) -> &'tcx [ty::Const<'tcx>] {
183        match &**self.valtree {
184            ValTreeKind::Branch(branch) => &**branch,
185            ValTreeKind::Leaf(..) => ::rustc_span::macros::bug_impl(None,
    format_args!("expected branch, got {0:?}", self), Location::caller())bug!("expected branch, got {:?}", self),
186        }
187    }
188
189    /// Attempts to convert to a `ValTreeKind::Leaf` value.
190    pub fn try_to_leaf(self) -> Option<ScalarInt> {
191        match &**self.valtree {
192            ValTreeKind::Leaf(s) => Some(*s),
193            ValTreeKind::Branch(_) => None,
194        }
195    }
196
197    /// Attempts to convert to a `ValTreeKind::Leaf` value.
198    pub fn try_to_scalar(&self) -> Option<Scalar> {
199        self.try_to_leaf().map(Scalar::Int)
200    }
201
202    /// Attempts to convert to a `ValTreeKind::Branch` value.
203    pub fn try_to_branch(self) -> Option<&'tcx [ty::Const<'tcx>]> {
204        match &**self.valtree {
205            ValTreeKind::Branch(branch) => Some(&**branch),
206            ValTreeKind::Leaf(_) => None,
207        }
208    }
209
210    /// Destructures ADT constants into the constants of their fields.
211    pub fn destructure_adt_const(&self) -> ty::DestructuredAdtConst<'tcx> {
212        let fields = self.to_branch();
213
214        let (variant, fields) = match self.ty.kind() {
215            ty::Adt(def, _) if def.variants().is_empty() => {
216                ::rustc_span::macros::bug_impl(None, format_args!("unreachable"),
    Location::caller())bug!("unreachable")
217            }
218            ty::Adt(def, _) if def.is_enum() => {
219                let (head, rest) = fields.split_first().unwrap();
220                (VariantIdx::from_u32(head.to_leaf().to_u32()), rest)
221            }
222            ty::Adt(_, _) => (FIRST_VARIANT, fields),
223            _ => ::rustc_span::macros::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),
224        };
225
226        ty::DestructuredAdtConst { variant, fields }
227    }
228}
229
230impl<'tcx> rustc_type_ir::inherent::ValueConst<TyCtxt<'tcx>> for Value<'tcx> {
231    fn ty(self) -> Ty<'tcx> {
232        self.ty
233    }
234
235    fn valtree(self) -> ValTree<'tcx> {
236        self.valtree
237    }
238}
239
240impl<'tcx> fmt::Display for Value<'tcx> {
241    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242        ty::tls::with(move |tcx| {
243            let mut p = FmtPrinter::new(tcx, Namespace::ValueNS);
244            p.pretty_print_const_valtree(tcx.lift(*self), /*print_ty*/ true)?;
245            f.write_str(&p.into_buffer())
246        })
247    }
248}