Skip to main content

rustc_type_ir/sty/
consts.rs

1use std::fmt;
2
3use derive_where::derive_where;
4use rustc_ast_ir::visit::VisitorResult;
5#[cfg(feature = "nightly")]
6use rustc_macros::StableHash_NoContext;
7use rustc_type_ir_macros::{GenericTypeVisitable, Lift_Generic};
8
9use crate::inherent::*;
10use crate::intern::Interned;
11use crate::relate::{Relate, RelateResult, TypeRelation};
12use crate::walk::TypeWalker;
13use crate::{
14    AliasConst, BoundConst, BoundVar, BoundVarIndexKind, ConstKind, ConstVid, DebruijnIndex,
15    FallibleTypeFolder, Flags, InferConst, Interner, IsRigid, PlaceholderConst, TypeFlags,
16    TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor,
17    ValTreeKind,
18};
19
20#[automatically_derived]
impl<I: Interner> ::core::clone::Clone for Const<I> where I: Interner {
    #[inline]
    fn clone(&self) -> Self { *self }
}
#[automatically_derived]
impl<I: Interner> ::core::marker::Copy for Const<I> where I: Interner { }
#[automatically_derived]
impl<I: Interner> ::core::cmp::PartialEq for Const<I> where I: Interner {
    #[inline]
    fn eq(&self, __other: &Self) -> ::core::primitive::bool {
        match (self, __other) {
            (Const(ref __field_0), Const(ref __other_field_0)) =>
                true &&
                    ::core::cmp::PartialEq::eq(__field_0, __other_field_0),
        }
    }
}
const _: () =
    {
        trait DeriveWhereAssertEq {
            fn assert(&self);
        }
        impl<I: Interner> DeriveWhereAssertEq for Const<I> where I: Interner {
            fn assert(&self) {
                struct __AssertEq<__T: ::core::cmp::Eq +
                    ?::core::marker::Sized>(::core::marker::PhantomData<__T>);
                let _: __AssertEq<I::InternedConstKind>;
            }
        }
    };
#[automatically_derived]
impl<I: Interner> ::core::cmp::Eq for Const<I> where I: Interner { }
#[automatically_derived]
impl<I: Interner> ::core::hash::Hash for Const<I> where I: Interner {
    fn hash<__H: ::core::hash::Hasher>(&self, __state: &mut __H) {
        match self {
            Const(ref __field_0) => {
                ::core::hash::Hash::hash(__field_0, __state);
            }
        }
    }
}#[derive_where(Clone, Copy, PartialEq, Eq, Hash; I: Interner)]
21#[cfg_attr(feature = "nightly", derive(const _: () =
    {
        impl<I: Interner> ::rustc_data_structures::stable_hash::StableHash for
            Const<I> where
            I::InternedConstKind: ::rustc_data_structures::stable_hash::StableHash
            {
            #[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 {
                    Const(ref __binding_0) => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                    }
                }
            }
        }
    };StableHash_NoContext))]
22#[cfg_attr(feature = "nightly", rustc_pass_by_value)]
23#[derive(const _: () =
    {
        unsafe impl<I: Interner, __V>
            ::rustc_type_ir::GenericTypeVisitable<__V> for Const<I> where
            I::InternedConstKind: ::rustc_type_ir::GenericTypeVisitable<__V> {
            fn generic_visit_with(&self, __visitor: &mut __V) {
                match *self {
                    Const(ref __binding_0) => {
                        {
                            ::rustc_type_ir::GenericTypeVisitable::<__V>::generic_visit_with(__binding_0,
                                __visitor);
                        }
                    }
                }
            }
        }
    };GenericTypeVisitable, const _: () =
    {
        impl<I: Interner, J> ::rustc_type_ir::lift::Lift<J> for Const<I> where
            J: Interner, I: ::rustc_type_ir::LiftInto<J> {
            type Lifted = Const<J>;
            fn lift_to_interner(self, interner: J) -> Self::Lifted {
                match self {
                    Const(__binding_0) => {
                        Const(__binding_0.lift_to_interner(interner))
                    }
                }
            }
        }
    };Lift_Generic)]
