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