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