1use std::hash::Hash;
4
5use hir_def::{ConstParamId, TypeOrConstParamId};
6use intern::{Interned, Symbol};
7use rustc_ast_ir::try_visit;
8use rustc_ast_ir::visit::VisitorResult;
9use rustc_type_ir::{
10 BoundVar, FlagComputation, Flags, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable,
11 TypeVisitable, WithCachedTypeInfo,
12 inherent::{IntoKind, PlaceholderLike},
13 relate::Relate,
14};
15
16use crate::{ConstScalar, MemoryMap, interner::InternedWrapperNoDebug};
17
18use super::{BoundVarKind, DbInterner, ErrorGuaranteed, GenericArgs, Placeholder, Ty};
19
20pub type ConstKind<'db> = rustc_type_ir::ConstKind<DbInterner<'db>>;
21pub type UnevaluatedConst<'db> = rustc_type_ir::UnevaluatedConst<DbInterner<'db>>;
22
23#[salsa::interned(constructor = new_, debug)]
24pub struct Const<'db> {
25 #[returns(ref)]
26 kind_: InternedWrapperNoDebug<WithCachedTypeInfo<ConstKind<'db>>>,
27}
28
29impl<'db> Const<'db> {
30 pub fn new(interner: DbInterner<'db>, kind: ConstKind<'db>) -> Self {
31 let flags = FlagComputation::for_const_kind(&kind);
32 let cached = WithCachedTypeInfo {
33 internee: kind,
34 flags: flags.flags,
35 outer_exclusive_binder: flags.outer_exclusive_binder,
36 };
37 Const::new_(interner.db(), InternedWrapperNoDebug(cached))
38 }
39
40 pub fn inner(&self) -> &WithCachedTypeInfo<ConstKind<'db>> {
41 salsa::with_attached_database(|db| {
42 let inner = &self.kind_(db).0;
43 unsafe { std::mem::transmute(inner) }
46 })
47 .unwrap()
48 }
49
50 pub fn error(interner: DbInterner<'db>) -> Self {
51 Const::new(interner, rustc_type_ir::ConstKind::Error(ErrorGuaranteed))
52 }
53
54 pub fn new_param(interner: DbInterner<'db>, param: ParamConst) -> Self {
55 Const::new(interner, rustc_type_ir::ConstKind::Param(param))
56 }
57
58 pub fn new_placeholder(interner: DbInterner<'db>, placeholder: PlaceholderConst) -> Self {
59 Const::new(interner, ConstKind::Placeholder(placeholder))
60 }
61
62 pub fn is_ct_infer(&self) -> bool {
63 matches!(&self.inner().internee, ConstKind::Infer(_))
64 }
65
66 pub fn is_trivially_wf(self) -> bool {
67 match self.kind() {
68 ConstKind::Param(_) | ConstKind::Placeholder(_) | ConstKind::Bound(..) => true,
69 ConstKind::Infer(_)
70 | ConstKind::Unevaluated(..)
71 | ConstKind::Value(_)
72 | ConstKind::Error(_)
73 | ConstKind::Expr(_) => false,
74 }
75 }
76}
77
78impl<'db> std::fmt::Debug for InternedWrapperNoDebug<WithCachedTypeInfo<ConstKind<'db>>> {
79 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80 self.0.internee.fmt(f)
81 }
82}
83
84pub type PlaceholderConst = Placeholder<rustc_type_ir::BoundVar>;
85
86#[derive(Copy, Clone, Hash, Eq, PartialEq)]
87pub struct ParamConst {
88 pub id: ConstParamId,
90 pub index: u32,
91}
92
93impl std::fmt::Debug for ParamConst {
94 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95 write!(f, "#{}", self.index)
96 }
97}
98
99#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
103pub struct ValueConst<'db> {
104 pub(crate) ty: Ty<'db>,
105 pub(crate) value: Valtree<'db>,
106}
107
108impl<'db> ValueConst<'db> {
109 pub fn new(ty: Ty<'db>, bytes: ConstBytes<'db>) -> Self {
110 let value = Valtree::new(bytes);
111 ValueConst { ty, value }
112 }
113}
114
115impl<'db> rustc_type_ir::inherent::ValueConst<DbInterner<'db>> for ValueConst<'db> {
116 fn ty(self) -> Ty<'db> {
117 self.ty
118 }
119
120 fn valtree(self) -> Valtree<'db> {
121 self.value
122 }
123}
124
125impl<'db> rustc_type_ir::TypeVisitable<DbInterner<'db>> for ValueConst<'db> {
126 fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
127 &self,
128 visitor: &mut V,
129 ) -> V::Result {
130 self.ty.visit_with(visitor)
131 }
132}
133
134impl<'db> rustc_type_ir::TypeFoldable<DbInterner<'db>> for ValueConst<'db> {
135 fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
136 ValueConst { ty: self.ty.fold_with(folder), value: self.value }
137 }
138 fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
139 self,
140 folder: &mut F,
141 ) -> Result<Self, F::Error> {
142 Ok(ValueConst { ty: self.ty.try_fold_with(folder)?, value: self.value })
143 }
144}
145
146#[derive(Debug, Clone, PartialEq, Eq)]
147pub struct ConstBytes<'db>(pub Box<[u8]>, pub MemoryMap<'db>);
148
149impl Hash for ConstBytes<'_> {
150 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
151 self.0.hash(state)
152 }
153}
154
155#[salsa::interned(constructor = new_, debug)]
156pub struct Valtree<'db> {
157 #[returns(ref)]
158 bytes_: ConstBytes<'db>,
159}
160
161impl<'db> Valtree<'db> {
162 pub fn new(bytes: ConstBytes<'db>) -> Self {
163 salsa::with_attached_database(|db| unsafe {
164 std::mem::transmute(Valtree::new_(db, bytes))
166 })
167 .unwrap()
168 }
169
170 pub fn inner(&self) -> &ConstBytes<'db> {
171 salsa::with_attached_database(|db| {
172 let inner = self.bytes_(db);
173 unsafe { std::mem::transmute(inner) }
176 })
177 .unwrap()
178 }
179}
180
181#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
182pub struct ExprConst;
183
184impl rustc_type_ir::inherent::ParamLike for ParamConst {
185 fn index(self) -> u32 {
186 self.index
187 }
188}
189
190impl<'db> IntoKind for Const<'db> {
191 type Kind = ConstKind<'db>;
192
193 fn kind(self) -> Self::Kind {
194 self.inner().internee
195 }
196}
197
198impl<'db> TypeVisitable<DbInterner<'db>> for Const<'db> {
199 fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
200 &self,
201 visitor: &mut V,
202 ) -> V::Result {
203 visitor.visit_const(*self)
204 }
205}
206
207impl<'db> TypeSuperVisitable<DbInterner<'db>> for Const<'db> {
208 fn super_visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
209 &self,
210 visitor: &mut V,
211 ) -> V::Result {
212 match self.kind() {
213 ConstKind::Unevaluated(uv) => uv.visit_with(visitor),
214 ConstKind::Value(v) => v.visit_with(visitor),
215 ConstKind::Expr(e) => e.visit_with(visitor),
216 ConstKind::Error(e) => e.visit_with(visitor),
217
218 ConstKind::Param(_)
219 | ConstKind::Infer(_)
220 | ConstKind::Bound(..)
221 | ConstKind::Placeholder(_) => V::Result::output(),
222 }
223 }
224}
225
226impl<'db> TypeFoldable<DbInterner<'db>> for Const<'db> {
227 fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
228 self,
229 folder: &mut F,
230 ) -> Result<Self, F::Error> {
231 folder.try_fold_const(self)
232 }
233 fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
234 folder.fold_const(self)
235 }
236}
237
238impl<'db> TypeSuperFoldable<DbInterner<'db>> for Const<'db> {
239 fn try_super_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
240 self,
241 folder: &mut F,
242 ) -> Result<Self, F::Error> {
243 let kind = match self.kind() {
244 ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.try_fold_with(folder)?),
245 ConstKind::Value(v) => ConstKind::Value(v.try_fold_with(folder)?),
246 ConstKind::Expr(e) => ConstKind::Expr(e.try_fold_with(folder)?),
247
248 ConstKind::Param(_)
249 | ConstKind::Infer(_)
250 | ConstKind::Bound(..)
251 | ConstKind::Placeholder(_)
252 | ConstKind::Error(_) => return Ok(self),
253 };
254 if kind != self.kind() { Ok(Const::new(folder.cx(), kind)) } else { Ok(self) }
255 }
256 fn super_fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(
257 self,
258 folder: &mut F,
259 ) -> Self {
260 let kind = match self.kind() {
261 ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.fold_with(folder)),
262 ConstKind::Value(v) => ConstKind::Value(v.fold_with(folder)),
263 ConstKind::Expr(e) => ConstKind::Expr(e.fold_with(folder)),
264
265 ConstKind::Param(_)
266 | ConstKind::Infer(_)
267 | ConstKind::Bound(..)
268 | ConstKind::Placeholder(_)
269 | ConstKind::Error(_) => return self,
270 };
271 if kind != self.kind() { Const::new(folder.cx(), kind) } else { self }
272 }
273}
274
275impl<'db> Relate<DbInterner<'db>> for Const<'db> {
276 fn relate<R: rustc_type_ir::relate::TypeRelation<DbInterner<'db>>>(
277 relation: &mut R,
278 a: Self,
279 b: Self,
280 ) -> rustc_type_ir::relate::RelateResult<DbInterner<'db>, Self> {
281 relation.consts(a, b)
282 }
283}
284
285impl<'db> Flags for Const<'db> {
286 fn flags(&self) -> rustc_type_ir::TypeFlags {
287 self.inner().flags
288 }
289
290 fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex {
291 self.inner().outer_exclusive_binder
292 }
293}
294
295impl<'db> rustc_type_ir::inherent::Const<DbInterner<'db>> for Const<'db> {
296 fn new_infer(interner: DbInterner<'db>, var: rustc_type_ir::InferConst) -> Self {
297 Const::new(interner, ConstKind::Infer(var))
298 }
299
300 fn new_var(interner: DbInterner<'db>, var: rustc_type_ir::ConstVid) -> Self {
301 Const::new(interner, ConstKind::Infer(rustc_type_ir::InferConst::Var(var)))
302 }
303
304 fn new_bound(
305 interner: DbInterner<'db>,
306 debruijn: rustc_type_ir::DebruijnIndex,
307 var: BoundVar,
308 ) -> Self {
309 Const::new(interner, ConstKind::Bound(debruijn, var))
310 }
311
312 fn new_anon_bound(
313 interner: DbInterner<'db>,
314 debruijn: rustc_type_ir::DebruijnIndex,
315 var: rustc_type_ir::BoundVar,
316 ) -> Self {
317 Const::new(interner, ConstKind::Bound(debruijn, var))
318 }
319
320 fn new_unevaluated(
321 interner: DbInterner<'db>,
322 uv: rustc_type_ir::UnevaluatedConst<DbInterner<'db>>,
323 ) -> Self {
324 Const::new(interner, ConstKind::Unevaluated(uv))
325 }
326
327 fn new_expr(interner: DbInterner<'db>, expr: ExprConst) -> Self {
328 Const::new(interner, ConstKind::Expr(expr))
329 }
330
331 fn new_error(interner: DbInterner<'db>, guar: ErrorGuaranteed) -> Self {
332 Const::new(interner, ConstKind::Error(guar))
333 }
334
335 fn new_placeholder(
336 interner: DbInterner<'db>,
337 param: <DbInterner<'db> as rustc_type_ir::Interner>::PlaceholderConst,
338 ) -> Self {
339 Const::new(interner, ConstKind::Placeholder(param))
340 }
341}
342
343impl<'db> PlaceholderLike<DbInterner<'db>> for PlaceholderConst {
344 type Bound = rustc_type_ir::BoundVar;
345
346 fn universe(self) -> rustc_type_ir::UniverseIndex {
347 self.universe
348 }
349
350 fn var(self) -> rustc_type_ir::BoundVar {
351 self.bound
352 }
353
354 fn with_updated_universe(self, ui: rustc_type_ir::UniverseIndex) -> Self {
355 Placeholder { universe: ui, bound: self.bound }
356 }
357
358 fn new(ui: rustc_type_ir::UniverseIndex, var: rustc_type_ir::BoundVar) -> Self {
359 Placeholder { universe: ui, bound: var }
360 }
361 fn new_anon(ui: rustc_type_ir::UniverseIndex, var: rustc_type_ir::BoundVar) -> Self {
362 Placeholder { universe: ui, bound: var }
363 }
364}
365
366impl<'db> TypeVisitable<DbInterner<'db>> for ExprConst {
367 fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
368 &self,
369 visitor: &mut V,
370 ) -> V::Result {
371 let ExprConst = &self;
373 V::Result::output()
374 }
375}
376
377impl<'db> TypeFoldable<DbInterner<'db>> for ExprConst {
378 fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
379 self,
380 folder: &mut F,
381 ) -> Result<Self, F::Error> {
382 Ok(ExprConst)
383 }
384 fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
385 ExprConst
386 }
387}
388
389impl<'db> Relate<DbInterner<'db>> for ExprConst {
390 fn relate<R: rustc_type_ir::relate::TypeRelation<DbInterner<'db>>>(
391 relation: &mut R,
392 a: Self,
393 b: Self,
394 ) -> rustc_type_ir::relate::RelateResult<DbInterner<'db>, Self> {
395 let ExprConst = b;
397 Ok(a)
398 }
399}
400
401impl<'db> rustc_type_ir::inherent::ExprConst<DbInterner<'db>> for ExprConst {
402 fn args(self) -> <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs {
403 let ExprConst = self;
405 GenericArgs::default()
406 }
407}