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