1mod valtree;
4
5use std::hash::Hash;
6
7use hir_def::ConstParamId;
8use intern::{Interned, InternedRef, impl_internable};
9use macros::{GenericTypeVisitable, TypeFoldable, TypeVisitable};
10use rustc_abi::TargetDataLayout;
11use rustc_ast_ir::visit::VisitorResult;
12use rustc_type_ir::{
13 BoundVar, BoundVarIndexKind, ConstVid, DebruijnIndex, FlagComputation, Flags,
14 GenericTypeVisitable, InferConst, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable,
15 TypeVisitable, TypeVisitableExt, WithCachedTypeInfo, inherent::IntoKind, relate::Relate,
16};
17
18use crate::{
19 ParamEnvAndCrate,
20 next_solver::{
21 AllocationData, ClauseKind, ParamEnv, impl_foldable_for_interned_slice,
22 impl_stored_interned, interned_slice,
23 },
24};
25
26use super::{DbInterner, ErrorGuaranteed, GenericArgs, Ty};
27
28pub use self::valtree::*;
29
30pub type ConstKind<'db> = rustc_type_ir::ConstKind<DbInterner<'db>>;
31pub type UnevaluatedConst<'db> = rustc_type_ir::UnevaluatedConst<DbInterner<'db>>;
32
33#[derive(Clone, Copy, PartialEq, Eq, Hash)]
34pub struct Const<'db> {
35 pub(super) interned: InternedRef<'db, ConstInterned>,
36}
37
38#[derive(PartialEq, Eq, Hash, GenericTypeVisitable)]
39#[repr(align(4))] pub(super) struct ConstInterned(pub(super) WithCachedTypeInfo<ConstKind<'static>>);
41
42impl_internable!(gc; ConstInterned);
43impl_stored_interned!(ConstInterned, Const, StoredConst);
44
45const _: () = {
46 const fn is_copy<T: Copy>() {}
47 is_copy::<Const<'static>>();
48};
49
50impl<'db> Const<'db> {
51 pub fn new(_interner: DbInterner<'db>, kind: ConstKind<'db>) -> Self {
52 let kind = unsafe { std::mem::transmute::<ConstKind<'db>, ConstKind<'static>>(kind) };
53 let flags = FlagComputation::for_const_kind(&kind);
54 let cached = WithCachedTypeInfo {
55 internee: kind,
56 flags: flags.flags,
57 outer_exclusive_binder: flags.outer_exclusive_binder,
58 };
59 Self { interned: Interned::new_gc(ConstInterned(cached)) }
60 }
61
62 pub fn inner(&self) -> &WithCachedTypeInfo<ConstKind<'db>> {
63 let inner = &self.interned.0;
64 unsafe {
65 std::mem::transmute::<
66 &WithCachedTypeInfo<ConstKind<'static>>,
67 &WithCachedTypeInfo<ConstKind<'db>>,
68 >(inner)
69 }
70 }
71
72 pub fn error(interner: DbInterner<'db>) -> Self {
73 interner.default_types().consts.error
74 }
75
76 pub fn new_param(interner: DbInterner<'db>, param: ParamConst) -> Self {
77 Const::new(interner, ConstKind::Param(param))
78 }
79
80 pub fn new_placeholder(interner: DbInterner<'db>, placeholder: PlaceholderConst<'db>) -> Self {
81 Const::new(interner, ConstKind::Placeholder(placeholder))
82 }
83
84 pub fn new_bound(
85 interner: DbInterner<'db>,
86 index: DebruijnIndex,
87 bound: BoundConst<'db>,
88 ) -> Self {
89 Const::new(interner, ConstKind::Bound(BoundVarIndexKind::Bound(index), bound))
90 }
91
92 pub fn new_valtree(interner: DbInterner<'db>, ty: Ty<'db>, kind: ValTreeKind<'db>) -> Self {
93 Const::new(interner, ConstKind::Value(ValueConst { ty, value: ValTree::new(kind) }))
94 }
95
96 pub fn new_value(interner: DbInterner<'db>, valtree: ValTree<'db>, ty: Ty<'db>) -> Self {
97 Const::new(interner, ConstKind::Value(ValueConst { ty, value: valtree }))
98 }
99
100 pub fn new_from_allocation(
101 interner: DbInterner<'db>,
102 allocation: &AllocationData<'db>,
103 param_env: ParamEnvAndCrate<'db>,
104 ) -> Self {
105 allocation_to_const(
106 interner,
107 allocation.ty,
108 &allocation.memory,
109 &allocation.memory_map,
110 param_env,
111 )
112 }
113
114 #[inline]
115 pub fn from_target_usize(interner: DbInterner<'db>, n: u64) -> Self {
117 let usize_ty = interner.default_types().types.usize;
118 let data_layout = interner.db.target_data_layout_or_default(interner.expect_crate());
119 Const::new_value(
120 interner,
121 ValTree::from_scalar_int(
122 interner,
123 ScalarInt::try_from_target_usize(n, data_layout).unwrap(),
124 ),
125 usize_ty,
126 )
127 }
128
129 pub fn is_ct_infer(&self) -> bool {
130 matches!(self.kind(), ConstKind::Infer(_))
131 }
132
133 pub fn is_error(&self) -> bool {
134 matches!(self.kind(), ConstKind::Error(_))
135 }
136
137 pub fn is_trivially_wf(self) -> bool {
138 match self.kind() {
139 ConstKind::Param(_) | ConstKind::Placeholder(_) | ConstKind::Bound(..) => true,
140 ConstKind::Infer(_)
141 | ConstKind::Unevaluated(..)
142 | ConstKind::Value(_)
143 | ConstKind::Error(_)
144 | ConstKind::Expr(_) => false,
145 }
146 }
147
148 pub fn try_to_value(self) -> Option<ValueConst<'db>> {
152 match self.kind() {
153 ConstKind::Value(cv) => Some(cv),
154 _ => None,
155 }
156 }
157
158 #[inline]
163 pub fn try_to_target_usize(self, data_layout: &TargetDataLayout) -> Option<u64> {
164 self.try_to_value()?.try_to_target_usize(data_layout)
165 }
166}
167
168impl<'db> std::fmt::Debug for Const<'db> {
169 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
170 self.inner().internee.fmt(f)
171 }
172}
173
174pub type PlaceholderConst<'db> = rustc_type_ir::PlaceholderConst<DbInterner<'db>>;
175
176#[derive(Copy, Clone, Hash, Eq, PartialEq)]
177pub struct ParamConst {
178 pub id: ConstParamId,
180 pub index: u32,
181}
182
183impl std::fmt::Debug for ParamConst {
184 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
185 write!(f, "#{}", self.index)
186 }
187}
188
189impl ParamConst {
190 pub fn find_const_ty_from_env<'db>(self, env: ParamEnv<'db>) -> Ty<'db> {
191 let mut candidates = env.clauses.iter().filter_map(|clause| {
192 match clause.kind().skip_binder() {
194 ClauseKind::ConstArgHasType(param_ct, ty) => {
195 assert!(!(param_ct, ty).has_escaping_bound_vars());
196
197 match param_ct.kind() {
198 ConstKind::Param(param_ct) if param_ct.index == self.index => Some(ty),
199 _ => None,
200 }
201 }
202 _ => None,
203 }
204 });
205
206 let ty = candidates.next().unwrap_or_else(|| {
213 panic!("cannot find `{self:?}` in param-env: {env:#?}");
214 });
215 assert!(
216 candidates.next().is_none(),
217 "did not expect duplicate `ConstParamHasTy` for `{self:?}` in param-env: {env:#?}"
218 );
219 ty
220 }
221}
222
223#[derive(
224 Copy, Clone, Debug, Hash, PartialEq, Eq, TypeVisitable, TypeFoldable, GenericTypeVisitable,
225)]
226pub struct ExprConst;
227
228impl rustc_type_ir::inherent::ParamLike for ParamConst {
229 fn index(self) -> u32 {
230 self.index
231 }
232}
233
234impl<'db> IntoKind for Const<'db> {
235 type Kind = ConstKind<'db>;
236
237 fn kind(self) -> Self::Kind {
238 self.inner().internee
239 }
240}
241
242impl<'db, V: super::WorldExposer> GenericTypeVisitable<V> for Const<'db> {
243 fn generic_visit_with(&self, visitor: &mut V) {
244 if visitor.on_interned(self.interned).is_continue() {
245 self.kind().generic_visit_with(visitor);
246 }
247 }
248}
249
250impl<'db> TypeVisitable<DbInterner<'db>> for Const<'db> {
251 fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
252 &self,
253 visitor: &mut V,
254 ) -> V::Result {
255 visitor.visit_const(*self)
256 }
257}
258
259impl<'db> TypeSuperVisitable<DbInterner<'db>> for Const<'db> {
260 fn super_visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
261 &self,
262 visitor: &mut V,
263 ) -> V::Result {
264 match self.kind() {
265 ConstKind::Unevaluated(uv) => uv.visit_with(visitor),
266 ConstKind::Value(v) => v.visit_with(visitor),
267 ConstKind::Expr(e) => e.visit_with(visitor),
268 ConstKind::Error(e) => e.visit_with(visitor),
269
270 ConstKind::Param(_)
271 | ConstKind::Infer(_)
272 | ConstKind::Bound(..)
273 | ConstKind::Placeholder(_) => V::Result::output(),
274 }
275 }
276}
277
278impl<'db> TypeFoldable<DbInterner<'db>> for Const<'db> {
279 fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
280 self,
281 folder: &mut F,
282 ) -> Result<Self, F::Error> {
283 folder.try_fold_const(self)
284 }
285 fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
286 folder.fold_const(self)
287 }
288}
289
290impl<'db> TypeSuperFoldable<DbInterner<'db>> for Const<'db> {
291 fn try_super_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
292 self,
293 folder: &mut F,
294 ) -> Result<Self, F::Error> {
295 let kind = match self.kind() {
296 ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.try_fold_with(folder)?),
297 ConstKind::Value(v) => ConstKind::Value(v.try_fold_with(folder)?),
298 ConstKind::Expr(e) => ConstKind::Expr(e.try_fold_with(folder)?),
299
300 ConstKind::Param(_)
301 | ConstKind::Infer(_)
302 | ConstKind::Bound(..)
303 | ConstKind::Placeholder(_)
304 | ConstKind::Error(_) => return Ok(self),
305 };
306 if kind != self.kind() { Ok(Const::new(folder.cx(), kind)) } else { Ok(self) }
307 }
308 fn super_fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(
309 self,
310 folder: &mut F,
311 ) -> Self {
312 let kind = match self.kind() {
313 ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.fold_with(folder)),
314 ConstKind::Value(v) => ConstKind::Value(v.fold_with(folder)),
315 ConstKind::Expr(e) => ConstKind::Expr(e.fold_with(folder)),
316
317 ConstKind::Param(_)
318 | ConstKind::Infer(_)
319 | ConstKind::Bound(..)
320 | ConstKind::Placeholder(_)
321 | ConstKind::Error(_) => return self,
322 };
323 if kind != self.kind() { Const::new(folder.cx(), kind) } else { self }
324 }
325}
326
327impl<'db> Relate<DbInterner<'db>> for Const<'db> {
328 fn relate<R: rustc_type_ir::relate::TypeRelation<DbInterner<'db>>>(
329 relation: &mut R,
330 a: Self,
331 b: Self,
332 ) -> rustc_type_ir::relate::RelateResult<DbInterner<'db>, Self> {
333 relation.consts(a, b)
334 }
335}
336
337impl<'db> Flags for Const<'db> {
338 fn flags(&self) -> rustc_type_ir::TypeFlags {
339 self.inner().flags
340 }
341
342 fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex {
343 self.inner().outer_exclusive_binder
344 }
345}
346
347impl<'db> rustc_type_ir::inherent::Const<DbInterner<'db>> for Const<'db> {
348 fn new_infer(interner: DbInterner<'db>, var: InferConst) -> Self {
349 Const::new(interner, ConstKind::Infer(var))
350 }
351
352 fn new_var(interner: DbInterner<'db>, var: ConstVid) -> Self {
353 Const::new(interner, ConstKind::Infer(InferConst::Var(var)))
354 }
355
356 fn new_bound(interner: DbInterner<'db>, debruijn: DebruijnIndex, var: BoundConst<'db>) -> Self {
357 Const::new(interner, ConstKind::Bound(BoundVarIndexKind::Bound(debruijn), var))
358 }
359
360 fn new_anon_bound(interner: DbInterner<'db>, debruijn: DebruijnIndex, var: BoundVar) -> Self {
361 Const::new(
362 interner,
363 ConstKind::Bound(BoundVarIndexKind::Bound(debruijn), BoundConst::new(var)),
364 )
365 }
366
367 fn new_canonical_bound(interner: DbInterner<'db>, var: BoundVar) -> Self {
368 Const::new(interner, ConstKind::Bound(BoundVarIndexKind::Canonical, BoundConst::new(var)))
369 }
370
371 fn new_placeholder(interner: DbInterner<'db>, param: PlaceholderConst<'db>) -> Self {
372 Const::new(interner, ConstKind::Placeholder(param))
373 }
374
375 fn new_unevaluated(
376 interner: DbInterner<'db>,
377 uv: rustc_type_ir::UnevaluatedConst<DbInterner<'db>>,
378 ) -> Self {
379 Const::new(interner, ConstKind::Unevaluated(uv))
380 }
381
382 fn new_expr(interner: DbInterner<'db>, expr: ExprConst) -> Self {
383 Const::new(interner, ConstKind::Expr(expr))
384 }
385
386 fn new_error(interner: DbInterner<'db>, _guar: ErrorGuaranteed) -> Self {
387 Const::error(interner)
388 }
389}
390
391pub type BoundConst<'db> = rustc_type_ir::BoundConst<DbInterner<'db>>;
392
393impl<'db> Relate<DbInterner<'db>> for ExprConst {
394 fn relate<R: rustc_type_ir::relate::TypeRelation<DbInterner<'db>>>(
395 _relation: &mut R,
396 a: Self,
397 b: Self,
398 ) -> rustc_type_ir::relate::RelateResult<DbInterner<'db>, Self> {
399 let ExprConst = b;
401 Ok(a)
402 }
403}
404
405impl<'db> rustc_type_ir::inherent::ExprConst<DbInterner<'db>> for ExprConst {
406 fn args(self) -> <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs {
407 let ExprConst = self;
409 GenericArgs::default()
410 }
411}
412
413interned_slice!(ConstsStorage, Consts, StoredConsts, consts, Const<'db>, Const<'static>);
414impl_foldable_for_interned_slice!(Consts);