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