swamp_vm_types/
types.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use crate::{
6    AggregateMemoryLocation, CountU16, FrameMemoryAddress, FrameMemoryRegion, FrameMemorySize,
7    InstructionPositionOffset, InstructionRange, MemoryLocation, align_to,
8};
9use fxhash::FxHasher;
10use seq_fmt::comma;
11use std::cmp::{Ordering, max};
12use std::fmt::{Debug, Display, Formatter, Write};
13use std::hash::{Hash, Hasher};
14use std::rc::Rc;
15use swamp_vm_isa::{
16    HEAP_PTR_ON_FRAME_ALIGNMENT, HEAP_PTR_ON_FRAME_SIZE, HeapMemoryAddress, HeapMemoryRegion,
17    InstructionPosition, MAP_HEADER_ALIGNMENT, MAP_HEADER_SIZE, MAP_ITERATOR_ALIGNMENT,
18    MAP_ITERATOR_SIZE, MemoryAlignment, MemoryOffset, MemorySize, ProgramCounterDelta,
19    RANGE_HEADER_ALIGNMENT, RANGE_HEADER_SIZE, RANGE_ITERATOR_ALIGNMENT, RANGE_ITERATOR_SIZE,
20    RegIndex, STRING_PTR_ALIGNMENT, STRING_PTR_SIZE, VEC_HEADER_SIZE, VEC_ITERATOR_ALIGNMENT,
21    VEC_ITERATOR_SIZE, VEC_PTR_ALIGNMENT, VEC_PTR_SIZE,
22};
23use tracing::error;
24use yansi::Paint;
25
26pub type BasicTypeRef = Rc<BasicType>;
27
28#[derive(Clone, Debug)]
29pub struct OffsetMemoryItem {
30    pub offset: MemoryOffset,
31    pub size: MemorySize,
32    pub name: String,
33    pub ty: BasicTypeRef,
34}
35
36impl Display for OffsetMemoryItem {
37    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
38        write!(f, "{}:{}", self.name, self.ty)
39    }
40}
41
42#[derive(Clone, Debug)]
43pub struct StructType {
44    pub name: String,
45    pub fields: Vec<OffsetMemoryItem>,
46    pub total_size: MemorySize,
47    pub max_alignment: MemoryAlignment,
48}
49
50impl Display for StructType {
51    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
52        write!(f, "{}", self.name)?;
53        for field in &self.fields {
54            write!(
55                f,
56                "{:04X}:{:X} {}:{}",
57                field.offset.0, field.size.0, field.name, field.ty
58            )?;
59        }
60        Ok(())
61    }
62}
63
64#[derive(Clone, Debug)]
65pub struct TupleType {
66    pub fields: Vec<OffsetMemoryItem>,
67    pub total_size: MemorySize,
68    pub max_alignment: MemoryAlignment,
69}
70
71impl TupleType {
72    #[must_use]
73    pub fn aligned_size_of_field(&self, field_index: usize) -> MemorySize {
74        let max_alignment: usize = self.max_alignment.into();
75        MemorySize(max(self.fields[field_index].size.0 as usize, max_alignment) as u32)
76    }
77}
78
79impl Display for TupleType {
80    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
81        for field in &self.fields {
82            write!(f, "{:04X}:{:X} {}", field.offset.0, field.size.0, field.ty)?;
83        }
84        Ok(())
85    }
86}
87
88#[derive(Clone, Debug)]
89pub struct TaggedUnionVariant {
90    pub name: String,     // e.g., "None", "Some"
91    pub ty: BasicTypeRef, // the payload type (could be unit/empty)
92}
93
94impl Display for TaggedUnionVariant {
95    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
96        write!(f, "{}: {}", self.name, self.ty)
97    }
98}
99
100#[derive(Clone, Debug)]
101pub struct TaggedUnion {
102    pub name: String,
103    pub tag_offset: MemoryOffset, // should always be 0
104    pub tag_alignment: MemoryAlignment,
105    pub tag_size: MemorySize,
106    pub payload_max_size: MemorySize,
107    pub max_payload_alignment: MemoryAlignment,
108    pub payload_offset: MemoryOffset,
109    pub variants: Vec<TaggedUnionVariant>,
110    pub total_size: MemorySize,
111    pub max_alignment: MemoryAlignment,
112}
113
114impl Display for TaggedUnion {
115    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
116        write!(f, "union {}:", self.name,)?;
117        for (offset, variant) in self.variants.iter().enumerate() {
118            writeln!(f, "  {offset}: {variant}")?;
119        }
120        Ok(())
121    }
122}
123
124impl TaggedUnion {
125    #[must_use]
126    pub fn payload_offset(&self) -> MemoryOffset {
127        align_to(MemoryOffset(self.tag_size.0), self.max_alignment)
128    }
129}
130
131impl TaggedUnion {
132    #[must_use]
133    pub fn get_variant_by_index(&self, index: usize) -> &TaggedUnionVariant {
134        debug_assert!(
135            index < self.variants.len(),
136            "variant out of bounds {index} out of {}",
137            self.variants.len()
138        );
139        &self.variants[index]
140    }
141
142    #[must_use]
143    pub fn get_variant_as_offset_item(&self, index: usize) -> OffsetMemoryItem {
144        let variant = self.get_variant_by_index(index);
145        OffsetMemoryItem {
146            offset: self.payload_offset,
147            size: variant.ty.total_size,
148            name: variant.name.clone(),
149            ty: variant.ty.clone(),
150        }
151    }
152}
153
154#[derive(Debug, Clone)]
155pub struct FrameMemoryAttribute {
156    pub is_temporary: bool,
157}
158
159#[derive(Debug, Clone)]
160pub enum DecoratedOperandAccessKind {
161    WriteRegister(TypedRegister, Option<PathInfo>, FrameMemoryAttribute), // register is modified
162    ReadRegister(TypedRegister, Option<PathInfo>, FrameMemoryAttribute), // register is only read from
163    ReadIndirectPointer(FrameMemoryAddress), // TODO: should probably be removed
164    DeltaPc(ProgramCounterDelta),            // for branch
165    AbsolutePc(InstructionPosition),         // e.g. call
166    MemorySize(MemorySize),
167    AbsoluteMemoryPosition(HeapMemoryAddress), // only for loading constants?
168    WriteFrameMemoryAddress(FrameMemoryAddress), // e.g. store to frame
169    ReadFrameMemoryAddress(FrameMemoryAddress), // e.g., load reg from frame
170    WriteBaseRegWithOffset(RegIndex, MemoryOffset),
171    ReadBaseRegWithOffset(RegIndex, MemoryOffset),
172    ImmediateU8(u8),
173    ImmediateU16(u16),
174    ImmediateU32(u32),
175    CountU16(u16),
176    CountU8(u8),
177    WriteMask(u8),
178    ReadMask(u8),
179}
180
181pub struct DecoratedOperandOrigin {}
182
183pub struct DecoratedOperand {
184    pub kind: DecoratedOperandAccessKind,
185    pub origin: DecoratedOperandOrigin,
186}
187
188pub struct DecoratedOpcode {
189    pub name: String,
190    pub operands: Vec<DecoratedOperand>,
191}
192
193#[derive(Clone, Debug)]
194pub struct MemoryElement {
195    pub offset: MemoryOffset,
196    pub size: MemorySize,
197    pub alignment: MemoryAlignment,
198}
199
200#[derive(Clone, Debug)]
201pub enum BasicTypeKind {
202    Empty,
203    Pointer,
204    U8,
205    B8,
206    U16,
207    S32,
208    Fixed32,
209    U32,
210    StringView {
211        byte: BasicTypeRef,
212        char: BasicTypeRef,
213    },
214    Struct(StructType),
215    TaggedUnion(TaggedUnion),
216    Tuple(TupleType),
217    Optional(TaggedUnion),
218    InternalRangeHeader,
219
220    // Can not be stored:
221    InternalVecIterator,
222    InternalStringIterator,
223    InternalMapIterator,
224    InternalSparseIterator,
225    InternalRangeIterator,
226    //InternalGridIterator,
227    SliceView(BasicTypeRef),
228
229    // Collections
230    FixedCapacityArray(BasicTypeRef, usize),
231    DynamicLengthVecView(BasicTypeRef),
232    VecStorage(BasicTypeRef, usize),
233    StringStorage {
234        element_type: BasicTypeRef,
235        char: BasicTypeRef,
236        capacity: usize,
237    },
238    StackStorage(BasicTypeRef, usize),
239    QueueStorage(BasicTypeRef, usize),
240    MapStorage {
241        key_type: BasicTypeRef,
242        value_type: BasicTypeRef,
243        logical_limit: usize,
244        capacity: CountU16,
245    },
246    SparseView(BasicTypeRef),
247    SparseStorage(BasicTypeRef, usize),
248
249    DynamicLengthMapView(Box<OffsetMemoryItem>, Box<OffsetMemoryItem>),
250    // DynamicLengthMapView(),
251    GridView(BasicTypeRef),
252    GridStorage(BasicTypeRef, usize, usize),
253    Any,
254}
255
256impl BasicTypeKind {
257    pub(crate) const fn manifestation(&self) -> Manifestation {
258        if self.is_scalar() {
259            Manifestation::Scalar
260        } else {
261            Manifestation::Aggregate
262        }
263    }
264
265    #[must_use]
266    pub fn element(&self) -> Option<BasicTypeRef> {
267        match &self {
268            Self::StackStorage(inner, _)
269            | Self::GridView(inner)
270            | Self::GridStorage(inner, ..)
271            | Self::SparseStorage(inner, _)
272            | Self::SparseView(inner)
273            | Self::QueueStorage(inner, _)
274            | Self::DynamicLengthVecView(inner)
275            | Self::FixedCapacityArray(inner, _)
276            | Self::VecStorage(inner, _)
277            | Self::SliceView(inner) => Some(inner.clone()),
278
279            Self::StringStorage { char, .. } | Self::StringView { char, .. } => Some(char.clone()),
280
281            _ => None,
282        }
283    }
284}
285
286pub enum Manifestation {
287    Scalar,
288    Aggregate,
289}
290
291impl Manifestation {
292    #[must_use]
293    pub const fn string(&self) -> &str {
294        match self {
295            Self::Scalar => "scalar",
296            Self::Aggregate => "aggregate",
297        }
298    }
299}
300
301impl Display for Manifestation {
302    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
303        write!(f, "{}", self.string())
304    }
305}
306
307impl BasicTypeKind {
308    pub(crate) const fn is_scalar(&self) -> bool {
309        matches!(
310            self,
311            Self::Empty
312                | Self::B8
313                | Self::U8
314                | Self::U16
315                | Self::S32
316                | Self::U32
317                | Self::Fixed32
318                | Self::StringView { .. }
319        )
320    }
321
322    #[must_use]
323    pub const fn is_reg_copy(&self) -> bool {
324        self.is_scalar()
325    }
326
327    #[must_use]
328    pub const fn is_view(&self) -> bool {
329        match self {
330            Self::GridView(_)
331            | Self::DynamicLengthMapView(_, _)
332            | Self::SparseView(_)
333            | Self::DynamicLengthVecView(_)
334            | Self::SliceView(_)
335            | Self::StringView { .. } => true,
336            _ => false,
337        }
338    }
339
340    #[must_use]
341    pub const fn is_aggregate(&self) -> bool {
342        !self.is_scalar()
343    }
344
345    #[must_use]
346    pub const fn is_mutable_reference(&self) -> bool {
347        false // MutablePointer removed - mutability is handled at analyzer level
348    }
349
350    pub(crate) const fn is_immutable(&self) -> bool {
351        !self.is_mutable_reference()
352    }
353
354    pub(crate) const fn is_storage(&self) -> bool {
355        !self.is_storage()
356    }
357
358    #[must_use]
359    pub const fn needs_copy_back_when_mutable(&self) -> bool {
360        self.is_scalar()
361    }
362
363    #[must_use]
364    pub fn union_info(&self) -> &TaggedUnion {
365        if let Self::TaggedUnion(union) = self {
366            union
367        } else {
368            panic!("wrong type")
369        }
370    }
371}
372
373impl Display for BasicTypeKind {
374    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
375        match self {
376            Self::Empty => write!(f, "()"),
377            Self::Pointer => write!(f, "Ptr"),
378            Self::Any => write!(f, "Any"),
379            Self::U8 => write!(f, "u8"),
380            Self::B8 => write!(f, "b8"),
381            Self::U16 => write!(f, "u16"),
382            Self::S32 => write!(f, "i32"),
383            Self::Fixed32 => write!(f, "Fixed(i32)"),
384            Self::U32 => write!(f, "u32"),
385            Self::StringView { .. } => write!(f, "String"),
386            Self::InternalRangeHeader => write!(f, "Range"),
387            Self::FixedCapacityArray(item_type, size) => write!(f, "[{item_type}; {size}]"),
388            Self::DynamicLengthVecView(item_type) => write!(f, "Vec<{item_type}>"),
389            Self::VecStorage(item_type, size) => write!(f, "Vec<{item_type}, {size}>"),
390            Self::StringStorage {
391                element_type: byte,
392                capacity,
393                ..
394            } => write!(f, "String<{byte}, {capacity}>"),
395            Self::SparseView(item_type) => write!(f, "Sparse<{item_type}>"),
396            Self::GridView(item_type) => write!(f, "Grid<{item_type}>"),
397            Self::SparseStorage(item_type, size) => write!(f, "SparseStorage<{item_type}, {size}>"),
398            Self::StackStorage(item_type, size) => write!(f, "StackStorage<{item_type}, {size}>"),
399            Self::GridStorage(item_type, width, height) => {
400                write!(f, "GridStorage<{item_type}, ({width},{height})>")
401            }
402            Self::QueueStorage(item_type, size) => write!(f, "QueueStorage<{item_type}, {size}>"),
403            Self::MapStorage {
404                logical_limit: logical_size,
405                capacity,
406                key_type,
407                value_type,
408                ..
409            } => write!(
410                f,
411                "MapStorage<{key_type}, {value_type}, {logical_size} ({capacity})>",
412            ),
413            Self::DynamicLengthMapView(key, value) => write!(f, "Map<{key}, {value}>"),
414            Self::InternalVecIterator => write!(f, "Vec::Iterator"),
415            Self::InternalStringIterator => write!(f, "String::Iterator"),
416            Self::InternalMapIterator => write!(f, "Map::Iterator"),
417            Self::InternalSparseIterator => write!(f, "Sparse::Iterator"),
418            Self::InternalRangeIterator => write!(f, "Range::Iterator"),
419            Self::Struct(struct_type) => write!(f, "{}", struct_type.name),
420            Self::TaggedUnion(union) => write!(f, "enum {}", union.name),
421            Self::Optional(optional) => write!(f, "{}?", optional.get_variant_by_index(1).ty),
422            Self::Tuple(tuple_type) => write!(f, "({})", comma(&tuple_type.fields)),
423            Self::SliceView(a) => write!(f, "slice<{}>", a.kind),
424        }
425    }
426}
427
428#[must_use]
429pub fn pointer_type_again() -> BasicTypeRef {
430    Rc::new(BasicType {
431        id: BasicTypeId::EMPTY,
432        kind: BasicTypeKind::U8, // Generic pointer type
433        total_size: MemorySize(4),
434        max_alignment: MemoryAlignment::U32,
435    })
436}
437
438// HACK:
439#[must_use]
440pub fn string_type() -> BasicTypeRef {
441    Rc::new(BasicType {
442        id: BasicTypeId::EMPTY,
443        kind: BasicTypeKind::U8,
444        total_size: STRING_PTR_SIZE,
445        max_alignment: STRING_PTR_ALIGNMENT,
446    })
447}
448// Hack:
449#[must_use]
450pub fn int_type() -> BasicTypeRef {
451    Rc::new(BasicType {
452        id: BasicTypeId::EMPTY,
453        kind: BasicTypeKind::S32,
454        total_size: MemorySize(4),
455        max_alignment: MemoryAlignment::U32,
456    })
457}
458
459// Hack
460#[must_use]
461pub fn float_type() -> BasicTypeRef {
462    Rc::new(BasicType {
463        id: BasicTypeId::EMPTY,
464        kind: BasicTypeKind::Fixed32,
465        total_size: MemorySize(4),
466        max_alignment: MemoryAlignment::U32,
467    })
468}
469
470// HACK
471#[must_use]
472pub fn bytes_type() -> BasicTypeRef {
473    Rc::new(BasicType {
474        id: BasicTypeId::EMPTY,
475        kind: BasicTypeKind::Empty,
476        total_size: MemorySize(0),
477        max_alignment: MemoryAlignment::U32,
478    })
479}
480
481#[must_use]
482pub const fn range_type() -> BasicType {
483    BasicType {
484        id: BasicTypeId::EMPTY,
485        kind: BasicTypeKind::InternalRangeHeader,
486        total_size: RANGE_HEADER_SIZE,
487        max_alignment: RANGE_HEADER_ALIGNMENT,
488    }
489}
490
491#[must_use]
492pub const fn range_iter_type() -> BasicType {
493    BasicType {
494        id: BasicTypeId::EMPTY,
495        kind: BasicTypeKind::InternalRangeIterator,
496        total_size: RANGE_ITERATOR_SIZE,
497        max_alignment: RANGE_ITERATOR_ALIGNMENT,
498    }
499}
500
501#[must_use]
502pub fn slice_type() -> BasicType {
503    BasicType {
504        id: BasicTypeId::EMPTY,
505        kind: BasicTypeKind::SliceView(BasicTypeRef::from(u8_type())), // todo: fix
506        total_size: MAP_HEADER_SIZE,
507        max_alignment: MAP_HEADER_ALIGNMENT,
508    }
509}
510
511// HACK: Used when we don't know the actual type. that should be a rare case.
512#[must_use]
513pub fn unknown_type() -> BasicTypeRef {
514    Rc::new(BasicType {
515        id: BasicTypeId::EMPTY,
516        kind: BasicTypeKind::Empty,
517        total_size: MemorySize(0),
518        max_alignment: MemoryAlignment::U8,
519    })
520}
521
522#[must_use]
523pub fn vec_type() -> BasicType {
524    BasicType {
525        id: BasicTypeId::EMPTY,
526        kind: BasicTypeKind::DynamicLengthVecView(BasicTypeRef::from(unknown_type())),
527        total_size: VEC_PTR_SIZE,
528        max_alignment: VEC_PTR_ALIGNMENT,
529    }
530}
531
532#[must_use]
533pub const fn vec_iter_type() -> BasicType {
534    BasicType {
535        id: BasicTypeId::EMPTY,
536        kind: BasicTypeKind::InternalVecIterator,
537        total_size: VEC_ITERATOR_SIZE,
538        max_alignment: VEC_ITERATOR_ALIGNMENT,
539    }
540}
541
542#[must_use]
543pub fn map_type() -> BasicType {
544    BasicType {
545        id: BasicTypeId::EMPTY,
546        kind: BasicTypeKind::DynamicLengthMapView(
547            Box::from(OffsetMemoryItem {
548                offset: MemoryOffset(0),
549                size: MemorySize(0),
550                name: String::new(),
551                ty: Rc::new(BasicType {
552                    id: BasicTypeId::EMPTY,
553                    kind: BasicTypeKind::Empty,
554                    total_size: MemorySize(0),
555                    max_alignment: MemoryAlignment::U8,
556                }),
557            }),
558            Box::from(OffsetMemoryItem {
559                offset: MemoryOffset(0),
560                size: MemorySize(0),
561                name: String::new(),
562                ty: Rc::new(BasicType {
563                    id: BasicTypeId::EMPTY,
564                    kind: BasicTypeKind::Empty,
565                    total_size: MemorySize(0),
566                    max_alignment: MemoryAlignment::U8,
567                }),
568            }),
569        ),
570
571        total_size: MAP_HEADER_SIZE,
572        max_alignment: MAP_HEADER_ALIGNMENT,
573    }
574}
575
576#[must_use]
577pub const fn map_iter_type() -> BasicType {
578    BasicType {
579        id: BasicTypeId::EMPTY,
580        kind: BasicTypeKind::InternalMapIterator,
581        total_size: MAP_ITERATOR_SIZE,
582        max_alignment: MAP_ITERATOR_ALIGNMENT,
583    }
584}
585
586// HACK: a way to go around the cache. must be fixed.
587#[must_use]
588pub fn u32_type() -> BasicTypeRef {
589    Rc::new(BasicType {
590        id: BasicTypeId::EMPTY,
591        kind: BasicTypeKind::U32,
592        total_size: MemorySize(4),
593        max_alignment: MemoryAlignment::U32,
594    })
595}
596
597#[must_use]
598pub fn u16_type() -> BasicTypeRef {
599    Rc::new(BasicType {
600        id: BasicTypeId::EMPTY,
601        kind: BasicTypeKind::U16,
602        total_size: MemorySize(2),
603        max_alignment: MemoryAlignment::U16,
604    })
605}
606
607// HACK:
608#[must_use]
609pub fn u8_type() -> BasicTypeRef {
610    Rc::new(BasicType {
611        id: BasicTypeId::EMPTY,
612        kind: BasicTypeKind::U8,
613        total_size: MemorySize(1),
614        max_alignment: MemoryAlignment::U8,
615    })
616}
617
618// HACK: should go through the cache
619#[must_use]
620pub fn b8_type() -> BasicTypeRef {
621    Rc::new(BasicType {
622        id: BasicTypeId::EMPTY,
623        kind: BasicTypeKind::B8,
624        total_size: MemorySize(1),
625        max_alignment: MemoryAlignment::U8,
626    })
627}
628
629// This is a hack, used when we don't know what
630// the actual type is
631#[must_use]
632pub fn pointer_type() -> BasicTypeRef {
633    // This is a
634    Rc::new(BasicType {
635        id: BasicTypeId::EMPTY,
636        kind: BasicTypeKind::U8, // Generic pointer type
637        total_size: HEAP_PTR_ON_FRAME_SIZE,
638        max_alignment: HEAP_PTR_ON_FRAME_ALIGNMENT,
639    })
640}
641
642/// Represents a type that has been allocated to a heap relative address
643#[derive(Clone, Debug)]
644pub struct HeapPlacedArray {
645    addr: HeapMemoryAddress,
646    byte_count: u32,
647}
648
649impl HeapPlacedArray {
650    #[must_use]
651    pub const fn new(addr: HeapMemoryAddress, byte_count: u32) -> Self {
652        Self { addr, byte_count }
653    }
654
655    #[must_use]
656    pub const fn addr(&self) -> HeapMemoryAddress {
657        self.addr
658    }
659
660    #[must_use]
661    pub const fn byte_count(&self) -> u32 {
662        self.byte_count
663    }
664}
665
666/// Represents a type that has been allocated to a frame relative address
667#[derive(Clone, Debug)]
668pub struct HeapPlacedType {
669    addr: HeapMemoryAddress,
670    ty: BasicTypeRef,
671}
672
673impl HeapPlacedType {
674    #[must_use]
675    pub const fn new(addr: HeapMemoryAddress, ty: BasicTypeRef) -> Self {
676        Self { addr, ty }
677    }
678
679    #[must_use]
680    pub fn region(&self) -> HeapMemoryRegion {
681        HeapMemoryRegion {
682            addr: self.addr,
683            size: self.ty.total_size,
684        }
685    }
686
687    #[must_use]
688    pub const fn addr(&self) -> HeapMemoryAddress {
689        self.addr
690    }
691
692    #[must_use]
693    pub fn size(&self) -> MemorySize {
694        self.ty.total_size
695    }
696
697    #[must_use]
698    pub const fn ty(&self) -> &BasicTypeRef {
699        &self.ty
700    }
701}
702
703/// Where a value is located
704#[derive(Clone, Debug)]
705pub enum Place {
706    Discard, // no output
707    Register(TypedRegister),
708    Memory(MemoryLocation),
709}
710
711impl Place {
712    #[must_use]
713    pub const fn vm_type(&self) -> Option<&VmType> {
714        match self {
715            Self::Discard => None,
716            Self::Register(reg) => Some(&reg.ty),
717            Self::Memory(mem) => Some(&mem.ty),
718        }
719    }
720}
721
722impl Display for Place {
723    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
724        match self {
725            Self::Discard => write!(f, "unit ()"),
726            Self::Register(reg) => write!(f, "reg: {reg}"),
727            Self::Memory(memory_location) => write!(f, "memory_location {memory_location:?}"),
728        }
729    }
730}
731
732impl Place {
733    #[must_use]
734    pub const fn memory_location(&self) -> Option<&MemoryLocation> {
735        match self {
736            Self::Discard => None,
737            Self::Register(_) => None,
738            Self::Memory(memory_location) => Some(memory_location),
739        }
740    }
741}
742
743impl Place {
744    #[must_use]
745    pub fn add_offset(&self, offset: MemoryOffset, vm_type: VmType) -> Self {
746        match self {
747            Self::Discard => {
748                panic!("add_offset")
749            }
750            Self::Register(reg) => {
751                if reg.ty.is_aggregate() {
752                    Self::Memory(MemoryLocation {
753                        base_ptr_reg: reg.clone(),
754                        offset,
755                        ty: vm_type,
756                    })
757                } else {
758                    panic!(
759                        "can not add offset to a register since it wasn't an aggregate {}",
760                        reg.ty
761                    )
762                }
763            }
764            Self::Memory(memory_location) => Self::Memory(MemoryLocation {
765                base_ptr_reg: memory_location.base_ptr_reg.clone(),
766                offset: memory_location.offset + offset,
767                ty: vm_type,
768            }),
769        }
770    }
771    #[must_use]
772    pub const fn new_unit() -> Self {
773        Self::Discard
774    }
775    #[must_use]
776    pub const fn new_reg(register: TypedRegister) -> Self {
777        Self::Register(register)
778    }
779    #[must_use]
780    pub const fn new_location(memory_location: MemoryLocation) -> Self {
781        Self::Memory(memory_location)
782    }
783
784    #[must_use]
785    pub const fn is_unit(&self) -> bool {
786        matches!(self, Self::Discard)
787    }
788    #[must_use]
789    pub const fn is_memory_location(&self) -> bool {
790        matches!(self, Self::Memory(_))
791    }
792
793    #[must_use]
794    pub const fn is_register(&self) -> bool {
795        matches!(self, Self::Register(_))
796    }
797    #[must_use]
798    pub fn ty(&self) -> &BasicTypeRef {
799        match self {
800            Self::Discard => panic!("no type"),
801            Self::Register(reg) => &reg.ty.basic_type,
802            Self::Memory(location) => &location.ty.basic_type,
803        }
804    }
805
806    #[must_use]
807    pub const fn register(&self) -> Option<&TypedRegister> {
808        match self {
809            Self::Register(reg) => Some(reg),
810            _ => None,
811        }
812    }
813
814    #[must_use]
815    pub const fn register_involved_in_destination(&self) -> Option<&TypedRegister> {
816        match self {
817            Self::Register(reg) => Some(reg),
818            Self::Memory(memory_location) => Some(memory_location.reg()),
819            Self::Discard => None,
820        }
821    }
822
823    #[must_use]
824    pub fn grab_register(&self) -> &TypedRegister {
825        match self {
826            Self::Register(reg) => reg,
827            Self::Memory(_) => {
828                panic!("assumed it would be a register")
829            }
830            Self::Discard => panic!("assumed it would be a register, but was unit"),
831        }
832    }
833
834    #[must_use]
835    pub fn grab_memory_location(&self) -> &MemoryLocation {
836        match self {
837            Self::Register(_reg) => panic!("assumed it was a memory location"),
838            Self::Memory(location) => location,
839            Self::Discard => {
840                panic!("assumed it would be a memory location, but was unit")
841            }
842        }
843    }
844
845    /// Use if you know for a fact that the Destination is a memory location
846    /// Either a `base_reg` + `offset` or a normal reg (usually from a variable)
847    #[must_use]
848    pub fn memory_location_or_pointer_reg(&self) -> MemoryLocation {
849        match self {
850            Self::Register(reg) => MemoryLocation {
851                base_ptr_reg: reg.clone(),
852                offset: MemoryOffset(0),
853                ty: reg.ty.clone(),
854            },
855            Self::Memory(location) => location.clone(),
856            Self::Discard => {
857                panic!("assumed it would be a memory location, but was unit")
858            }
859        }
860    }
861
862    #[must_use]
863    pub fn grab_aggregate_memory_location_or_pointer_reg(&self) -> AggregateMemoryLocation {
864        AggregateMemoryLocation {
865            location: self.memory_location_or_pointer_reg(),
866        }
867    }
868    #[must_use]
869    pub fn grab_aggregate_memory_location(&self) -> AggregateMemoryLocation {
870        AggregateMemoryLocation {
871            location: self.grab_memory_location().clone(),
872        }
873    }
874}
875
876#[derive(Clone)]
877pub struct TypedRegister {
878    pub index: u8,
879    pub ty: VmType,
880    pub comment: String,
881}
882
883impl PartialEq<Self> for TypedRegister {
884    fn eq(&self, other: &Self) -> bool {
885        self.index == other.index
886    }
887}
888
889impl Eq for TypedRegister {}
890
891impl Ord for TypedRegister {
892    fn cmp(&self, other: &Self) -> Ordering {
893        self.index.cmp(&other.index)
894    }
895}
896impl PartialOrd<Self> for TypedRegister {
897    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
898        self.index.partial_cmp(&other.index)
899    }
900}
901
902impl TypedRegister {
903    #[must_use]
904    pub fn comment(&self) -> &str {
905        &self.comment
906    }
907}
908
909impl TypedRegister {
910    #[must_use]
911    pub fn new_empty_reserved() -> Self {
912        Self {
913            index: 0xff,
914            ty: VmType::new_unknown_placement(BasicTypeRef::from(unknown_type())),
915            comment: String::new(),
916        }
917    }
918}
919
920impl TypedRegister {
921    #[must_use]
922    pub fn final_type(&self) -> BasicTypeRef {
923        self.ty.basic_type.clone()
924    }
925}
926
927impl Debug for TypedRegister {
928    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
929        write!(f, "r{} ({} - {})", self.index, self.ty, self.comment)
930    }
931}
932
933impl Display for TypedRegister {
934    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
935        write!(f, "r{}", self.index)
936    }
937}
938
939impl TypedRegister {
940    #[must_use]
941    pub fn new_frame_placed(index: u8, frame_placed: FramePlacedType) -> Self {
942        Self {
943            index,
944            ty: VmType::new_frame_placed(frame_placed),
945            comment: String::new(),
946        }
947    }
948
949    #[must_use]
950    pub const fn new_vm_type(index: u8, ty: VmType) -> Self {
951        Self {
952            index,
953            ty,
954            comment: String::new(),
955        }
956    }
957
958    pub fn with_comment(&mut self, comment: &str) -> &mut Self {
959        self.comment = comment.to_string();
960        self
961    }
962    #[must_use]
963    pub const fn addressing(&self) -> u8 {
964        self.index
965    }
966
967    #[must_use]
968    pub const fn ty(&self) -> &BasicTypeRef {
969        &self.ty.basic_type
970    }
971
972    #[must_use]
973    pub fn frame_placed(&self) -> FramePlacedType {
974        if let Some(fp) = self.ty.frame_placed_type() {
975            fp
976        } else {
977            panic!("")
978        }
979    }
980
981    #[must_use]
982    pub fn size(&self) -> MemorySize {
983        self.ty.basic_type.total_size
984    }
985
986    #[must_use]
987    pub fn addr(&self) -> FrameMemoryAddress {
988        self.frame_placed().addr
989    }
990
991    #[must_use]
992    pub fn region(&self) -> FrameMemoryRegion {
993        self.frame_placed().region()
994    }
995
996    #[must_use]
997    pub fn underlying(&self) -> BasicTypeRef {
998        self.ty.basic_type.clone()
999    }
1000}
1001
1002#[derive(Clone, Debug)]
1003pub enum VmTypeOrigin {
1004    Unknown,
1005    InsideReg,
1006    Frame(FrameMemoryRegion),
1007    Heap(HeapMemoryRegion), // Constants only?
1008}
1009
1010impl Display for VmTypeOrigin {
1011    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1012        match self {
1013            Self::Unknown => Ok(()),
1014            Self::Frame(region) => write!(f, "frame {region}"),
1015            Self::Heap(region) => write!(f, "heap {region}"),
1016            Self::InsideReg => write!(f, "reg"),
1017        }
1018    }
1019}
1020
1021#[derive(Clone, Debug)]
1022pub struct VmType {
1023    pub basic_type: BasicTypeRef,
1024    pub origin: VmTypeOrigin,
1025}
1026
1027impl VmType {
1028    #[must_use]
1029    pub fn is_collection_like(&self) -> bool {
1030        self.basic_type.is_collection_like()
1031    }
1032}
1033
1034impl VmType {
1035    #[must_use]
1036    pub fn is_mutable_primitive(&self) -> bool {
1037        self.basic_type.is_mutable_reference()
1038            && self
1039                .basic_type
1040                .should_be_copied_back_when_mutable_arg_or_return()
1041    }
1042
1043    #[must_use]
1044    pub fn element_count_always_same_as_capacity(&self) -> bool {
1045        self.basic_type.element_count_always_same_as_capacity()
1046    }
1047}
1048
1049impl Display for VmType {
1050    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1051        write!(
1052            f,
1053            "{} {} {}",
1054            tinter::bright_green(&self.basic_type),
1055            self.origin,
1056            tinter::bright_magenta(self.manifestation())
1057        )
1058    }
1059}
1060
1061impl VmType {
1062    #[must_use]
1063    pub fn new_frame_placed(frame_placed: FramePlacedType) -> Self {
1064        Self {
1065            basic_type: frame_placed.ty.clone(),
1066            origin: VmTypeOrigin::Frame(frame_placed.region()),
1067        }
1068    }
1069    #[must_use]
1070    pub fn is_immutable(&self) -> bool {
1071        self.basic_type.kind.is_immutable()
1072    }
1073
1074    #[must_use]
1075    pub fn manifestation(&self) -> Manifestation {
1076        self.basic_type.manifestation()
1077    }
1078
1079    #[must_use]
1080    pub const fn new_heap_placement(
1081        basic_type: BasicTypeRef,
1082        heap_region: HeapMemoryRegion,
1083    ) -> Self {
1084        Self {
1085            basic_type,
1086            origin: VmTypeOrigin::Heap(heap_region),
1087        }
1088    }
1089
1090    #[must_use]
1091    pub const fn new_contained_in_register(basic_type: BasicTypeRef) -> Self {
1092        Self {
1093            basic_type,
1094            origin: VmTypeOrigin::InsideReg,
1095        }
1096    }
1097
1098    #[must_use]
1099    pub const fn new_unknown_placement(basic_type: BasicTypeRef) -> Self {
1100        Self {
1101            basic_type,
1102            origin: VmTypeOrigin::Unknown,
1103        }
1104    }
1105
1106    #[must_use]
1107    pub const fn new_basic_with_origin(basic_type: BasicTypeRef, origin: VmTypeOrigin) -> Self {
1108        Self { basic_type, origin }
1109    }
1110
1111    #[must_use]
1112    pub fn frame_placed_type(&self) -> Option<FramePlacedType> {
1113        if let VmTypeOrigin::Frame(region) = self.origin {
1114            Some(FramePlacedType {
1115                addr: region.addr,
1116                ty: self.basic_type.clone(),
1117            })
1118        } else {
1119            None
1120        }
1121    }
1122
1123    #[must_use]
1124    pub fn is_mutable_reference_semantic(&self) -> bool {
1125        self.basic_type.is_mutable_reference()
1126    }
1127
1128    #[must_use]
1129    pub fn is_aggregate(&self) -> bool {
1130        self.basic_type.is_aggregate()
1131    }
1132
1133    #[must_use]
1134    pub fn is_scalar(&self) -> bool {
1135        self.basic_type.is_scalar()
1136    }
1137
1138    #[must_use]
1139    pub fn is_reg_copy(&self) -> bool {
1140        self.basic_type.is_reg_copy()
1141    }
1142
1143    #[must_use]
1144    pub fn needs_allocated_space_for_return_in_reg0(&self) -> bool {
1145        self.basic_type.is_aggregate()
1146    }
1147
1148    #[must_use]
1149    pub fn needs_copy_back_for_mutable(&self) -> bool {
1150        !self.basic_type.is_aggregate()
1151    }
1152    #[must_use]
1153    pub const fn basic_type(&self) -> &BasicTypeRef {
1154        &self.basic_type
1155    }
1156}
1157
1158/// Represents a type that has been allocated to a frame relative address
1159#[derive(Clone, Debug)]
1160pub struct FramePlacedType {
1161    addr: FrameMemoryAddress,
1162    ty: BasicTypeRef,
1163}
1164
1165impl FramePlacedType {
1166    #[must_use]
1167    pub const fn new(addr: FrameMemoryAddress, ty: BasicTypeRef) -> Self {
1168        Self { addr, ty }
1169    }
1170
1171    #[must_use]
1172    pub fn region(&self) -> FrameMemoryRegion {
1173        FrameMemoryRegion {
1174            addr: self.addr,
1175            size: self.ty.total_size,
1176        }
1177    }
1178
1179    #[must_use]
1180    pub const fn addr(&self) -> FrameMemoryAddress {
1181        self.addr
1182    }
1183
1184    #[must_use]
1185    pub fn size(&self) -> MemorySize {
1186        self.ty.total_size
1187    }
1188
1189    #[must_use]
1190    pub fn ty(&self) -> &BasicType {
1191        &self.ty
1192    }
1193
1194    #[must_use]
1195    pub fn final_type(&self) -> BasicTypeRef {
1196        self.ty.clone()
1197    }
1198
1199    #[must_use]
1200    pub fn move_with_offset(&self, offset: MemoryOffset, ty: BasicTypeRef) -> Self {
1201        Self {
1202            addr: self.addr + offset,
1203            ty,
1204        }
1205    }
1206
1207    #[must_use]
1208    pub fn move_to_field(&self, index: usize) -> Self {
1209        let offset_info = self.ty.get_field_offset(index).unwrap();
1210        Self {
1211            addr: self.addr + offset_info.offset,
1212            ty: offset_info.ty.clone(),
1213        }
1214    }
1215
1216    #[must_use]
1217    pub fn move_to_optional_some_payload(&self) -> Self {
1218        self.move_to_optional_payload_variant(1)
1219    }
1220
1221    #[must_use]
1222    pub fn move_to_optional_none_payload(&self) -> Self {
1223        self.move_to_optional_payload_variant(0)
1224    }
1225
1226    #[must_use]
1227    pub fn move_to_optional_payload_variant(&self, index: usize) -> Self {
1228        let optional_info = self.ty.optional_info().unwrap();
1229        Self::new(
1230            self.addr + optional_info.payload_offset,
1231            optional_info.get_variant_by_index(index).ty.clone(),
1232        )
1233    }
1234
1235    #[must_use]
1236    pub fn move_to_optional_tag(&self) -> Self {
1237        let optional_info = self.ty().optional_info().unwrap();
1238
1239        let addr = self.addr() + optional_info.tag_offset;
1240        assert_eq!(optional_info.tag_size.0, 1);
1241
1242        let tag_type = Rc::new(BasicType {
1243            id: BasicTypeId::EMPTY,
1244            kind: BasicTypeKind::B8,
1245            total_size: MemorySize(1),
1246            max_alignment: MemoryAlignment::U8,
1247        });
1248
1249        Self::new(addr, tag_type)
1250    }
1251}
1252
1253pub enum BoundsCheck {
1254    KnownSizeAtCompileTime(u16),
1255    RegisterWithMaxCount(TypedRegister),
1256}
1257
1258#[derive(Clone, Debug)]
1259pub struct BasicTypeId(pub u32);
1260
1261impl BasicTypeId {
1262    pub const EMPTY: Self = Self(0xffff_ffff);
1263}
1264
1265#[derive(Clone, Debug)]
1266pub struct BasicType {
1267    pub id: BasicTypeId,
1268    pub kind: BasicTypeKind,
1269    pub total_size: MemorySize,
1270    pub max_alignment: MemoryAlignment,
1271}
1272
1273impl BasicType {
1274    #[must_use]
1275    pub const fn is_vec_like(&self) -> bool {
1276        matches!(
1277            self.kind,
1278            BasicTypeKind::VecStorage(..)
1279                | BasicTypeKind::DynamicLengthVecView(..)
1280                | BasicTypeKind::StringStorage { .. }
1281                | BasicTypeKind::StringView { .. }
1282                | BasicTypeKind::StackStorage(..)
1283                | BasicTypeKind::QueueStorage(..)
1284                | BasicTypeKind::SliceView(..)
1285                | BasicTypeKind::FixedCapacityArray(..)
1286        )
1287    }
1288
1289    #[must_use]
1290    pub fn element(&self) -> Option<BasicTypeRef> {
1291        self.kind.element()
1292    }
1293
1294    #[must_use]
1295    pub const fn is_collection(&self) -> bool {
1296        matches!(
1297            self.kind,
1298            BasicTypeKind::VecStorage(..)
1299                | BasicTypeKind::StringStorage { .. }
1300                | BasicTypeKind::StringView { .. }
1301                | BasicTypeKind::SliceView(..)
1302                | BasicTypeKind::FixedCapacityArray(..)
1303                | BasicTypeKind::DynamicLengthVecView(..)
1304                | BasicTypeKind::MapStorage { .. }
1305                | BasicTypeKind::DynamicLengthMapView(..)
1306                | BasicTypeKind::GridStorage(..)
1307                | BasicTypeKind::GridView(..)
1308                | BasicTypeKind::SparseStorage(..)
1309                | BasicTypeKind::SparseView(..)
1310                | BasicTypeKind::StackStorage(..)
1311                | BasicTypeKind::QueueStorage(..)
1312        )
1313    }
1314
1315    #[must_use]
1316    pub fn might_contain_collections(&self) -> bool {
1317        match &self.kind {
1318            BasicTypeKind::Struct(struct_type) => struct_type
1319                .fields
1320                .iter()
1321                .any(|field| field.ty.is_collection() || field.ty.might_contain_collections()),
1322            BasicTypeKind::Tuple(tuple_type) => tuple_type
1323                .fields
1324                .iter()
1325                .any(|field| field.ty.is_collection() || field.ty.might_contain_collections()),
1326            BasicTypeKind::TaggedUnion(union_type) => union_type.variants.iter().any(|variant| {
1327                variant.ty.is_collection() || variant.ty.might_contain_collections()
1328            }),
1329            BasicTypeKind::Optional(union_type) => union_type.variants.iter().any(|variant| {
1330                variant.ty.is_collection() || variant.ty.might_contain_collections()
1331            }),
1332            BasicTypeKind::MapStorage { value_type, .. } => {
1333                value_type.is_collection() || value_type.might_contain_collections()
1334            }
1335            _ => false,
1336        }
1337    }
1338
1339    pub(crate) const fn element_count_always_same_as_capacity(&self) -> bool {
1340        matches!(self.kind, BasicTypeKind::FixedCapacityArray(..))
1341    }
1342    #[must_use]
1343    pub const fn is_collection_like(&self) -> bool {
1344        matches!(
1345            self.kind,
1346            BasicTypeKind::FixedCapacityArray(..)
1347            // String
1348            | BasicTypeKind::StringView { .. }
1349            | BasicTypeKind::StringStorage { .. }
1350
1351            // Vec
1352            | BasicTypeKind::VecStorage(..)
1353            | BasicTypeKind::StackStorage(..)
1354            | BasicTypeKind::DynamicLengthVecView(..)
1355            // Map
1356            | BasicTypeKind::MapStorage {  ..}
1357            | BasicTypeKind::DynamicLengthMapView(..)
1358        )
1359    }
1360    #[must_use]
1361    pub const fn is_collection_with_capacity(&self) -> bool {
1362        matches!(
1363            self.kind,
1364            BasicTypeKind::FixedCapacityArray(..)
1365            // Vec
1366            | BasicTypeKind::VecStorage(..)
1367            | BasicTypeKind::StringStorage {..}
1368            // Map
1369            | BasicTypeKind::MapStorage { ..}
1370        )
1371    }
1372}
1373
1374impl BasicType {
1375    pub(crate) const fn manifestation(&self) -> Manifestation {
1376        self.kind.manifestation()
1377    }
1378}
1379
1380impl BasicType {
1381    #[must_use]
1382    pub const fn should_be_copied_back_when_mutable_arg_or_return(&self) -> bool {
1383        !self.is_aggregate()
1384    }
1385}
1386
1387impl BasicType {
1388    #[must_use]
1389    pub fn referenced_type(&self) -> &Self {
1390        // MutablePointer removed - mutability handled at analyzer level
1391        panic!("referenced_type() is no longer supported - MutablePointer was removed")
1392    }
1393}
1394
1395impl BasicType {
1396    #[must_use]
1397    pub const fn make_pointer(&self) -> Self {
1398        // MutablePointer removed - return a generic pointer type
1399        Self {
1400            id: BasicTypeId::EMPTY,
1401            kind: BasicTypeKind::U8,
1402            total_size: HEAP_PTR_ON_FRAME_SIZE,
1403            max_alignment: HEAP_PTR_ON_FRAME_ALIGNMENT,
1404        }
1405    }
1406}
1407
1408impl BasicType {}
1409
1410impl BasicType {
1411    #[must_use]
1412    pub fn get_variant(&self, variant_index: usize) -> &TaggedUnionVariant {
1413        match &self.kind {
1414            BasicTypeKind::TaggedUnion(tagged) | BasicTypeKind::Optional(tagged) => {
1415                tagged.get_variant_by_index(variant_index)
1416            }
1417            _ => panic!("type is not a tagged union"),
1418        }
1419    }
1420}
1421
1422impl BasicType {
1423    #[must_use]
1424    pub const fn is_scalar(&self) -> bool {
1425        self.kind.is_scalar()
1426    }
1427
1428    #[must_use]
1429    pub const fn is_reg_copy(&self) -> bool {
1430        self.kind.is_reg_copy()
1431    }
1432
1433    #[must_use]
1434    pub const fn is_scratch_arena_allocated(&self) -> bool {
1435        matches!(self.kind, BasicTypeKind::StringView { .. })
1436    }
1437
1438    #[must_use]
1439    pub const fn needs_hidden_pointer_as_return(&self) -> bool {
1440        self.kind.is_aggregate() && !self.is_scratch_arena_allocated()
1441    }
1442
1443    #[must_use]
1444    pub const fn is_mutable_reference(&self) -> bool {
1445        self.kind.is_mutable_reference()
1446    }
1447}
1448
1449impl BasicType {
1450    #[must_use]
1451    pub const fn unwrap_info(
1452        &self,
1453    ) -> Option<(MemoryOffset, MemorySize, MemoryOffset, MemorySize)> {
1454        match &self.kind {
1455            BasicTypeKind::TaggedUnion(tagged) | BasicTypeKind::Optional(tagged) => Some((
1456                tagged.tag_offset,
1457                tagged.tag_size,
1458                tagged.payload_offset,
1459                tagged.payload_max_size,
1460            )),
1461            _ => None,
1462        }
1463    }
1464
1465    #[must_use]
1466    pub fn union_info(&self) -> &TaggedUnion {
1467        self.kind.union_info()
1468    }
1469
1470    #[must_use]
1471    pub fn create_mutable_pointer(&self) -> Self {
1472        // MutablePointer removed - return a generic pointer type
1473        debug_assert!(!self.is_mutable_reference());
1474
1475        Self {
1476            id: BasicTypeId::EMPTY,
1477            kind: BasicTypeKind::U8,
1478            total_size: HEAP_PTR_ON_FRAME_SIZE,
1479            max_alignment: HEAP_PTR_ON_FRAME_ALIGNMENT,
1480        }
1481    }
1482
1483    #[must_use]
1484    pub const fn is_aggregate(&self) -> bool {
1485        self.kind.is_aggregate()
1486    }
1487
1488    #[must_use]
1489    pub const fn optional_info(&self) -> Option<&TaggedUnion> {
1490        match &self.kind {
1491            BasicTypeKind::Optional(tagged_union) => Some(tagged_union),
1492            _ => None,
1493        }
1494    }
1495
1496    #[must_use]
1497    pub fn get_field_offset(&self, index: usize) -> Option<&OffsetMemoryItem> {
1498        match &self.kind {
1499            BasicTypeKind::Struct(struct_type) => struct_type.fields.get(index),
1500            BasicTypeKind::Tuple(tuple_type) => tuple_type.fields.get(index),
1501            _ => {
1502                error!(?self, "not a type with fields");
1503                None
1504            }
1505        }
1506    }
1507
1508    #[must_use]
1509    pub fn bucket_size_for_vec_like(&self) -> Option<MemorySize> {
1510        match &self.kind {
1511            BasicTypeKind::FixedCapacityArray(inner, _capacity) => Some(inner.total_size),
1512            BasicTypeKind::SliceView(inner) => Some(inner.total_size),
1513            BasicTypeKind::VecStorage(inner, _) => Some(inner.total_size),
1514            BasicTypeKind::StringStorage {
1515                element_type: byte, ..
1516            } => Some(byte.total_size),
1517            BasicTypeKind::DynamicLengthVecView(inner) => Some(inner.total_size),
1518            BasicTypeKind::StringView { .. } => Some(MemorySize(1)), // String elements are bytes (u8)
1519            _ => None,
1520        }
1521    }
1522
1523    #[must_use]
1524    pub const fn header_size_for_vec_like(&self) -> Option<MemorySize> {
1525        match &self.kind {
1526            BasicTypeKind::SliceView(_)
1527            | BasicTypeKind::DynamicLengthVecView(_)
1528            | BasicTypeKind::VecStorage(_, _)
1529            | BasicTypeKind::StringStorage { .. }
1530            | BasicTypeKind::StringView { .. } => Some(VEC_HEADER_SIZE),
1531            BasicTypeKind::DynamicLengthMapView(..) => Some(MAP_HEADER_SIZE),
1532            _ => None,
1533        }
1534    }
1535
1536    #[must_use]
1537    pub fn element_pair(&self) -> Option<(&OffsetMemoryItem, &OffsetMemoryItem)> {
1538        match &self.kind {
1539            BasicTypeKind::DynamicLengthMapView(a, b) => Some((a, b)),
1540            _ => None,
1541        }
1542    }
1543
1544    #[must_use]
1545    pub fn is_int(&self) -> bool {
1546        matches!(self.kind, BasicTypeKind::S32)
1547            && self.total_size.0 == 4
1548            && self.max_alignment == MemoryAlignment::U32
1549    }
1550
1551    #[must_use]
1552    pub fn is_codepoint(&self) -> bool {
1553        matches!(self.kind, BasicTypeKind::U32)
1554            && self.total_size.0 == 4
1555            && self.max_alignment == MemoryAlignment::U32
1556    }
1557    #[must_use]
1558    pub fn is_float(&self) -> bool {
1559        matches!(self.kind, BasicTypeKind::Fixed32)
1560            && self.total_size.0 == 4
1561            && self.max_alignment == MemoryAlignment::U32
1562    }
1563
1564    #[must_use]
1565    pub fn is_str(&self) -> bool {
1566        (matches!(self.kind, BasicTypeKind::StringView { .. })
1567            && self.total_size == STRING_PTR_SIZE
1568            && self.max_alignment == STRING_PTR_ALIGNMENT)
1569            || matches!(self.kind, BasicTypeKind::StringStorage { .. })
1570    }
1571
1572    #[must_use]
1573    pub fn is_bool(&self) -> bool {
1574        matches!(self.kind, BasicTypeKind::B8)
1575            && self.total_size.0 == 1
1576            && self.max_alignment == MemoryAlignment::U8
1577    }
1578    #[must_use]
1579    pub fn is_byte(&self) -> bool {
1580        matches!(self.kind, BasicTypeKind::U8)
1581            && self.total_size.0 == 1
1582            && self.max_alignment == MemoryAlignment::U8
1583    }
1584}
1585
1586impl Display for BasicType {
1587    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1588        write!(f, "{}", self.kind)
1589    }
1590}
1591
1592#[derive(Clone, Debug)]
1593pub struct VariableInfo {
1594    pub is_mutable: bool,
1595    pub name: String,
1596}
1597
1598impl Display for VariableInfo {
1599    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1600        let mut_prefix = if self.is_mutable { "mut " } else { "" };
1601
1602        let name = &self.name;
1603        write!(f, "{mut_prefix}{name}")
1604    }
1605}
1606
1607#[derive(Clone, Debug)]
1608pub enum VariableInfoKind {
1609    Variable(VariableInfo),
1610    Parameter(VariableInfo),
1611    Return,
1612}
1613
1614impl Display for VariableInfoKind {
1615    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1616        match self {
1617            Self::Variable(var_info) => {
1618                write!(f, "{} {var_info}", "var:".white())
1619            }
1620            Self::Parameter(var_info) => {
1621                write!(f, "{} {var_info}", "param:".white())
1622            }
1623            Self::Return => {
1624                write!(f, "{}", "return".white())
1625            }
1626        }
1627    }
1628}
1629
1630#[derive(Clone, Debug)]
1631pub struct FrameAddressInfo {
1632    pub kind: VariableInfoKind,
1633    pub frame_placed_type: FramePlacedType,
1634}
1635
1636#[derive(Clone, Debug)]
1637pub struct VariableRegister {
1638    pub unique_id_in_function: usize,
1639    pub variable: VariableInfo,
1640    pub register: TypedRegister,
1641}
1642
1643impl Display for VariableRegister {
1644    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1645        write!(f, "{}: {}", self.register, self.variable)
1646    }
1647}
1648
1649#[derive(Clone, Debug)]
1650pub struct VariableRegisterRange {
1651    pub start: u8,
1652    pub count: u8,
1653}
1654
1655#[derive(Clone, Debug)]
1656pub struct FrameMemoryInfo {
1657    pub infos: Vec<FrameAddressInfo>,
1658    pub total_frame_size: FrameMemorySize,
1659    pub variable_frame_size: FrameMemorySize,
1660    pub variable_registers: Vec<VariableRegister>,
1661    //    pub variable_register_range: VariableRegisterRange,
1662    pub frame_size_for_variables_except_temp: FrameMemorySize,
1663}
1664
1665#[derive(Clone)]
1666pub struct FrameRelativeInfo {
1667    pub frame_memory_region: FrameMemoryRegion,
1668    pub kind: FrameAddressInfo,
1669}
1670
1671#[derive(Clone, Debug)]
1672pub struct PathInfo {
1673    pub steps: Vec<PathStep>,
1674}
1675
1676impl PathInfo {
1677    #[must_use]
1678    pub fn convert_to_string(&self) -> String {
1679        let path = &self.steps;
1680
1681        let last = path.last().unwrap();
1682
1683        let names: Vec<_> = path.iter().map(|x| x.item.name.to_string()).collect();
1684
1685        let types: Vec<_> = path.iter().map(|x| format!("{}", x.item.ty.kind)).collect();
1686
1687        let names_path = names.join(".");
1688        let types_path = types.join("->");
1689
1690        format!(
1691            "{:04X}:{:X} {} ({})",
1692            (last.origin + last.item.offset).0.bright_cyan(),
1693            last.item.ty.total_size.0.yellow(),
1694            names_path.bright_blue(),
1695            types_path.yellow(),
1696        )
1697    }
1698}
1699
1700#[derive(Clone, Debug)]
1701pub struct PathStep {
1702    pub item: OffsetMemoryItem,
1703    pub origin: FrameMemoryAddress,
1704}
1705
1706impl PathStep {
1707    #[must_use]
1708    pub const fn absolute_address(&self) -> FrameMemoryAddress {
1709        FrameMemoryAddress(self.origin.0 + self.item.offset.0)
1710    }
1711}
1712
1713impl FrameMemoryInfo {
1714    #[must_use]
1715    pub const fn size(&self) -> FrameMemorySize {
1716        self.total_frame_size
1717    }
1718
1719    /// Returns a vector of `OffsetMemoryItem` from root to the one containing the address.
1720    #[must_use]
1721    pub fn find_path_to_address_items(&self, target: FrameMemoryAddress) -> Option<PathInfo> {
1722        for info in &self.infos {
1723            // Synthesize a root OffsetMemoryItem
1724            let root_item = OffsetMemoryItem {
1725                offset: MemoryOffset(0),
1726                size: info.frame_placed_type.ty.total_size,
1727                name: info.kind.to_string(),
1728                ty: info.frame_placed_type.ty.clone(),
1729            };
1730            let base_addr = info.frame_placed_type.addr;
1731            let mut path = Vec::new();
1732            if find_in_item(&root_item, base_addr, target, &mut path) {
1733                return Some(PathInfo { steps: path });
1734            }
1735        }
1736        None
1737    }
1738}
1739fn find_in_item(
1740    item: &OffsetMemoryItem,
1741    base_addr: FrameMemoryAddress,
1742    target: FrameMemoryAddress,
1743    path: &mut Vec<PathStep>,
1744) -> bool {
1745    let item_addr = FrameMemoryAddress(base_addr.0 + item.offset.0);
1746    path.push(PathStep {
1747        item: item.clone(),
1748        origin: base_addr,
1749    });
1750
1751    if item_addr.0 == target.0 {
1752        return true;
1753    }
1754
1755    match &item.ty.kind {
1756        BasicTypeKind::Struct(st) => {
1757            for field in &st.fields {
1758                if find_in_item(field, item_addr, target, path) {
1759                    return true;
1760                }
1761            }
1762        }
1763        BasicTypeKind::Tuple(tt) => {
1764            for field in &tt.fields {
1765                if find_in_item(field, item_addr, target, path) {
1766                    return true;
1767                }
1768            }
1769        }
1770        BasicTypeKind::TaggedUnion(tu) => {
1771            for variant in &tu.variants {
1772                // Synthesize an OffsetMemoryItem for the variant
1773                let variant_item = OffsetMemoryItem {
1774                    offset: MemoryOffset(0),
1775                    size: variant.ty.total_size,
1776                    name: variant.name.clone(),
1777                    ty: variant.ty.clone(),
1778                };
1779                if find_in_item(&variant_item, item_addr, target, path) {
1780                    return true;
1781                }
1782            }
1783        }
1784        BasicTypeKind::Optional(tu) => {
1785            for variant in &tu.variants {
1786                let variant_item = OffsetMemoryItem {
1787                    offset: MemoryOffset(0),
1788                    size: variant.ty.total_size,
1789                    name: variant.name.clone(),
1790                    ty: variant.ty.clone(),
1791                };
1792                if find_in_item(&variant_item, item_addr, target, path) {
1793                    return true;
1794                }
1795            }
1796        }
1797        BasicTypeKind::SliceView(inner) => {
1798            let slice_item = OffsetMemoryItem {
1799                offset: MemoryOffset(0),
1800                size: inner.total_size,
1801                name: "slice".to_string(),
1802                ty: inner.clone(),
1803            };
1804            if find_in_item(&slice_item, item_addr, target, path) {
1805                return true;
1806            }
1807        }
1808        BasicTypeKind::DynamicLengthMapView(a, b) => {
1809            if find_in_item(a, item_addr, target, path) {
1810                return true;
1811            }
1812            if find_in_item(b, item_addr, target, path) {
1813                return true;
1814            }
1815        }
1816        _ => {}
1817    }
1818
1819    path.pop();
1820    false
1821}
1822
1823#[derive(Clone, Debug)]
1824pub enum FunctionInfoKind {
1825    Constant(usize),
1826    Normal(usize),
1827}
1828
1829#[derive(Clone, Debug)]
1830pub struct FunctionInfo {
1831    pub kind: FunctionInfoKind,
1832    pub frame_memory: FrameMemoryInfo,
1833    pub params: Vec<BasicTypeRef>,
1834    pub return_type: VmType,
1835    pub name: String,
1836    pub ip_range: InstructionRange,
1837}
1838
1839#[derive(Clone, Debug)]
1840pub struct CompleteFunctionInfo {
1841    pub ip: InstructionPosition,
1842    pub size: InstructionPositionOffset,
1843    pub info: FunctionInfo,
1844}
1845
1846pub fn new_line_and_tab(f: &mut dyn Write, tabs: usize) -> std::fmt::Result {
1847    let tab_str = "  ".repeat(tabs);
1848    writeln!(f)?;
1849    write!(f, "{tab_str}")
1850}
1851
1852pub fn show_memory_offset(
1853    offset: MemoryOffset,
1854    origin: FrameMemoryAddress,
1855    f: &mut dyn Write,
1856    _tabs: usize,
1857) -> std::fmt::Result {
1858    let result = origin + offset;
1859    write!(f, "{}+{:04X}", result, offset.0.yellow())
1860}
1861fn show_memory_size(size: MemorySize, f: &mut dyn Write, _tabs: usize) -> std::fmt::Result {
1862    write!(f, "{} ({})", size.green(), size.0)
1863}
1864
1865pub fn show_offset_item(
1866    offset_item: &OffsetMemoryItem,
1867    origin: FrameMemoryAddress,
1868    f: &mut dyn Write,
1869    tabs: usize,
1870) -> std::fmt::Result {
1871    show_memory_offset(offset_item.offset, origin, f, tabs)?;
1872    write!(f, ":")?;
1873    show_memory_size(offset_item.size, f, tabs)?;
1874    write!(f, " ")?;
1875    write_identifier_and_colon(&offset_item.name, f)?;
1876    let adjusted_origin = origin + offset_item.offset;
1877    write_basic_type(&offset_item.ty, adjusted_origin, f, tabs + 1)
1878}
1879
1880pub fn show_tagged_union(
1881    tagged_union: &TaggedUnion,
1882    origin: FrameMemoryAddress,
1883    f: &mut dyn Write,
1884    tabs: usize,
1885) -> std::fmt::Result {
1886    write!(f, "union tag_size:")?;
1887    show_memory_size(tagged_union.tag_size, f, tabs)?;
1888    write!(f, " max payload:")?;
1889    show_memory_size(tagged_union.payload_max_size, f, tabs)?;
1890
1891    let adjusted_payload_origin = origin + tagged_union.payload_offset;
1892
1893    for (index, union_data) in tagged_union
1894        .variants
1895        .clone()
1896        .into_iter()
1897        .take(4)
1898        .enumerate()
1899    {
1900        //iter().enumerate() {
1901        new_line_and_tab(f, tabs + 1)?;
1902        write!(f, "{}> ", index.bright_magenta())?;
1903        write_identifier_and_colon(&union_data.name, f)?;
1904        write_basic_type(&union_data.ty, adjusted_payload_origin, f, tabs + 1)?;
1905    }
1906    Ok(())
1907}
1908
1909pub fn show_struct_type(
1910    s: &StructType,
1911    origin: FrameMemoryAddress,
1912    f: &mut dyn Write,
1913    tabs: usize,
1914) -> std::fmt::Result {
1915    write!(f, "{} {{", s.name)?;
1916    for offset_item in &s.fields {
1917        new_line_and_tab(f, tabs + 1)?;
1918        show_offset_item(offset_item, origin, f, tabs + 1)?;
1919    }
1920    write!(f, " }}")
1921}
1922
1923pub fn show_tuple_type(
1924    s: &TupleType,
1925    origin: FrameMemoryAddress,
1926    f: &mut dyn Write,
1927    tabs: usize,
1928) -> std::fmt::Result {
1929    write!(f, "(")?;
1930    for offset_item in &s.fields {
1931        new_line_and_tab(f, tabs + 1)?;
1932        show_offset_item(offset_item, origin, f, tabs + 1)?;
1933    }
1934    write!(f, " )")
1935}
1936
1937pub fn write_identifier_and_colon(identifier: &str, f: &mut dyn Write) -> std::fmt::Result {
1938    write!(f, "{}: ", identifier.blue())
1939}
1940
1941pub fn write_basic_type(
1942    ty: &BasicType,
1943    origin: FrameMemoryAddress,
1944    f: &mut dyn Write,
1945    tabs: usize,
1946) -> std::fmt::Result {
1947    match &ty.kind {
1948        BasicTypeKind::Any => write!(f, "Any"),
1949        BasicTypeKind::Pointer => write!(f, "Ptr"),
1950        BasicTypeKind::Empty => write!(f, "()"),
1951        BasicTypeKind::U8 => write!(f, "{}", "u8".white()),
1952        BasicTypeKind::B8 => write!(f, "{}", "b8".white()),
1953        BasicTypeKind::U16 => write!(f, "{}", "u16".white()),
1954        BasicTypeKind::S32 => write!(f, "{}", "s32".white()),
1955        BasicTypeKind::Fixed32 => write!(f, "{}", "f32".white()),
1956        BasicTypeKind::U32 => write!(f, "{}", "u32".white()),
1957        BasicTypeKind::Struct(s) => show_struct_type(s, origin, f, tabs),
1958        BasicTypeKind::TaggedUnion(tagged_union) => {
1959            show_tagged_union(tagged_union, origin, f, tabs)
1960        }
1961        BasicTypeKind::Optional(tagged_union) => {
1962            write!(f, "Option<{}> ", tagged_union.variants[1].ty)?;
1963            show_tagged_union(tagged_union, origin, f, tabs)
1964        }
1965        BasicTypeKind::Tuple(tuple_type) => show_tuple_type(tuple_type, origin, f, tabs),
1966
1967        BasicTypeKind::SliceView(slice_inner_type) => {
1968            write!(f, "[|")?;
1969            write_basic_type(slice_inner_type, origin, f, tabs + 1)?;
1970            write!(f, "|]")
1971        }
1972        BasicTypeKind::DynamicLengthMapView(key_type, value_type) => {
1973            write!(f, "[|")?;
1974            show_offset_item(key_type, origin, f, tabs + 1)?;
1975            write!(f, ", ")?;
1976            show_offset_item(value_type, origin, f, tabs + 1)?;
1977            write!(f, "|]")
1978        }
1979        BasicTypeKind::StringView { .. } => {
1980            write!(f, "str")
1981        }
1982        BasicTypeKind::InternalRangeHeader => {
1983            write!(f, "range")
1984        }
1985
1986        BasicTypeKind::FixedCapacityArray(element_type, size) => {
1987            write!(f, "[{element_type}, {size}]")
1988        }
1989        BasicTypeKind::DynamicLengthVecView(element_type) => {
1990            write!(f, "Vec<{element_type}>")
1991        }
1992        BasicTypeKind::VecStorage(element_type, size) => {
1993            write!(f, "VecStorage<{element_type}, {size}>")
1994        }
1995        BasicTypeKind::StringStorage {
1996            element_type: byte,
1997            capacity,
1998            ..
1999        } => {
2000            write!(f, "StringStorage<{byte}, {capacity}>")
2001        }
2002        BasicTypeKind::QueueStorage(element_type, size) => {
2003            write!(f, "QueueStorage<{element_type}, {size}>")
2004        }
2005        BasicTypeKind::GridStorage(element_type, width, height) => {
2006            write!(f, "GridStorage<{element_type}, ({width},{height})>")
2007        }
2008        BasicTypeKind::StackStorage(element_type, size) => {
2009            write!(f, "StackStorage<{element_type}, {size}>")
2010        }
2011        BasicTypeKind::SparseView(element_type) => {
2012            write!(f, "Sparse<{element_type}>")
2013        }
2014        BasicTypeKind::GridView(element_type) => {
2015            write!(f, "grid<{element_type}>")
2016        }
2017        BasicTypeKind::SparseStorage(element_type, size) => {
2018            write!(f, "SparseStorage<{element_type}, {size}>")
2019        }
2020        BasicTypeKind::MapStorage {
2021            logical_limit: logical_size,
2022            key_type,
2023            value_type,
2024            ..
2025        } => {
2026            write!(f, "MapStorage<{key_type}, {value_type}, {logical_size}>",)
2027        }
2028        BasicTypeKind::InternalVecIterator => {
2029            write!(f, "vec_iter")
2030        }
2031        BasicTypeKind::InternalStringIterator => {
2032            write!(f, "str_iter")
2033        }
2034        BasicTypeKind::InternalRangeIterator => {
2035            write!(f, "range_iter")
2036        }
2037        BasicTypeKind::InternalMapIterator => {
2038            write!(f, "map_iter")
2039        }
2040        BasicTypeKind::InternalSparseIterator => {
2041            write!(f, "sparse_iter")
2042        }
2043    }
2044}
2045
2046pub fn show_frame_addr(
2047    addr: FrameMemoryAddress,
2048    f: &mut dyn Write,
2049    _tabs: usize,
2050) -> std::fmt::Result {
2051    write!(f, "{:04X}", addr.0.blue())
2052}
2053
2054pub fn show_frame_region(
2055    region: FrameMemoryRegion,
2056    f: &mut dyn Write,
2057    tabs: usize,
2058    use_color: bool,
2059) -> std::fmt::Result {
2060    if use_color {
2061        yansi::enable();
2062    } else {
2063        yansi::disable();
2064    }
2065    show_frame_addr(region.addr, f, tabs)?;
2066    write!(f, ":")?;
2067    show_memory_size(region.size, f, tabs)
2068}
2069
2070pub fn show_frame_memory(
2071    frame_relative_infos: &FrameMemoryInfo,
2072    f: &mut dyn Write,
2073    use_color: bool,
2074) -> std::fmt::Result {
2075    for mem in &frame_relative_infos.infos {
2076        let addr = mem.frame_placed_type.addr;
2077        show_frame_region(mem.frame_placed_type.region(), f, 0, use_color)?;
2078        write!(f, " ")?;
2079        match &mem.kind {
2080            VariableInfoKind::Variable(v) => {
2081                write!(f, "var ")?;
2082                write_identifier_and_colon(&v.name, f)?;
2083            }
2084            VariableInfoKind::Parameter(v) => {
2085                write!(f, "param ")?;
2086                write_identifier_and_colon(&v.name, f)?;
2087            }
2088            VariableInfoKind::Return => {
2089                write!(f, "return:")?;
2090            }
2091        }
2092        write!(f, " ")?;
2093        write_basic_type(&mem.frame_placed_type.ty, addr, f, 0)?;
2094        writeln!(f)?;
2095    }
2096
2097    writeln!(
2098        f,
2099        "frame size for variables: {:0}",
2100        frame_relative_infos.frame_size_for_variables_except_temp
2101    )?;
2102    Ok(())
2103}
2104
2105impl Hash for BasicType {
2106    fn hash<H: Hasher>(&self, state: &mut H) {
2107        // Remember: do not include the application-specific ID in the universal hash
2108        // Only hash the structural components
2109        self.kind.hash(state);
2110        self.total_size.0.hash(state);
2111        self.max_alignment.hash(state);
2112    }
2113}
2114
2115impl Hash for BasicTypeKind {
2116    fn hash<H: Hasher>(&self, state: &mut H) {
2117        std::mem::discriminant(self).hash(state);
2118
2119        match self {
2120            Self::Any => {}
2121            Self::Pointer => {}
2122            Self::Empty => {}
2123            Self::U8 => {}
2124            Self::B8 => {}
2125            Self::U16 => {}
2126            Self::S32 => {}
2127            Self::Fixed32 => {}
2128            Self::U32 => {}
2129            Self::InternalRangeHeader => {}
2130            Self::InternalVecIterator => {}
2131            Self::InternalStringIterator => {}
2132            Self::InternalMapIterator => {}
2133            Self::InternalSparseIterator => {}
2134            Self::InternalRangeIterator => {}
2135
2136            Self::StringView { byte, char } => {
2137                byte.universal_hash(state);
2138                char.universal_hash(state);
2139            }
2140
2141            Self::Struct(struct_type) => {
2142                struct_type.hash(state);
2143            }
2144
2145            Self::TaggedUnion(union) => {
2146                union.hash(state);
2147            }
2148
2149            Self::Tuple(tuple_type) => {
2150                tuple_type.hash(state);
2151            }
2152
2153            Self::Optional(optional) => {
2154                optional.hash(state);
2155            }
2156
2157            Self::SliceView(inner) => {
2158                inner.universal_hash(state);
2159            }
2160
2161            Self::FixedCapacityArray(inner, size) => {
2162                inner.universal_hash(state);
2163                size.hash(state);
2164            }
2165
2166            Self::DynamicLengthVecView(inner) => {
2167                inner.universal_hash(state);
2168            }
2169
2170            Self::VecStorage(inner, size) => {
2171                inner.universal_hash(state);
2172                size.hash(state);
2173            }
2174
2175            Self::StringStorage {
2176                element_type,
2177                char,
2178                capacity,
2179            } => {
2180                element_type.universal_hash(state);
2181                char.universal_hash(state);
2182                capacity.hash(state);
2183            }
2184
2185            Self::StackStorage(inner, size) => {
2186                inner.universal_hash(state);
2187                size.hash(state);
2188            }
2189
2190            Self::QueueStorage(inner, size) => {
2191                inner.universal_hash(state);
2192                size.hash(state);
2193            }
2194
2195            Self::MapStorage {
2196                key_type,
2197                value_type,
2198                logical_limit,
2199                capacity,
2200            } => {
2201                key_type.universal_hash(state);
2202                value_type.universal_hash(state);
2203                logical_limit.hash(state);
2204                capacity.0.hash(state);
2205            }
2206
2207            Self::SparseView(inner) => {
2208                inner.universal_hash(state);
2209            }
2210
2211            Self::SparseStorage(inner, size) => {
2212                inner.universal_hash(state);
2213                size.hash(state);
2214            }
2215
2216            Self::DynamicLengthMapView(key, value) => {
2217                key.hash(state);
2218                value.hash(state);
2219            }
2220
2221            Self::GridView(inner) => {
2222                inner.universal_hash(state);
2223            }
2224
2225            Self::GridStorage(inner, width, height) => {
2226                inner.universal_hash(state);
2227                width.hash(state);
2228                height.hash(state);
2229            }
2230        }
2231    }
2232}
2233
2234impl Hash for StructType {
2235    fn hash<H: Hasher>(&self, state: &mut H) {
2236        self.name.hash(state);
2237        // Hash fields in a deterministic order
2238        for field in &self.fields {
2239            field.hash(state);
2240        }
2241        self.total_size.0.hash(state);
2242        self.max_alignment.hash(state);
2243    }
2244}
2245
2246impl Hash for TupleType {
2247    fn hash<H: Hasher>(&self, state: &mut H) {
2248        // Hash fields in order
2249        for field in &self.fields {
2250            field.hash(state);
2251        }
2252        self.total_size.0.hash(state);
2253        self.max_alignment.hash(state);
2254    }
2255}
2256
2257impl Hash for TaggedUnion {
2258    fn hash<H: Hasher>(&self, state: &mut H) {
2259        self.name.hash(state);
2260        self.tag_offset.0.hash(state);
2261        self.tag_alignment.hash(state);
2262        self.tag_size.0.hash(state);
2263        self.payload_max_size.0.hash(state);
2264        self.max_payload_alignment.hash(state);
2265        self.payload_offset.0.hash(state);
2266
2267        // Hash variants in order
2268        for variant in &self.variants {
2269            variant.hash(state);
2270        }
2271
2272        self.total_size.0.hash(state);
2273        self.max_alignment.hash(state);
2274    }
2275}
2276
2277impl Hash for TaggedUnionVariant {
2278    fn hash<H: Hasher>(&self, state: &mut H) {
2279        self.name.hash(state);
2280        self.ty.universal_hash(state);
2281    }
2282}
2283
2284impl Hash for OffsetMemoryItem {
2285    fn hash<H: Hasher>(&self, state: &mut H) {
2286        self.offset.0.hash(state);
2287        self.size.0.hash(state);
2288        self.name.hash(state);
2289        self.ty.universal_hash(state);
2290    }
2291}
2292
2293// Add universal hash methods to BasicType
2294impl BasicType {
2295    /// Computes a universal hash based on the type's structure, independent of application-specific IDs.
2296    /// This is useful for RPC calls and serialization in general.
2297    ///
2298    /// Two types with the same structure will have the same universal hash across different applications,
2299    /// even if they have different `BasicTypeId` values.
2300    pub fn universal_hash<H: Hasher>(&self, state: &mut H) {
2301        self.hash(state);
2302    }
2303
2304    /// Computes a universal hash and returns it as an u64.
2305    #[must_use]
2306    pub fn universal_hash_u64(&self) -> u64 {
2307        let mut hasher = FxHasher::default();
2308        self.universal_hash(&mut hasher);
2309        hasher.finish()
2310    }
2311}