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