24pub struct Const<I: Interner>(pub I::InternedConstKind);
25
26impl<I: Interner> fmt::Debug for Const<I> {
27    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28        // If this is a value, we spend some effort to make it look nice.
29        if let ConstKind::Value(cv) = self.kind() {
30            f.write_fmt(format_args!("{0}", cv))write!(f, "{}", cv)
31        } else {
32            // Fall back to something verbose.
33            f.write_fmt(format_args!("{0:?}", self.kind()))write!(f, "{:?}", self.kind())
34        }
35    }
36}
37
38impl<I: Interner> Const<I> {
39    #[inline]
40    pub fn kind(self) -> ConstKind<I> {
41        *self.0.get()
42    }
43
44    #[inline]
45    pub fn new(interner: I, kind: ConstKind<I>) -> Self {
46        interner.mk_ct_from_kind(kind)
47    }
48
49    #[inline]
50    pub fn new_var(interner: I, infer: ConstVid) -> Self {
51        Self::new(interner, ConstKind::Infer(InferConst::Var(infer)))
52    }
53
54    #[inline]
55    pub fn new_infer(interner: I, infer: InferConst) -> Self {
56        Self::new(interner, ConstKind::Infer(infer))
57    }
58
59    #[inline]
60    pub fn new_bound(interner: I, debruijn: DebruijnIndex, bound_const: BoundConst<I>) -> Self {
61        Self::new(interner, ConstKind::Bound(BoundVarIndexKind::Bound(debruijn), bound_const))
62    }
63
64    #[inline]
65    pub fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self {
66        Self::new_bound(interner, debruijn, BoundConst::new(var))
67    }
68
69    #[inline]
70    pub fn new_canonical_bound(interner: I, var: BoundVar) -> Self {
71        Self::new(interner, ConstKind::Bound(BoundVarIndexKind::Canonical, BoundConst::new(var)))
72    }
73
74    #[inline]
75    pub fn new_placeholder(interner: I, placeholder: PlaceholderConst<I>) -> Self {
76        Self::new(interner, ConstKind::Placeholder(placeholder))
77    }
78
79    #[inline]
80    pub fn new_alias(interner: I, is_rigid: IsRigid, alias_const: AliasConst<I>) -> Self {
81        Self::new(interner, ConstKind::Alias(is_rigid, alias_const))
82    }
83
84    #[inline]
85    pub fn new_expr(interner: I, expr: I::ExprConst) -> Self {
86        Const::new(interner, ConstKind::Expr(expr))
87    }
88
89    #[inline]
90    pub fn new_error(interner: I, e: I::ErrorGuaranteed) -> Self {
91        Const::new(interner, ConstKind::Error(e))
92    }
93
94    #[inline]
95    pub fn is_ct_var(self) -> bool {
96        #[allow(non_exhaustive_omitted_patterns)] match self.kind() {
    ConstKind::Infer(InferConst::Var(_)) => true,
    _ => false,
}matches!(self.kind(), ConstKind::Infer(InferConst::Var(_)))
97    }
98
99    #[inline]
100    pub fn is_ct_error(self) -> bool {
101        #[allow(non_exhaustive_omitted_patterns)] match self.kind() {
    ConstKind::Error(_) => true,
    _ => false,
}matches!(self.kind(), ConstKind::Error(_))
102    }
103
104    #[inline]
105    pub fn new_param(interner: I, param: I::ParamConst) -> Self {
106        Self::new(interner, ConstKind::Param(param))
107    }
108
109    #[inline]
110    pub fn new_fresh(interner: I, fresh: u32) -> Self {
111        Self::new(interner, ConstKind::Infer(InferConst::Fresh(fresh)))
112    }
113
114    #[track_caller]
115    pub fn new_misc_error(interner: I) -> Self {
116        Self::new_error_with_message(
117            interner,
118            I::Span::dummy(),
119            "ty::ConstKind::Error constructed but no error reported",
120        )
121    }
122
123    #[track_caller]
124    pub fn new_error_with_message(interner: I, span: I::Span, msg: impl ToString) -> Self {
125        let reported = interner.span_delayed_bug(span, msg);
126        Self::new_error(interner, reported)
127    }
128
129    pub fn is_trivially_wf(self) -> bool {
130        match self.kind() {
131            ConstKind::Param(_) | ConstKind::Placeholder(_) | ConstKind::Bound(..) => true,
132            ConstKind::Infer(_)
133            | ConstKind::Alias(..)
134            | ConstKind::Value(_)
135            | ConstKind::Error(_)
136            | ConstKind::Expr(_) => false,
137        }
138    }
139
140    pub fn is_ct_infer(self) -> bool {
141        #[allow(non_exhaustive_omitted_patterns)] match self.kind() {
    ConstKind::Infer(_) => true,
    _ => false,
}matches!(self.kind(), ConstKind::Infer(_))
142    }
143
144    pub fn ct_vid(self) -> Option<ConstVid> {
145        match self.kind() {
146            ConstKind::Infer(InferConst::Var(vid)) => Some(vid),
147            _ => None,
148        }
149    }
150
151    #[inline]
152    pub fn new_value(interner: I, valtree: I::ValTree, ty: I::Ty) -> Self {
153        Self::new(interner, ConstKind::Value(I::ValueConst::new(ty, valtree)))
154    }
155
156    /// Creates an interned zst constant.
157    #[inline]
158    pub fn zero_sized(interner: I, ty: I::Ty) -> Self {
159        Self::new_value(interner, interner.const_zst(), ty)
160    }
161
162    /// Panics if `self.kind != ty::ConstKind::Value`.
163    pub fn to_value(self) -> I::ValueConst {
164        match self.kind() {
165            ConstKind::Value(cv) => cv,
166            _ => {
    ::core::panicking::panic_fmt(format_args!("expected ConstKind::Value, got {0:?}",
            self.kind()));
}panic!("expected ConstKind::Value, got {:?}", self.kind()),
167        }
168    }
169
170    /// Attempts to convert to a value.
171    ///
172    /// Note that this does not normalize the constant.
173    pub fn try_to_value(self) -> Option<I::ValueConst> {
174        match self.kind() {
175            ConstKind::Value(cv) => Some(cv),
176            _ => None,
177        }
178    }
179
180    /// Converts to a `ValTreeKind::Leaf` value, `panic`'ing
181    /// if this constant is some other kind.
182    ///
183    /// Note that this does not normalize the constant.
184    #[inline]
185    pub fn to_leaf(self) -> I::ScalarInt {
186        self.to_value().valtree().kind().to_leaf()
187    }
188
189    /// Converts to a `ValTreeKind::Branch` value, `panic`'ing
190    /// if this constant is some other kind.
191    ///
192    /// Note that this does not normalize the constant.
193    #[inline]
194    pub fn to_branch(self) -> I::Consts {
195        self.to_value().valtree().kind().to_branch()
196    }
197
198    /// Attempts to convert to a `ValTreeKind::Leaf` value.
199    ///
200    /// Note that this does not normalize the constant.
201    pub fn try_to_leaf(self) -> Option<I::ScalarInt> {
202        self.try_to_value()?.valtree().kind().try_to_leaf()
203    }
204    /// Attempts to convert to a `ValTreeKind::Branch` value.
205    ///
206    /// Note that this does not normalize the constant.
207    pub fn try_to_branch(self) -> Option<I::Consts> {
208        self.try_to_value()?.valtree().kind().try_to_branch()
209    }
210
211    /// Attempts to convert to a `ValTreeKind::Leaf` value.
212    ///
213    /// Note that this does not normalize the constant.
214    pub fn try_to_scalar(self) -> Option<I::Scalar> {
215        self.try_to_leaf().map(|x| x.to_scalar())
216    }
217
218    /// Creates a constant with the given integer value and interns it.
219    #[inline]
220    pub fn from_bits(interner: I, bits: u128, typing_env: I::TypingEnv, ty: I::Ty) -> Self {
221        let size = typing_env.layout_size(interner, ty);
222        let scalar_int = I::ScalarInt::try_from_uint(bits, size).unwrap();
223        let valtree = interner.intern_valtree(ValTreeKind::Leaf(scalar_int));
224        Self::new_value(interner, valtree, ty)
225    }
226
227    #[inline]
228    /// Creates an interned bool constant.
229    pub fn from_bool(interner: I, v: bool) -> Self {
230        let bool_ty = I::Ty::new_bool(interner);
231        Self::from_bits(interner, v as u128, I::TypingEnv::fully_monomorphized(), bool_ty)
232    }
233
234    #[inline]
235    /// Creates an interned usize constant.
236    pub fn from_target_usize(interner: I, n: u64) -> Self {
237        let usize_ty = I::Ty::new_usize(interner);
238        Self::from_bits(interner, n as u128, I::TypingEnv::fully_monomorphized(), usize_ty)
239    }
240
241    /// Convenience method to extract the value of a usize constant,
242    /// useful to get the length of an array type.
243    ///
244    /// Note that this does not evaluate the constant.
245    #[inline]
246    pub fn try_to_target_usize(self, interner: I) -> Option<u64> {
247        self.try_to_value()?.try_to_target_usize(interner)
248    }
249
250    /// Iterator that walks `self` and any types reachable from
251    /// `self`, in depth-first order. Note that just walks the types
252    /// that appear in `self`, it does not descend into the fields of
253    /// structs or variants. For example:
254    ///
255    /// ```text
256    /// isize => { isize }
257    /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
258    /// [isize] => { [isize], isize }
259    /// ```
260    pub fn walk(self) -> TypeWalker<I> {
261        TypeWalker::new(self.into())
262    }
263}
264
265impl<I: Interner> Flags for Const<I> {
266    fn flags(&self) -> TypeFlags {
267        self.0.get().flags
268    }
269
270    fn outer_exclusive_binder(&self) -> DebruijnIndex {
271        self.0.get().outer_exclusive_binder
272    }
273}
274
275impl<I: Interner> IntoKind for Const<I> {
276    type Kind = ConstKind<I>;
277
278    fn kind(self) -> Self::Kind {
279        *self.0.get()
280    }
281}
282
283impl<I: Interner> TypeFoldable<I> for Const<I> {
284    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
285        folder.try_fold_const(self)
286    }
287
288    fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
289        folder.fold_const(self)
290    }
291}
292
293impl<I: Interner> TypeVisitable<I> for Const<I> {
294    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
295        visitor.visit_const(*self)
296    }
297}
298
299impl<I: Interner> TypeSuperFoldable<I> for Const<I> {
300    fn try_super_fold_with<F: FallibleTypeFolder<I>>(
301        self,
302        folder: &mut F,
303    ) -> Result<Self, F::Error> {
304        let kind = match self.kind() {
305            ConstKind::Alias(is_rigid, alias_const) => {
306                ConstKind::Alias(is_rigid, alias_const.try_fold_with(folder)?)
307            }
308            ConstKind::Value(v) => ConstKind::Value(v.try_fold_with(folder)?),
309            ConstKind::Expr(e) => ConstKind::Expr(e.try_fold_with(folder)?),
310
311            ConstKind::Param(_)
312            | ConstKind::Infer(_)
313            | ConstKind::Bound(..)
314            | ConstKind::Placeholder(_)
315            | ConstKind::Error(_) => return Ok(self),
316        };
317        if kind != self.kind() { Ok(Self::new(folder.cx(), kind)) } else { Ok(self) }
318    }
319
320    fn super_fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
321        let kind = match self.kind() {
322            ConstKind::Alias(is_rigid, alias_const) => {
323                ConstKind::Alias(is_rigid, alias_const.fold_with(folder))
324            }
325            ConstKind::Value(v) => ConstKind::Value(v.fold_with(folder)),
326            ConstKind::Expr(e) => ConstKind::Expr(e.fold_with(folder)),
327
328            ConstKind::Param(_)
329            | ConstKind::Infer(_)
330            | ConstKind::Bound(..)
331            | ConstKind::Placeholder(_)
332            | ConstKind::Error(_) => return self,
333        };
334        if kind != self.kind() { Self::new(folder.cx(), kind) } else { self }
335    }
336}
337
338impl<I: Interner> TypeSuperVisitable<I> for Const<I> {
339    fn super_visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
340        match self.kind() {
341            ConstKind::Alias(_, alias_const) => alias_const.visit_with(visitor),
342            ConstKind::Value(v) => v.visit_with(visitor),
343            ConstKind::Expr(e) => e.visit_with(visitor),
344            ConstKind::Error(e) => e.visit_with(visitor),
345
346            ConstKind::Param(_)
347            | ConstKind::Infer(_)
348            | ConstKind::Bound(..)
349            | ConstKind::Placeholder(_) => V::Result::output(),
350        }
351    }
352}
353
354impl<I: Interner> Relate<I> for Const<I> {
355    fn relate<R: TypeRelation<I>>(relation: &mut R, a: Self, b: Self) -> RelateResult<I, Self> {
356        relation.consts(a, b)
357    }
358}