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 seq_fmt::comma;
16use std::cmp::{max, Ordering};
17use std::fmt::{Debug, Display, Formatter, Write};
18use std::hash::{Hash, Hasher};
19use std::rc::Rc;
20use tracing::error;
21use yansi::Paint;
22
23pub type BasicTypeRef = Rc<BasicType>;
24
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 return_type: VmType,
1785    pub name: String,
1786    pub ip_range: InstructionRange,
1787}
1788
1789#[derive(Clone, Debug)]
1790pub struct CompleteFunctionInfo {
1791    pub ip: InstructionPosition,
1792    pub size: InstructionPositionOffset,
1793    pub info: FunctionInfo,
1794}
1795
1796pub fn new_line_and_tab(f: &mut dyn Write, tabs: usize) -> std::fmt::Result {
1797    let tab_str = "  ".repeat(tabs);
1798    writeln!(f)?;
1799    write!(f, "{tab_str}")
1800}
1801
1802pub fn show_memory_offset(
1803    offset: MemoryOffset,
1804    origin: FrameMemoryAddress,
1805    f: &mut dyn Write,
1806    _tabs: usize,
1807) -> std::fmt::Result {
1808    let result = origin + offset;
1809    write!(f, "{}+{:04X}", result, offset.0.yellow())
1810}
1811fn show_memory_size(size: MemorySize, f: &mut dyn Write, _tabs: usize) -> std::fmt::Result {
1812    write!(f, "{} ({})", size.green(), size.0)
1813}
1814
1815pub fn show_offset_item(
1816    offset_item: &OffsetMemoryItem,
1817    origin: FrameMemoryAddress,
1818    f: &mut dyn Write,
1819    tabs: usize,
1820) -> std::fmt::Result {
1821    show_memory_offset(offset_item.offset, origin, f, tabs)?;
1822    write!(f, ":")?;
1823    show_memory_size(offset_item.size, f, tabs)?;
1824    write!(f, " ")?;
1825    write_identifier_and_colon(&offset_item.name, f)?;
1826    let adjusted_origin = origin + offset_item.offset;
1827    write_basic_type(&offset_item.ty, adjusted_origin, f, tabs + 1)
1828}
1829
1830pub fn show_tagged_union(
1831    tagged_union: &TaggedUnion,
1832    origin: FrameMemoryAddress,
1833    f: &mut dyn Write,
1834    tabs: usize,
1835) -> std::fmt::Result {
1836    write!(f, "union tag_size:")?;
1837    show_memory_size(tagged_union.tag_size, f, tabs)?;
1838    write!(f, " max payload:")?;
1839    show_memory_size(tagged_union.payload_max_size, f, tabs)?;
1840
1841    let adjusted_payload_origin = origin + tagged_union.payload_offset;
1842
1843    for (index, union_data) in tagged_union
1844        .variants
1845        .clone()
1846        .into_iter()
1847        .take(4)
1848        .enumerate()
1849    {
1850        //iter().enumerate() {
1851        new_line_and_tab(f, tabs + 1)?;
1852        write!(f, "{}> ", index.bright_magenta())?;
1853        write_identifier_and_colon(&union_data.name, f)?;
1854        write_basic_type(&union_data.ty, adjusted_payload_origin, f, tabs + 1)?;
1855    }
1856    Ok(())
1857}
1858
1859pub fn show_struct_type(
1860    s: &StructType,
1861    origin: FrameMemoryAddress,
1862    f: &mut dyn Write,
1863    tabs: usize,
1864) -> std::fmt::Result {
1865    write!(f, "{} {{", s.name)?;
1866    for offset_item in &s.fields {
1867        new_line_and_tab(f, tabs + 1)?;
1868        show_offset_item(offset_item, origin, f, tabs + 1)?;
1869    }
1870    write!(f, " }}")
1871}
1872
1873pub fn show_tuple_type(
1874    s: &TupleType,
1875    origin: FrameMemoryAddress,
1876    f: &mut dyn Write,
1877    tabs: usize,
1878) -> std::fmt::Result {
1879    write!(f, "(")?;
1880    for offset_item in &s.fields {
1881        new_line_and_tab(f, tabs + 1)?;
1882        show_offset_item(offset_item, origin, f, tabs + 1)?;
1883    }
1884    write!(f, " )")
1885}
1886
1887pub fn write_identifier_and_colon(identifier: &str, f: &mut dyn Write) -> std::fmt::Result {
1888    write!(f, "{}: ", identifier.blue())
1889}
1890
1891pub fn write_basic_type(
1892    ty: &BasicType,
1893    origin: FrameMemoryAddress,
1894    f: &mut dyn Write,
1895    tabs: usize,
1896) -> std::fmt::Result {
1897    match &ty.kind {
1898        BasicTypeKind::Any => write!(f, "Any"),
1899        BasicTypeKind::Empty => write!(f, "()"),
1900        BasicTypeKind::U8 => write!(f, "{}", "u8".white()),
1901        BasicTypeKind::B8 => write!(f, "{}", "b8".white()),
1902        BasicTypeKind::U16 => write!(f, "{}", "u16".white()),
1903        BasicTypeKind::S32 => write!(f, "{}", "s32".white()),
1904        BasicTypeKind::Fixed32 => write!(f, "{}", "f32".white()),
1905        BasicTypeKind::U32 => write!(f, "{}", "u32".white()),
1906        BasicTypeKind::Struct(s) => show_struct_type(s, origin, f, tabs),
1907        BasicTypeKind::TaggedUnion(tagged_union) => {
1908            show_tagged_union(tagged_union, origin, f, tabs)
1909        }
1910        BasicTypeKind::Optional(tagged_union) => {
1911            write!(f, "Option<{}> ", tagged_union.variants[1].ty)?;
1912            show_tagged_union(tagged_union, origin, f, tabs)
1913        }
1914        BasicTypeKind::Tuple(tuple_type) => show_tuple_type(tuple_type, origin, f, tabs),
1915
1916        BasicTypeKind::SliceView(slice_inner_type) => {
1917            write!(f, "[|")?;
1918            write_basic_type(slice_inner_type, origin, f, tabs + 1)?;
1919            write!(f, "|]")
1920        }
1921        BasicTypeKind::DynamicLengthMapView(key_type, value_type) => {
1922            write!(f, "[|")?;
1923            show_offset_item(key_type, origin, f, tabs + 1)?;
1924            write!(f, ", ")?;
1925            show_offset_item(value_type, origin, f, tabs + 1)?;
1926            write!(f, "|]")
1927        }
1928        BasicTypeKind::StringView { .. } => {
1929            write!(f, "str")
1930        }
1931        BasicTypeKind::InternalRangeHeader => {
1932            write!(f, "range")
1933        }
1934
1935        BasicTypeKind::FixedCapacityArray(element_type, size) => {
1936            write!(f, "[{element_type}, {size}]")
1937        }
1938        BasicTypeKind::DynamicLengthVecView(element_type) => {
1939            write!(f, "Vec<{element_type}>")
1940        }
1941        BasicTypeKind::VecStorage(element_type, size) => {
1942            write!(f, "VecStorage<{element_type}, {size}>")
1943        }
1944        BasicTypeKind::StringStorage {
1945            element_type: byte,
1946            capacity,
1947            ..
1948        } => {
1949            write!(f, "StringStorage<{byte}, {capacity}>")
1950        }
1951        BasicTypeKind::QueueStorage(element_type, size) => {
1952            write!(f, "QueueStorage<{element_type}, {size}>")
1953        }
1954        BasicTypeKind::GridStorage(element_type, width, height) => {
1955            write!(f, "GridStorage<{element_type}, ({width},{height})>")
1956        }
1957        BasicTypeKind::StackStorage(element_type, size) => {
1958            write!(f, "StackStorage<{element_type}, {size}>")
1959        }
1960        BasicTypeKind::SparseView(element_type) => {
1961            write!(f, "Sparse<{element_type}>")
1962        }
1963        BasicTypeKind::GridView(element_type) => {
1964            write!(f, "grid<{element_type}>")
1965        }
1966        BasicTypeKind::SparseStorage(element_type, size) => {
1967            write!(f, "SparseStorage<{element_type}, {size}>")
1968        }
1969        BasicTypeKind::MapStorage {
1970            logical_limit: logical_size,
1971            key_type,
1972            value_type,
1973            ..
1974        } => {
1975            write!(f, "MapStorage<{key_type}, {value_type}, {logical_size}>", )
1976        }
1977        BasicTypeKind::InternalVecIterator => {
1978            write!(f, "vec_iter")
1979        }
1980        BasicTypeKind::InternalStringIterator => {
1981            write!(f, "str_iter")
1982        }
1983        BasicTypeKind::InternalRangeIterator => {
1984            write!(f, "range_iter")
1985        }
1986        BasicTypeKind::InternalMapIterator => {
1987            write!(f, "map_iter")
1988        }
1989        BasicTypeKind::InternalSparseIterator => {
1990            write!(f, "sparse_iter")
1991        }
1992    }
1993}
1994
1995pub fn show_frame_addr(
1996    addr: FrameMemoryAddress,
1997    f: &mut dyn Write,
1998    _tabs: usize,
1999) -> std::fmt::Result {
2000    write!(f, "{:04X}", addr.0.blue())
2001}
2002
2003pub fn show_frame_region(
2004    region: FrameMemoryRegion,
2005    f: &mut dyn Write,
2006    tabs: usize,
2007) -> std::fmt::Result {
2008    show_frame_addr(region.addr, f, tabs)?;
2009    write!(f, ":")?;
2010    show_memory_size(region.size, f, tabs)
2011}
2012
2013pub fn show_frame_memory(
2014    frame_relative_infos: &FrameMemoryInfo,
2015    f: &mut dyn Write,
2016) -> std::fmt::Result {
2017    for mem in &frame_relative_infos.infos {
2018        let addr = mem.frame_placed_type.addr;
2019        show_frame_region(mem.frame_placed_type.region(), f, 0)?;
2020        write!(f, " ")?;
2021        match &mem.kind {
2022            VariableInfoKind::Variable(v) => {
2023                write!(f, "var ")?;
2024                write_identifier_and_colon(&v.name, f)?;
2025            }
2026            VariableInfoKind::Parameter(v) => {
2027                write!(f, "param ")?;
2028                write_identifier_and_colon(&v.name, f)?;
2029            }
2030            VariableInfoKind::Return => {
2031                write!(f, "return:")?;
2032            }
2033        }
2034        write!(f, " ")?;
2035        write_basic_type(&mem.frame_placed_type.ty, addr, f, 0)?;
2036        writeln!(f)?;
2037    }
2038
2039    writeln!(
2040        f,
2041        "frame size for variables: {:0}",
2042        frame_relative_infos.frame_size_for_variables_except_temp
2043    )?;
2044    Ok(())
2045}
2046
2047impl Hash for BasicType {
2048    fn hash<H: Hasher>(&self, state: &mut H) {
2049        // Remember: do not include the application-specific ID in the universal hash
2050        // Only hash the structural components
2051        self.kind.hash(state);
2052        self.total_size.0.hash(state);
2053        self.max_alignment.hash(state);
2054    }
2055}
2056
2057impl Hash for BasicTypeKind {
2058    fn hash<H: Hasher>(&self, state: &mut H) {
2059        std::mem::discriminant(self).hash(state);
2060
2061        match self {
2062            Self::Any => panic!("not allowed to perform hash on any"),
2063            Self::Empty => {}
2064            Self::U8 => {}
2065            Self::B8 => {}
2066            Self::U16 => {}
2067            Self::S32 => {}
2068            Self::Fixed32 => {}
2069            Self::U32 => {}
2070            Self::InternalRangeHeader => {}
2071            Self::InternalVecIterator => {}
2072            Self::InternalStringIterator => {}
2073            Self::InternalMapIterator => {}
2074            Self::InternalSparseIterator => {}
2075            Self::InternalRangeIterator => {}
2076
2077            Self::StringView { byte, char } => {
2078                byte.universal_hash(state);
2079                char.universal_hash(state);
2080            }
2081
2082            Self::Struct(struct_type) => {
2083                struct_type.hash(state);
2084            }
2085
2086            Self::TaggedUnion(union) => {
2087                union.hash(state);
2088            }
2089
2090            Self::Tuple(tuple_type) => {
2091                tuple_type.hash(state);
2092            }
2093
2094            Self::Optional(optional) => {
2095                optional.hash(state);
2096            }
2097
2098            Self::SliceView(inner) => {
2099                inner.universal_hash(state);
2100            }
2101
2102            Self::FixedCapacityArray(inner, size) => {
2103                inner.universal_hash(state);
2104                size.hash(state);
2105            }
2106
2107            Self::DynamicLengthVecView(inner) => {
2108                inner.universal_hash(state);
2109            }
2110
2111            Self::VecStorage(inner, size) => {
2112                inner.universal_hash(state);
2113                size.hash(state);
2114            }
2115
2116            Self::StringStorage { element_type, char, capacity } => {
2117                element_type.universal_hash(state);
2118                char.universal_hash(state);
2119                capacity.hash(state);
2120            }
2121
2122            Self::StackStorage(inner, size) => {
2123                inner.universal_hash(state);
2124                size.hash(state);
2125            }
2126
2127            Self::QueueStorage(inner, size) => {
2128                inner.universal_hash(state);
2129                size.hash(state);
2130            }
2131
2132            Self::MapStorage { key_type, value_type, logical_limit, capacity } => {
2133                key_type.universal_hash(state);
2134                value_type.universal_hash(state);
2135                logical_limit.hash(state);
2136                capacity.0.hash(state);
2137            }
2138
2139            Self::SparseView(inner) => {
2140                inner.universal_hash(state);
2141            }
2142
2143            Self::SparseStorage(inner, size) => {
2144                inner.universal_hash(state);
2145                size.hash(state);
2146            }
2147
2148            Self::DynamicLengthMapView(key, value) => {
2149                key.hash(state);
2150                value.hash(state);
2151            }
2152
2153            Self::GridView(inner) => {
2154                inner.universal_hash(state);
2155            }
2156
2157            Self::GridStorage(inner, width, height) => {
2158                inner.universal_hash(state);
2159                width.hash(state);
2160                height.hash(state);
2161            }
2162        }
2163    }
2164}
2165
2166impl Hash for StructType {
2167    fn hash<H: Hasher>(&self, state: &mut H) {
2168        self.name.hash(state);
2169        // Hash fields in a deterministic order
2170        for field in &self.fields {
2171            field.hash(state);
2172        }
2173        self.total_size.0.hash(state);
2174        self.max_alignment.hash(state);
2175    }
2176}
2177
2178impl Hash for TupleType {
2179    fn hash<H: Hasher>(&self, state: &mut H) {
2180        // Hash fields in order
2181        for field in &self.fields {
2182            field.hash(state);
2183        }
2184        self.total_size.0.hash(state);
2185        self.max_alignment.hash(state);
2186    }
2187}
2188
2189impl Hash for TaggedUnion {
2190    fn hash<H: Hasher>(&self, state: &mut H) {
2191        self.name.hash(state);
2192        self.tag_offset.0.hash(state);
2193        self.tag_alignment.hash(state);
2194        self.tag_size.0.hash(state);
2195        self.payload_max_size.0.hash(state);
2196        self.max_payload_alignment.hash(state);
2197        self.payload_offset.0.hash(state);
2198
2199        // Hash variants in order
2200        for variant in &self.variants {
2201            variant.hash(state);
2202        }
2203
2204        self.total_size.0.hash(state);
2205        self.max_alignment.hash(state);
2206    }
2207}
2208
2209impl Hash for TaggedUnionVariant {
2210    fn hash<H: Hasher>(&self, state: &mut H) {
2211        self.name.hash(state);
2212        self.ty.universal_hash(state);
2213    }
2214}
2215
2216impl Hash for OffsetMemoryItem {
2217    fn hash<H: Hasher>(&self, state: &mut H) {
2218        self.offset.0.hash(state);
2219        self.size.0.hash(state);
2220        self.name.hash(state);
2221        self.ty.universal_hash(state);
2222    }
2223}
2224
2225// Add universal hash methods to BasicType
2226impl BasicType {
2227    /// Computes a universal hash based on the type's structure, independent of application-specific IDs.
2228    /// This is useful for RPC calls and serialization in general.
2229    ///
2230    /// Two types with the same structure will have the same universal hash across different applications,
2231    /// even if they have different `BasicTypeId` values.
2232    pub fn universal_hash<H: Hasher>(&self, state: &mut H) {
2233        self.hash(state);
2234    }
2235
2236    /// Computes a universal hash and returns it as an u64.
2237    #[must_use] pub fn universal_hash_u64(&self) -> u64 {
2238        let mut hasher = std::collections::hash_map::DefaultHasher::new();
2239        self.universal_hash(&mut hasher);
2240        hasher.finish()
2241    }
2242}