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