1use std::{fmt, hash::Hash, num::NonZero};
2
3use intern::{Interned, InternedRef, impl_internable};
4use macros::{GenericTypeVisitable, TypeFoldable, TypeVisitable};
5use rustc_abi::{Size, TargetDataLayout};
6use rustc_type_ir::{GenericTypeVisitable, TypeFoldable, TypeVisitable, inherent::IntoKind};
7use stdx::never;
8
9use crate::{
10 MemoryMap, ParamEnvAndCrate, consteval,
11 db::HirDatabase,
12 mir::pad16,
13 next_solver::{Const, Consts, TyKind, WorldExposer},
14};
15
16use super::{DbInterner, Ty};
17
18pub type ValTreeKind<'db> = rustc_type_ir::ValTreeKind<DbInterner<'db>>;
19
20#[derive(
24 Debug, Copy, Clone, Eq, PartialEq, Hash, TypeFoldable, TypeVisitable, GenericTypeVisitable,
25)]
26pub struct ValueConst<'db> {
27 pub ty: Ty<'db>,
28 pub value: ValTree<'db>,
29}
30
31impl<'db> ValueConst<'db> {
32 pub fn new(ty: Ty<'db>, kind: ValTreeKind<'db>) -> Self {
33 let value = ValTree::new(kind);
34 ValueConst { ty, value }
35 }
36
37 pub fn try_to_leaf(self) -> Option<ScalarInt> {
39 match self.value.inner() {
40 ValTreeKind::Leaf(s) => Some(*s),
41 ValTreeKind::Branch(_) => None,
42 }
43 }
44
45 #[inline]
50 pub fn try_to_bits(
51 self,
52 db: &'db dyn HirDatabase,
53 param_env: ParamEnvAndCrate<'db>,
54 ) -> Option<u128> {
55 let (TyKind::Bool | TyKind::Char | TyKind::Uint(_) | TyKind::Int(_) | TyKind::Float(_)) =
56 self.ty.kind()
57 else {
58 return None;
59 };
60 let scalar = self.try_to_leaf()?;
61 let size = db.layout_of_ty(self.ty.store(), param_env.store()).ok()?.size;
62 Some(scalar.to_bits(size))
63 }
64}
65
66pub(super) fn allocation_to_const<'db>(
67 interner: DbInterner<'db>,
68 ty: Ty<'db>,
69 memory: &[u8],
70 memory_map: &MemoryMap<'db>,
71 param_env: ParamEnvAndCrate<'db>,
72) -> Const<'db> {
73 let Ok(data_layout) = interner.db.target_data_layout(param_env.krate) else {
74 return Const::error(interner);
75 };
76 let valtree = match ty.kind() {
77 TyKind::Bool => ValTreeKind::Leaf(ScalarInt::from(memory[0] != 0)),
78 TyKind::Char => {
79 let it = u128::from_le_bytes(pad16(memory, false)) as u32;
80 let Ok(c) = char::try_from(it) else {
81 return Const::error(interner);
82 };
83 ValTreeKind::Leaf(ScalarInt::from(c))
84 }
85 TyKind::Int(int) => {
86 let it = i128::from_le_bytes(pad16(memory, true));
87 let size = int.bit_width().map(Size::from_bits).unwrap_or(data_layout.pointer_size());
88 let scalar = ScalarInt::try_from_int(it, size).unwrap();
89 ValTreeKind::Leaf(scalar)
90 }
91 TyKind::Uint(uint) => {
92 let it = u128::from_le_bytes(pad16(memory, false));
93 let size = uint.bit_width().map(Size::from_bits).unwrap_or(data_layout.pointer_size());
94 let scalar = ScalarInt::try_from_uint(it, size).unwrap();
95 ValTreeKind::Leaf(scalar)
96 }
97 TyKind::Float(float) => {
98 let scalar = match float {
99 rustc_ast_ir::FloatTy::F16 => {
100 ScalarInt::from(u16::from_le_bytes(memory.try_into().unwrap()))
101 }
102 rustc_ast_ir::FloatTy::F32 => {
103 ScalarInt::from(u32::from_le_bytes(memory.try_into().unwrap()))
104 }
105 rustc_ast_ir::FloatTy::F64 => {
106 ScalarInt::from(u64::from_le_bytes(memory.try_into().unwrap()))
107 }
108 rustc_ast_ir::FloatTy::F128 => {
109 ScalarInt::from(u128::from_le_bytes(memory.try_into().unwrap()))
110 }
111 };
112 ValTreeKind::Leaf(scalar)
113 }
114 TyKind::Ref(_, t, _) => match t.kind() {
115 TyKind::Str => {
116 let addr = usize::from_le_bytes(memory[0..memory.len() / 2].try_into().unwrap());
117 let size = usize::from_le_bytes(memory[memory.len() / 2..].try_into().unwrap());
118 let Some(bytes) = memory_map.get(addr, size) else {
119 return Const::error(interner);
120 };
121 let u8_values = &interner.default_types().consts.u8_values;
122 ValTreeKind::Branch(Consts::new_from_iter(
123 interner,
124 bytes.iter().map(|&byte| u8_values[usize::from(byte)]),
125 ))
126 }
127 TyKind::Slice(ty) => {
128 let addr = usize::from_le_bytes(memory[0..memory.len() / 2].try_into().unwrap());
129 let count = usize::from_le_bytes(memory[memory.len() / 2..].try_into().unwrap());
130 let Ok(layout) = interner.db.layout_of_ty(ty.store(), param_env.store()) else {
131 return Const::error(interner);
132 };
133 let size_one = layout.size.bytes_usize();
134 let Some(bytes) = memory_map.get(addr, size_one * count) else {
135 return Const::error(interner);
136 };
137 let expected_len = count * size_one;
138 if bytes.len() < expected_len {
139 never!(
140 "Memory map size is too small. Expected {expected_len}, got {}",
141 bytes.len(),
142 );
143 return Const::error(interner);
144 }
145 let items = (0..count).map(|i| {
146 let offset = size_one * i;
147 let bytes = &bytes[offset..offset + size_one];
148 allocation_to_const(interner, ty, bytes, memory_map, param_env)
149 });
150 ValTreeKind::Branch(Consts::new_from_iter(interner, items))
151 }
152 TyKind::Dynamic(_, _) => {
153 let addr = usize::from_le_bytes(memory[0..memory.len() / 2].try_into().unwrap());
154 let ty_id = usize::from_le_bytes(memory[memory.len() / 2..].try_into().unwrap());
155 let Ok(t) = memory_map.vtable_ty(ty_id) else {
156 return Const::error(interner);
157 };
158 let Ok(layout) = interner.db.layout_of_ty(t.store(), param_env.store()) else {
159 return Const::error(interner);
160 };
161 let size = layout.size.bytes_usize();
162 let Some(bytes) = memory_map.get(addr, size) else {
163 return Const::error(interner);
164 };
165 return allocation_to_const(interner, t, bytes, memory_map, param_env);
166 }
167 TyKind::Adt(..) if memory.len() == 2 * size_of::<usize>() => {
168 return Const::error(interner);
170 }
171 _ => {
172 let addr = usize::from_le_bytes(match memory.try_into() {
173 Ok(b) => b,
174 Err(_) => {
175 never!(
176 "tried rendering ty {:?} in const ref with incorrect byte count {}",
177 t,
178 memory.len()
179 );
180 return Const::error(interner);
181 }
182 });
183 let Ok(layout) = interner.db.layout_of_ty(t.store(), param_env.store()) else {
184 return Const::error(interner);
185 };
186 let size = layout.size.bytes_usize();
187 let Some(bytes) = memory_map.get(addr, size) else {
188 return Const::error(interner);
189 };
190 return allocation_to_const(interner, t, bytes, memory_map, param_env);
191 }
192 },
193 TyKind::Tuple(tys) => {
194 let Ok(layout) = interner.db.layout_of_ty(ty.store(), param_env.store()) else {
195 return Const::error(interner);
196 };
197 let items = tys.iter().enumerate().map(|(id, ty)| {
198 let offset = layout.fields.offset(id).bytes_usize();
199 let Ok(layout) = interner.db.layout_of_ty(ty.store(), param_env.store()) else {
200 return Const::error(interner);
201 };
202 let size = layout.size.bytes_usize();
203 allocation_to_const(
204 interner,
205 ty,
206 &memory[offset..offset + size],
207 memory_map,
208 param_env,
209 )
210 });
211 ValTreeKind::Branch(Consts::new_from_iter(interner, items))
212 }
213 TyKind::Adt(..) => {
214 return Const::error(interner);
216 }
217 TyKind::FnDef(..) => {
218 return Const::error(interner);
220 }
221 TyKind::FnPtr(_, _) | TyKind::RawPtr(_, _) => {
222 let it = u128::from_le_bytes(pad16(memory, false));
223 let scalar = ScalarInt::try_from_uint(it, data_layout.pointer_size()).unwrap();
225 ValTreeKind::Leaf(scalar)
226 }
227 TyKind::Array(ty, len) => {
228 let Some(len) = consteval::try_const_usize(interner.db, len) else {
229 return Const::error(interner);
230 };
231 let Ok(layout) = interner.db.layout_of_ty(ty.store(), param_env.store()) else {
232 return Const::error(interner);
233 };
234 let size_one = layout.size.bytes_usize();
235 let items = (0..len as usize).map(|i| {
236 let offset = size_one * i;
237 allocation_to_const(
238 interner,
239 ty,
240 &memory[offset..offset + size_one],
241 memory_map,
242 param_env,
243 )
244 });
245 ValTreeKind::Branch(Consts::new_from_iter(interner, items))
246 }
247 TyKind::Never => return Const::error(interner),
248 TyKind::Closure(_, _)
250 | TyKind::Coroutine(_, _)
251 | TyKind::CoroutineWitness(_, _)
252 | TyKind::CoroutineClosure(_, _)
253 | TyKind::UnsafeBinder(_) => return Const::error(interner),
254 TyKind::Foreign(_) => return Const::error(interner),
256 TyKind::Pat(_, _) => return Const::error(interner),
257 TyKind::Error(..)
258 | TyKind::Placeholder(_)
259 | TyKind::Alias(..)
260 | TyKind::Param(_)
261 | TyKind::Bound(_, _)
262 | TyKind::Infer(_) => return Const::error(interner),
263 TyKind::Slice(_) | TyKind::Str | TyKind::Dynamic(_, _) => {
265 return Const::error(interner);
266 }
267 };
268 Const::new_valtree(interner, ty, valtree)
269}
270
271impl<'db> rustc_type_ir::inherent::ValueConst<DbInterner<'db>> for ValueConst<'db> {
272 fn ty(self) -> Ty<'db> {
273 self.ty
274 }
275
276 fn valtree(self) -> ValTree<'db> {
277 self.value
278 }
279}
280
281#[derive(Clone, Copy, PartialEq, Eq, Hash)]
282pub struct ValTree<'db> {
283 interned: InternedRef<'db, ValTreeInterned>,
284}
285
286impl<'db, V: WorldExposer> GenericTypeVisitable<V> for ValTree<'db> {
287 fn generic_visit_with(&self, visitor: &mut V) {
288 if visitor.on_interned(self.interned).is_continue() {
289 self.inner().generic_visit_with(visitor);
290 }
291 }
292}
293
294impl<'db> TypeVisitable<DbInterner<'db>> for ValTree<'db> {
295 fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
296 &self,
297 visitor: &mut V,
298 ) -> V::Result {
299 self.inner().visit_with(visitor)
300 }
301}
302
303impl<'db> TypeFoldable<DbInterner<'db>> for ValTree<'db> {
304 fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
305 self,
306 folder: &mut F,
307 ) -> Result<Self, F::Error> {
308 self.inner().try_fold_with(folder).map(ValTree::new)
309 }
310
311 fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
312 ValTree::new(self.inner().fold_with(folder))
313 }
314}
315
316#[derive(Debug, PartialEq, Eq, Hash, GenericTypeVisitable)]
317pub(in super::super) struct ValTreeInterned(ValTreeKind<'static>);
318
319impl_internable!(gc; ValTreeInterned);
320
321const _: () = {
322 const fn is_copy<T: Copy>() {}
323 is_copy::<ValTree<'static>>();
324};
325
326impl<'db> IntoKind for ValTree<'db> {
327 type Kind = ValTreeKind<'db>;
328
329 fn kind(self) -> Self::Kind {
330 *self.inner()
331 }
332}
333
334impl<'db> ValTree<'db> {
335 #[inline]
336 pub fn new(kind: ValTreeKind<'db>) -> Self {
337 let kind = unsafe { std::mem::transmute::<ValTreeKind<'db>, ValTreeKind<'static>>(kind) };
338 Self { interned: Interned::new_gc(ValTreeInterned(kind)) }
339 }
340
341 #[inline]
342 pub fn inner(&self) -> &ValTreeKind<'db> {
343 let inner = &self.interned.0;
344 unsafe { std::mem::transmute::<&ValTreeKind<'static>, &ValTreeKind<'db>>(inner) }
345 }
346}
347
348impl std::fmt::Debug for ValTree<'_> {
349 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
350 self.interned.fmt(f)
351 }
352}
353
354#[derive(Clone, Copy, Eq, PartialEq, Hash)]
359#[repr(Rust, packed)]
360pub struct ScalarInt {
361 data: u128,
364 size: NonZero<u8>,
365}
366
367impl ScalarInt {
368 pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: NonZero::new(1).unwrap() };
369 pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: NonZero::new(1).unwrap() };
370
371 fn raw(data: u128, size: Size) -> Self {
372 Self { data, size: NonZero::new(size.bytes() as u8).unwrap() }
373 }
374
375 #[inline]
376 pub fn size(self) -> Size {
377 Size::from_bytes(self.size.get())
378 }
379
380 #[inline(always)]
384 fn check_data(self) {
385 debug_assert_eq!(
391 self.size().truncate(self.data),
392 { self.data },
393 "Scalar value {:#x} exceeds size of {} bytes",
394 { self.data },
395 self.size
396 );
397 }
398
399 #[inline]
400 pub fn null(size: Size) -> Self {
401 Self::raw(0, size)
402 }
403
404 #[inline]
405 pub fn is_null(self) -> bool {
406 self.data == 0
407 }
408
409 #[inline]
410 pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
411 let (r, overflow) = Self::truncate_from_uint(i, size);
412 if overflow { None } else { Some(r) }
413 }
414
415 #[inline]
417 pub fn truncate_from_uint(i: impl Into<u128>, size: Size) -> (Self, bool) {
418 let data = i.into();
419 let r = Self::raw(size.truncate(data), size);
420 (r, r.data != data)
421 }
422
423 #[inline]
424 pub fn try_from_int(i: impl Into<i128>, size: Size) -> Option<Self> {
425 let (r, overflow) = Self::truncate_from_int(i, size);
426 if overflow { None } else { Some(r) }
427 }
428
429 #[inline]
431 pub fn truncate_from_int(i: impl Into<i128>, size: Size) -> (Self, bool) {
432 let data = i.into();
433 let r = Self::raw(size.truncate(data as u128), size);
435 (r, size.sign_extend(r.data) != data)
436 }
437
438 #[inline]
439 pub fn try_from_target_usize(
440 i: impl Into<u128>,
441 data_layout: &TargetDataLayout,
442 ) -> Option<Self> {
443 Self::try_from_uint(i, data_layout.pointer_size())
444 }
445
446 #[inline]
451 pub fn try_to_bits(self, target_size: Size) -> Result<u128, Size> {
452 assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
453 if target_size.bytes() == u64::from(self.size.get()) {
454 self.check_data();
455 Ok(self.data)
456 } else {
457 Err(self.size())
458 }
459 }
460
461 #[inline]
462 pub fn to_bits(self, target_size: Size) -> u128 {
463 self.try_to_bits(target_size).unwrap_or_else(|size| {
464 panic!("expected int of size {}, but got size {}", target_size.bytes(), size.bytes())
465 })
466 }
467
468 #[inline]
470 pub fn to_bits_unchecked(self) -> u128 {
471 self.check_data();
472 self.data
473 }
474
475 #[inline]
478 pub fn to_uint(self, size: Size) -> u128 {
479 self.to_bits(size)
480 }
481
482 #[inline]
483 pub fn to_uint_unchecked(self) -> u128 {
484 self.data
485 }
486
487 #[inline]
490 pub fn to_u8(self) -> u8 {
491 self.to_uint(Size::from_bits(8)).try_into().unwrap()
492 }
493
494 #[inline]
497 pub fn to_u16(self) -> u16 {
498 self.to_uint(Size::from_bits(16)).try_into().unwrap()
499 }
500
501 #[inline]
504 pub fn to_u32(self) -> u32 {
505 self.to_uint(Size::from_bits(32)).try_into().unwrap()
506 }
507
508 #[inline]
511 pub fn to_u64(self) -> u64 {
512 self.to_uint(Size::from_bits(64)).try_into().unwrap()
513 }
514
515 #[inline]
518 pub fn to_u128(self) -> u128 {
519 self.to_uint(Size::from_bits(128))
520 }
521
522 #[inline]
523 pub fn to_target_usize(&self, data_layout: &TargetDataLayout) -> u64 {
524 self.to_uint(data_layout.pointer_size()).try_into().unwrap()
525 }
526
527 #[inline]
531 pub fn try_to_bool(self) -> Result<bool, ()> {
532 match self.to_u8() {
533 0 => Ok(false),
534 1 => Ok(true),
535 _ => Err(()),
536 }
537 }
538
539 #[inline]
542 pub fn to_int(self, size: Size) -> i128 {
543 let b = self.to_bits(size);
544 size.sign_extend(b)
545 }
546
547 #[inline]
548 pub fn to_int_unchecked(self) -> i128 {
549 self.size().sign_extend(self.data)
550 }
551
552 pub fn to_i8(self) -> i8 {
555 self.to_int(Size::from_bits(8)).try_into().unwrap()
556 }
557
558 pub fn to_i16(self) -> i16 {
561 self.to_int(Size::from_bits(16)).try_into().unwrap()
562 }
563
564 pub fn to_i32(self) -> i32 {
567 self.to_int(Size::from_bits(32)).try_into().unwrap()
568 }
569
570 pub fn to_i64(self) -> i64 {
573 self.to_int(Size::from_bits(64)).try_into().unwrap()
574 }
575
576 pub fn to_i128(self) -> i128 {
579 self.to_int(Size::from_bits(128))
580 }
581
582 #[inline]
583 pub fn to_target_isize(&self, data_layout: &TargetDataLayout) -> i64 {
584 self.to_int(data_layout.pointer_size()).try_into().unwrap()
585 }
586}
587
588macro_rules! from_x_for_scalar_int {
589 ($($ty:ty),*) => {
590 $(
591 impl From<$ty> for ScalarInt {
592 #[inline]
593 fn from(u: $ty) -> Self {
594 Self {
595 data: u128::from(u),
596 size: NonZero::new(size_of::<$ty>() as u8).unwrap(),
597 }
598 }
599 }
600 )*
601 }
602}
603
604macro_rules! from_scalar_int_for_x {
605 ($($ty:ty),*) => {
606 $(
607 impl From<ScalarInt> for $ty {
608 #[inline]
609 fn from(int: ScalarInt) -> Self {
610 int.to_uint(Size::from_bytes(size_of::<$ty>()))
613 .try_into().unwrap()
614 }
615 }
616 )*
617 }
618}
619
620from_x_for_scalar_int!(u8, u16, u32, u64, u128, bool);
621from_scalar_int_for_x!(u8, u16, u32, u64, u128);
622
623impl TryFrom<ScalarInt> for bool {
624 type Error = ();
625 #[inline]
626 fn try_from(int: ScalarInt) -> Result<Self, ()> {
627 int.try_to_bool()
628 }
629}
630
631impl From<char> for ScalarInt {
632 #[inline]
633 fn from(c: char) -> Self {
634 (c as u32).into()
635 }
636}
637
638macro_rules! from_x_for_scalar_int_signed {
639 ($($ty:ty),*) => {
640 $(
641 impl From<$ty> for ScalarInt {
642 #[inline]
643 fn from(u: $ty) -> Self {
644 Self {
645 data: u128::from(u.cast_unsigned()), size: NonZero::new(size_of::<$ty>() as u8).unwrap(),
647 }
648 }
649 }
650 )*
651 }
652}
653
654macro_rules! from_scalar_int_for_x_signed {
655 ($($ty:ty),*) => {
656 $(
657 impl From<ScalarInt> for $ty {
658 #[inline]
659 fn from(int: ScalarInt) -> Self {
660 int.to_int(Size::from_bytes(size_of::<$ty>()))
663 .try_into().unwrap()
664 }
665 }
666 )*
667 }
668}
669
670from_x_for_scalar_int_signed!(i8, i16, i32, i64, i128);
671from_scalar_int_for_x_signed!(i8, i16, i32, i64, i128);
672
673impl From<std::cmp::Ordering> for ScalarInt {
674 #[inline]
675 fn from(c: std::cmp::Ordering) -> Self {
676 ScalarInt::from(c as i8)
678 }
679}
680
681#[derive(Debug)]
683pub struct CharTryFromScalarInt;
684
685impl TryFrom<ScalarInt> for char {
686 type Error = CharTryFromScalarInt;
687
688 #[inline]
689 fn try_from(int: ScalarInt) -> Result<Self, Self::Error> {
690 match char::from_u32(int.to_u32()) {
691 Some(c) => Ok(c),
692 None => Err(CharTryFromScalarInt),
693 }
694 }
695}
696
697impl fmt::Debug for ScalarInt {
698 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
699 write!(f, "0x{self:x}")
701 }
702}
703
704impl fmt::LowerHex for ScalarInt {
705 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
706 self.check_data();
707 if f.alternate() {
708 write!(f, "0x")?;
710 }
711 write!(f, "{:01$x}", { self.data }, self.size.get() as usize * 2)
719 }
720}
721
722impl fmt::UpperHex for ScalarInt {
723 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
724 self.check_data();
725 write!(f, "{:01$X}", { self.data }, self.size.get() as usize * 2)
733 }
734}
735
736impl fmt::Display for ScalarInt {
737 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
738 self.check_data();
739 write!(f, "{}", { self.data })
740 }
741}