1use std::borrow::Cow;
2
3use rustc_data_structures::intern::Interned;
4use rustc_error_messages::MultiSpan;
5use rustc_macros::HashStable;
6use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
7
8use crate::ty::{self, Ty, TyCtxt};
9
10mod int;
11mod kind;
12mod valtree;
13
14pub use int::*;
15pub use kind::*;
16use rustc_span::{DUMMY_SP, ErrorGuaranteed};
17pub use valtree::*;
18
19pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>;
20pub type UnevaluatedConst<'tcx> = ir::UnevaluatedConst<TyCtxt<'tcx>>;
21
22#[cfg(target_pointer_width = "64")]
23rustc_data_structures::static_assert_size!(ConstKind<'_>, 24);
24
25#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)]
26#[rustc_pass_by_value]
27pub struct Const<'tcx>(pub(super) Interned<'tcx, WithCachedTypeInfo<ConstKind<'tcx>>>);
28
29impl<'tcx> rustc_type_ir::inherent::IntoKind for Const<'tcx> {
30 type Kind = ConstKind<'tcx>;
31
32 fn kind(self) -> ConstKind<'tcx> {
33 self.kind()
34 }
35}
36
37impl<'tcx> rustc_type_ir::Flags for Const<'tcx> {
38 fn flags(&self) -> TypeFlags {
39 self.0.flags
40 }
41
42 fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex {
43 self.0.outer_exclusive_binder
44 }
45}
46
47impl<'tcx> Const<'tcx> {
48 #[inline]
49 pub fn kind(self) -> ConstKind<'tcx> {
50 let a: &ConstKind<'tcx> = self.0.0;
51 *a
52 }
53
54 #[inline]
56 pub fn flags(self) -> TypeFlags {
57 self.0.flags
58 }
59
60 #[inline]
62 pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex {
63 self.0.outer_exclusive_binder
64 }
65
66 #[inline]
67 pub fn new(tcx: TyCtxt<'tcx>, kind: ty::ConstKind<'tcx>) -> Const<'tcx> {
68 tcx.mk_ct_from_kind(kind)
69 }
70
71 #[inline]
72 pub fn new_param(tcx: TyCtxt<'tcx>, param: ty::ParamConst) -> Const<'tcx> {
73 Const::new(tcx, ty::ConstKind::Param(param))
74 }
75
76 #[inline]
77 pub fn new_var(tcx: TyCtxt<'tcx>, infer: ty::ConstVid) -> Const<'tcx> {
78 Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Var(infer)))
79 }
80
81 #[inline]
82 pub fn new_fresh(tcx: TyCtxt<'tcx>, fresh: u32) -> Const<'tcx> {
83 Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Fresh(fresh)))
84 }
85
86 #[inline]
87 pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst) -> Const<'tcx> {
88 Const::new(tcx, ty::ConstKind::Infer(infer))
89 }
90
91 #[inline]
92 pub fn new_bound(
93 tcx: TyCtxt<'tcx>,
94 debruijn: ty::DebruijnIndex,
95 var: ty::BoundVar,
96 ) -> Const<'tcx> {
97 Const::new(tcx, ty::ConstKind::Bound(debruijn, var))
98 }
99
100 #[inline]
101 pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderConst) -> Const<'tcx> {
102 Const::new(tcx, ty::ConstKind::Placeholder(placeholder))
103 }
104
105 #[inline]
106 pub fn new_unevaluated(tcx: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Const<'tcx> {
107 tcx.debug_assert_args_compatible(uv.def, uv.args);
108 Const::new(tcx, ty::ConstKind::Unevaluated(uv))
109 }
110
111 #[inline]
112 pub fn new_value(tcx: TyCtxt<'tcx>, valtree: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
113 Const::new(tcx, ty::ConstKind::Value(ty::Value { ty, valtree }))
114 }
115
116 #[inline]
117 pub fn new_expr(tcx: TyCtxt<'tcx>, expr: ty::Expr<'tcx>) -> Const<'tcx> {
118 Const::new(tcx, ty::ConstKind::Expr(expr))
119 }
120
121 #[inline]
122 pub fn new_error(tcx: TyCtxt<'tcx>, e: ty::ErrorGuaranteed) -> Const<'tcx> {
123 Const::new(tcx, ty::ConstKind::Error(e))
124 }
125
126 #[track_caller]
128 pub fn new_misc_error(tcx: TyCtxt<'tcx>) -> Const<'tcx> {
129 Const::new_error_with_message(
130 tcx,
131 DUMMY_SP,
132 "ty::ConstKind::Error constructed but no error reported",
133 )
134 }
135
136 #[track_caller]
138 pub fn new_error_with_message<S: Into<MultiSpan>>(
139 tcx: TyCtxt<'tcx>,
140 span: S,
141 msg: impl Into<Cow<'static, str>>,
142 ) -> Const<'tcx> {
143 let reported = tcx.dcx().span_delayed_bug(span, msg);
144 Const::new_error(tcx, reported)
145 }
146}
147
148impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
149 fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst) -> Self {
150 Const::new_infer(tcx, infer)
151 }
152
153 fn new_var(tcx: TyCtxt<'tcx>, vid: ty::ConstVid) -> Self {
154 Const::new_var(tcx, vid)
155 }
156
157 fn new_bound(interner: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
158 Const::new_bound(interner, debruijn, var)
159 }
160
161 fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
162 Const::new_bound(tcx, debruijn, var)
163 }
164
165 fn new_unevaluated(interner: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Self {
166 Const::new_unevaluated(interner, uv)
167 }
168
169 fn new_expr(interner: TyCtxt<'tcx>, expr: ty::Expr<'tcx>) -> Self {
170 Const::new_expr(interner, expr)
171 }
172
173 fn new_error(interner: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self {
174 Const::new_error(interner, guar)
175 }
176}
177
178impl<'tcx> Const<'tcx> {
179 #[inline]
181 pub fn from_bits(
182 tcx: TyCtxt<'tcx>,
183 bits: u128,
184 typing_env: ty::TypingEnv<'tcx>,
185 ty: Ty<'tcx>,
186 ) -> Self {
187 let size = tcx
188 .layout_of(typing_env.as_query_input(ty))
189 .unwrap_or_else(|e| panic!("could not compute layout for {ty:?}: {e:?}"))
190 .size;
191 ty::Const::new_value(
192 tcx,
193 ty::ValTree::from_scalar_int(tcx, ScalarInt::try_from_uint(bits, size).unwrap()),
194 ty,
195 )
196 }
197
198 #[inline]
199 pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
201 ty::Const::new_value(tcx, ty::ValTree::zst(tcx), ty)
202 }
203
204 #[inline]
205 pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
207 Self::from_bits(tcx, v as u128, ty::TypingEnv::fully_monomorphized(), tcx.types.bool)
208 }
209
210 #[inline]
211 pub fn from_target_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
213 Self::from_bits(tcx, n as u128, ty::TypingEnv::fully_monomorphized(), tcx.types.usize)
214 }
215
216 pub fn to_value(self) -> ty::Value<'tcx> {
218 match self.kind() {
219 ty::ConstKind::Value(cv) => cv,
220 _ => bug!("expected ConstKind::Value, got {:?}", self.kind()),
221 }
222 }
223
224 pub fn try_to_value(self) -> Option<ty::Value<'tcx>> {
228 match self.kind() {
229 ty::ConstKind::Value(cv) => Some(cv),
230 _ => None,
231 }
232 }
233
234 #[inline]
239 pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
240 self.try_to_value()?.try_to_target_usize(tcx)
241 }
242
243 pub fn is_ct_infer(self) -> bool {
244 matches!(self.kind(), ty::ConstKind::Infer(_))
245 }
246}