1use super::core::Module;
4#[cfg(feature = "component-model")]
5use crate::validator::component::ComponentState;
6#[cfg(feature = "component-model")]
7use crate::validator::component_types::{ComponentTypeAlloc, ComponentTypeList};
8use crate::{AbstractHeapType, collections::map::Entry};
9use crate::{CompositeInnerType, prelude::*};
10use crate::{
11 Export, ExternalKind, GlobalType, Import, Matches, MemoryType, PackedIndex, RecGroup, RefType,
12 Result, SubType, TableType, TypeRef, UnpackedIndex, ValType, WithRecGroup,
13};
14use crate::{FuncType, HeapType, ValidatorId};
15use alloc::sync::Arc;
16use core::ops::{Deref, DerefMut, Index, Range};
17use core::{hash::Hash, mem};
18
19pub trait TypeIdentifier: core::fmt::Debug + Copy + Eq + Sized + 'static {
25 type Data: TypeData<Id = Self>;
27
28 #[doc(hidden)]
30 fn from_index(index: u32) -> Self;
31
32 #[doc(hidden)]
35 fn list(types: &TypeList) -> &SnapshotList<Self::Data>;
36
37 #[doc(hidden)]
40 fn list_mut(types: &mut TypeList) -> &mut SnapshotList<Self::Data>;
41
42 #[doc(hidden)]
44 fn index(&self) -> usize;
45}
46
47pub trait TypeData: core::fmt::Debug {
52 type Id: TypeIdentifier<Data = Self>;
54
55 const IS_CORE_SUB_TYPE: bool;
57
58 #[doc(hidden)]
60 fn type_info(&self, types: &TypeList) -> TypeInfo;
61}
62
63macro_rules! define_type_id {
64 ($name:ident, $data:ty, $($list:ident).*, $type_str:expr) => {
65 #[doc = "Represents a unique identifier for a "]
66 #[doc = $type_str]
67 #[doc = " type known to a [`crate::Validator`]."]
68 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
69 #[repr(C)] pub struct $name {
71 index: u32,
73 }
74
75 impl TypeIdentifier for $name {
76 type Data = $data;
77
78 fn from_index(index: u32) -> Self {
79 $name { index }
80 }
81
82 fn list(types: &TypeList) -> &SnapshotList<Self::Data> {
83 &types.$($list).*
84 }
85
86 fn list_mut(types: &mut TypeList) -> &mut SnapshotList<Self::Data> {
87 &mut types.$($list).*
88 }
89
90 fn index(&self) -> usize {
91 usize::try_from(self.index).unwrap()
92 }
93 }
94
95
96 const _: () = {
99 assert!(core::mem::size_of::<$name>() <= 4);
100 };
101 };
102}
103#[cfg(feature = "component-model")]
104pub(crate) use define_type_id;
105
106#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
109#[repr(C)]
110pub struct CoreTypeId {
111 index: u32,
112}
113
114#[test]
115fn assert_core_type_id_small() {
116 assert!(core::mem::size_of::<CoreTypeId>() <= 4);
117}
118
119impl TypeIdentifier for CoreTypeId {
120 type Data = SubType;
121
122 fn from_index(index: u32) -> Self {
123 CoreTypeId { index }
124 }
125
126 fn list(types: &TypeList) -> &SnapshotList<Self::Data> {
127 &types.core_types
128 }
129
130 fn list_mut(types: &mut TypeList) -> &mut SnapshotList<Self::Data> {
131 &mut types.core_types
132 }
133
134 fn index(&self) -> usize {
135 usize::try_from(self.index).unwrap()
136 }
137}
138
139impl TypeData for SubType {
140 type Id = CoreTypeId;
141 const IS_CORE_SUB_TYPE: bool = true;
142 fn type_info(&self, _types: &TypeList) -> TypeInfo {
143 let size = 1 + match &self.composite_type.inner {
145 CompositeInnerType::Func(ty) => 1 + (ty.params().len() + ty.results().len()) as u32,
146 CompositeInnerType::Array(_) => 2,
147 CompositeInnerType::Struct(ty) => 1 + 2 * ty.fields.len() as u32,
148 CompositeInnerType::Cont(_) => 1,
149 };
150 TypeInfo::core(size)
151 }
152}
153
154define_type_id!(
155 RecGroupId,
156 Range<CoreTypeId>,
157 rec_group_elements,
158 "recursion group"
159);
160
161impl TypeData for Range<CoreTypeId> {
162 type Id = RecGroupId;
163 const IS_CORE_SUB_TYPE: bool = true;
164 fn type_info(&self, _types: &TypeList) -> TypeInfo {
165 let size = self.end.index() - self.start.index();
166 TypeInfo::core(u32::try_from(size).unwrap())
167 }
168}
169
170#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
193#[doc(hidden)]
195pub struct TypeInfo(u32);
196
197impl TypeInfo {
198 pub(crate) fn new() -> TypeInfo {
203 TypeInfo::_new(1, false)
204 }
205
206 #[cfg(feature = "component-model")]
209 pub(crate) fn borrow() -> TypeInfo {
210 TypeInfo::_new(1, true)
211 }
212
213 pub(crate) fn core(size: u32) -> TypeInfo {
216 TypeInfo::_new(size, false)
217 }
218
219 fn _new(size: u32, contains_borrow: bool) -> TypeInfo {
220 assert!(size < (1 << 24));
221 TypeInfo(size | ((contains_borrow as u32) << 31))
222 }
223
224 #[cfg(feature = "component-model")]
233 pub(crate) fn combine(&mut self, other: TypeInfo, offset: usize) -> Result<()> {
234 *self = TypeInfo::_new(
235 super::combine_type_sizes(self.size(), other.size(), offset)?,
236 self.contains_borrow() || other.contains_borrow(),
237 );
238 Ok(())
239 }
240
241 pub(crate) fn size(&self) -> u32 {
242 self.0 & 0xffffff
243 }
244
245 #[cfg(feature = "component-model")]
246 pub(crate) fn contains_borrow(&self) -> bool {
247 (self.0 >> 31) != 0
248 }
249}
250
251#[derive(Debug, Clone, Copy, PartialEq, Eq)]
253pub enum EntityType {
254 Func(CoreTypeId),
256 Table(TableType),
258 Memory(MemoryType),
260 Global(GlobalType),
262 Tag(CoreTypeId),
264 FuncExact(CoreTypeId),
266}
267
268impl EntityType {
269 #[cfg(feature = "component-model")]
270 pub(crate) fn desc(&self) -> &'static str {
271 match self {
272 Self::Func(_) => "func",
273 Self::Table(_) => "table",
274 Self::Memory(_) => "memory",
275 Self::Global(_) => "global",
276 Self::Tag(_) => "tag",
277 Self::FuncExact(_) => "func_exact",
278 }
279 }
280
281 pub(crate) fn info(&self, types: &TypeList) -> TypeInfo {
282 match self {
283 Self::Func(id) | Self::Tag(id) | Self::FuncExact(id) => types[*id].type_info(types),
284 Self::Table(_) | Self::Memory(_) | Self::Global(_) => TypeInfo::new(),
285 }
286 }
287}
288
289#[allow(clippy::large_enum_variant)]
290pub(super) enum TypesKind {
291 Module(Arc<Module>),
292 #[cfg(feature = "component-model")]
293 Component(ComponentState),
294}
295
296pub struct Types {
300 id: ValidatorId,
301 pub(super) list: TypeList,
302 pub(super) kind: TypesKind,
303}
304
305#[derive(Clone, Copy)]
306pub(super) enum TypesRefKind<'a> {
307 Module(&'a Module),
308 #[cfg(feature = "component-model")]
309 Component(&'a ComponentState),
310}
311
312#[derive(Clone, Copy)]
316pub struct TypesRef<'a> {
317 id: ValidatorId,
318 pub(super) list: &'a TypeList,
319 pub(super) kind: TypesRefKind<'a>,
320}
321
322impl<'a> TypesRef<'a> {
323 pub(crate) fn from_module(id: ValidatorId, types: &'a TypeList, module: &'a Module) -> Self {
324 Self {
325 id,
326 list: types,
327 kind: TypesRefKind::Module(module),
328 }
329 }
330
331 #[cfg(feature = "component-model")]
332 pub(crate) fn from_component(
333 id: ValidatorId,
334 types: &'a TypeList,
335 component: &'a ComponentState,
336 ) -> Self {
337 Self {
338 id,
339 list: types,
340 kind: TypesRefKind::Component(component),
341 }
342 }
343
344 #[inline]
346 pub fn id(&self) -> ValidatorId {
347 self.id
348 }
349
350 pub fn get<T>(&self, id: T) -> Option<&'a T::Data>
354 where
355 T: TypeIdentifier,
356 {
357 self.list.get(id)
358 }
359
360 pub fn rec_group_id_of(&self, id: CoreTypeId) -> RecGroupId {
362 self.list.rec_group_id_of(id)
363 }
364
365 pub fn rec_group_elements(&self, id: RecGroupId) -> impl ExactSizeIterator<Item = CoreTypeId> {
367 let range = &self.list.rec_group_elements[id];
368 (range.start.index..range.end.index).map(|index| CoreTypeId { index })
369 }
370
371 pub fn supertype_of(&self, id: CoreTypeId) -> Option<CoreTypeId> {
373 self.list.supertype_of(id)
374 }
375
376 pub fn core_type_at_in_module(&self, index: u32) -> CoreTypeId {
387 match &self.kind {
388 TypesRefKind::Module(module) => module.types[index as usize].into(),
389 #[cfg(feature = "component-model")]
390 TypesRefKind::Component(_) => panic!("use `core_type_at_in_component` instead"),
391 }
392 }
393
394 pub fn core_type_count_in_module(&self) -> u32 {
399 match &self.kind {
400 TypesRefKind::Module(module) => module.types.len() as u32,
401 #[cfg(feature = "component-model")]
402 TypesRefKind::Component(_) => 0,
403 }
404 }
405
406 pub fn table_at(&self, index: u32) -> TableType {
412 let tables = match &self.kind {
413 TypesRefKind::Module(module) => &module.tables,
414 #[cfg(feature = "component-model")]
415 TypesRefKind::Component(component) => &component.core_tables,
416 };
417 tables[index as usize]
418 }
419
420 pub fn table_count(&self) -> u32 {
422 match &self.kind {
423 TypesRefKind::Module(module) => module.tables.len() as u32,
424 #[cfg(feature = "component-model")]
425 TypesRefKind::Component(component) => component.core_tables.len() as u32,
426 }
427 }
428
429 pub fn memory_at(&self, index: u32) -> MemoryType {
435 let memories = match &self.kind {
436 TypesRefKind::Module(module) => &module.memories,
437 #[cfg(feature = "component-model")]
438 TypesRefKind::Component(component) => &component.core_memories,
439 };
440
441 memories[index as usize]
442 }
443
444 pub fn memory_count(&self) -> u32 {
446 match &self.kind {
447 TypesRefKind::Module(module) => module.memories.len() as u32,
448 #[cfg(feature = "component-model")]
449 TypesRefKind::Component(component) => component.core_memories.len() as u32,
450 }
451 }
452
453 pub fn global_at(&self, index: u32) -> GlobalType {
459 let globals = match &self.kind {
460 TypesRefKind::Module(module) => &module.globals,
461 #[cfg(feature = "component-model")]
462 TypesRefKind::Component(component) => &component.core_globals,
463 };
464
465 globals[index as usize]
466 }
467
468 pub fn global_count(&self) -> u32 {
470 match &self.kind {
471 TypesRefKind::Module(module) => module.globals.len() as u32,
472 #[cfg(feature = "component-model")]
473 TypesRefKind::Component(component) => component.core_globals.len() as u32,
474 }
475 }
476
477 pub fn tag_at(&self, index: u32) -> CoreTypeId {
483 let tags = match &self.kind {
484 TypesRefKind::Module(module) => &module.tags,
485 #[cfg(feature = "component-model")]
486 TypesRefKind::Component(component) => &component.core_tags,
487 };
488 tags[index as usize]
489 }
490
491 pub fn tag_count(&self) -> u32 {
493 match &self.kind {
494 TypesRefKind::Module(module) => module.tags.len() as u32,
495 #[cfg(feature = "component-model")]
496 TypesRefKind::Component(component) => component.core_tags.len() as u32,
497 }
498 }
499
500 pub fn core_function_at(&self, index: u32) -> CoreTypeId {
506 match &self.kind {
507 TypesRefKind::Module(module) => module.types[module.functions[index as usize] as usize],
508 #[cfg(feature = "component-model")]
509 TypesRefKind::Component(component) => component.core_funcs[index as usize],
510 }
511 }
512
513 pub fn function_count(&self) -> u32 {
518 match &self.kind {
519 TypesRefKind::Module(module) => module.functions.len() as u32,
520 #[cfg(feature = "component-model")]
521 TypesRefKind::Component(component) => component.core_funcs.len() as u32,
522 }
523 }
524
525 pub fn element_at(&self, index: u32) -> RefType {
531 match &self.kind {
532 TypesRefKind::Module(module) => module.element_types[index as usize],
533 #[cfg(feature = "component-model")]
534 TypesRefKind::Component(_) => {
535 panic!("no elements on a component")
536 }
537 }
538 }
539
540 pub fn element_count(&self) -> u32 {
542 match &self.kind {
543 TypesRefKind::Module(module) => module.element_types.len() as u32,
544 #[cfg(feature = "component-model")]
545 TypesRefKind::Component(_) => 0,
546 }
547 }
548
549 pub fn entity_type_from_import(&self, import: &Import) -> Option<EntityType> {
551 match &self.kind {
552 TypesRefKind::Module(module) => Some(match import.ty {
553 TypeRef::Func(idx) => EntityType::Func(*module.types.get(idx as usize)?),
554 TypeRef::FuncExact(idx) => EntityType::FuncExact(*module.types.get(idx as usize)?),
555 TypeRef::Table(ty) => EntityType::Table(ty),
556 TypeRef::Memory(ty) => EntityType::Memory(ty),
557 TypeRef::Global(ty) => EntityType::Global(ty),
558 TypeRef::Tag(ty) => EntityType::Tag(*module.types.get(ty.func_type_idx as usize)?),
559 }),
560 #[cfg(feature = "component-model")]
561 TypesRefKind::Component(_) => None,
562 }
563 }
564
565 pub fn entity_type_from_export(&self, export: &Export) -> Option<EntityType> {
567 match &self.kind {
568 TypesRefKind::Module(module) => Some(match export.kind {
569 ExternalKind::Func | ExternalKind::FuncExact => EntityType::Func(
570 module.types[*module.functions.get(export.index as usize)? as usize],
571 ),
572 ExternalKind::Table => {
573 EntityType::Table(*module.tables.get(export.index as usize)?)
574 }
575 ExternalKind::Memory => {
576 EntityType::Memory(*module.memories.get(export.index as usize)?)
577 }
578 ExternalKind::Global => {
579 EntityType::Global(*module.globals.get(export.index as usize)?)
580 }
581 ExternalKind::Tag => EntityType::Tag(*module.tags.get(export.index as usize)?),
582 }),
583 #[cfg(feature = "component-model")]
584 TypesRefKind::Component(_) => None,
585 }
586 }
587
588 pub fn core_imports(
592 &self,
593 ) -> Option<impl Iterator<Item = (&'a str, &'a str, EntityType)> + 'a> {
594 match &self.kind {
595 TypesRefKind::Module(module) => Some(
596 module
597 .imports
598 .iter()
599 .flat_map(|((m, n), t)| t.iter().map(move |t| (m.as_str(), n.as_str(), *t))),
600 ),
601 #[cfg(feature = "component-model")]
602 TypesRefKind::Component(_) => None,
603 }
604 }
605
606 pub fn core_exports(&self) -> Option<impl Iterator<Item = (&'a str, EntityType)> + 'a> {
610 match &self.kind {
611 TypesRefKind::Module(module) => {
612 Some(module.exports.iter().map(|(n, t)| (n.as_str(), *t)))
613 }
614 #[cfg(feature = "component-model")]
615 TypesRefKind::Component(_) => None,
616 }
617 }
618}
619
620impl<T> Index<T> for TypesRef<'_>
621where
622 T: TypeIdentifier,
623{
624 type Output = T::Data;
625
626 fn index(&self, index: T) -> &Self::Output {
627 &self.list[index]
628 }
629}
630
631impl Types {
632 pub(crate) fn from_module(id: ValidatorId, types: TypeList, module: Arc<Module>) -> Self {
633 Self {
634 id,
635 list: types,
636 kind: TypesKind::Module(module),
637 }
638 }
639
640 #[cfg(feature = "component-model")]
641 pub(crate) fn from_component(
642 id: ValidatorId,
643 types: TypeList,
644 component: ComponentState,
645 ) -> Self {
646 Self {
647 id,
648 list: types,
649 kind: TypesKind::Component(component),
650 }
651 }
652
653 pub fn as_ref(&self) -> TypesRef<'_> {
655 TypesRef {
656 id: self.id,
657 list: &self.list,
658 kind: match &self.kind {
659 TypesKind::Module(module) => TypesRefKind::Module(module),
660 #[cfg(feature = "component-model")]
661 TypesKind::Component(component) => TypesRefKind::Component(component),
662 },
663 }
664 }
665}
666
667impl<T> Index<T> for Types
668where
669 T: TypeIdentifier,
670{
671 type Output = T::Data;
672
673 fn index(&self, id: T) -> &Self::Output {
674 &self.list[id]
675 }
676}
677
678#[doc(hidden)]
692#[derive(Debug)]
693pub struct SnapshotList<T> {
694 snapshots: Vec<Arc<Snapshot<T>>>,
704
705 snapshots_total: usize,
707
708 cur: Vec<T>,
710}
711
712#[derive(Debug)]
713struct Snapshot<T> {
714 prior_types: usize,
715 items: Vec<T>,
716}
717
718impl<T> SnapshotList<T> {
719 pub(crate) fn get(&self, index: usize) -> Option<&T> {
721 if index >= self.snapshots_total {
723 return self.cur.get(index - self.snapshots_total);
724 }
725 let i = match self
729 .snapshots
730 .binary_search_by_key(&index, |snapshot| snapshot.prior_types)
731 {
732 Ok(i) => i,
733 Err(i) => i - 1,
734 };
735 let snapshot = &self.snapshots[i];
736 Some(&snapshot.items[index - snapshot.prior_types])
737 }
738
739 pub(crate) fn push(&mut self, val: T) {
741 self.cur.push(val);
742 }
743
744 pub(crate) fn len(&self) -> usize {
746 self.cur.len() + self.snapshots_total
747 }
748
749 #[cfg(feature = "component-model")]
751 pub(crate) fn truncate(&mut self, len: usize) {
752 assert!(len >= self.snapshots_total);
753 self.cur.truncate(len - self.snapshots_total);
754 }
755
756 pub(crate) fn commit(&mut self) -> SnapshotList<T> {
763 let len = self.cur.len();
768 if len > 0 {
769 self.cur.shrink_to_fit();
770 self.snapshots.push(Arc::new(Snapshot {
771 prior_types: self.snapshots_total,
772 items: mem::take(&mut self.cur),
773 }));
774 self.snapshots_total += len;
775 }
776 SnapshotList {
777 snapshots: self.snapshots.clone(),
778 snapshots_total: self.snapshots_total,
779 cur: Vec::new(),
780 }
781 }
782}
783
784impl<T> Index<usize> for SnapshotList<T> {
785 type Output = T;
786
787 #[inline]
788 fn index(&self, index: usize) -> &T {
789 match self.get(index) {
790 Some(x) => x,
791 None => panic!(
792 "out-of-bounds indexing into `SnapshotList`: index is {index}, but length is {}",
793 self.len()
794 ),
795 }
796 }
797}
798
799impl<T, U> Index<U> for SnapshotList<T>
800where
801 U: TypeIdentifier<Data = T>,
802{
803 type Output = T;
804
805 #[inline]
806 fn index(&self, id: U) -> &T {
807 self.get(id.index()).unwrap()
808 }
809}
810
811impl<T> Default for SnapshotList<T> {
812 fn default() -> SnapshotList<T> {
813 SnapshotList {
814 snapshots: Vec::new(),
815 snapshots_total: 0,
816 cur: Vec::new(),
817 }
818 }
819}
820
821#[derive(Default, Debug)]
829#[doc(hidden)]
831pub struct TypeList {
832 pub(super) core_types: SnapshotList<SubType>,
836 pub(super) core_type_to_rec_group: SnapshotList<RecGroupId>,
840 pub(super) core_type_to_supertype: SnapshotList<Option<CoreTypeId>>,
844 pub(super) core_type_to_depth: Option<IndexMap<CoreTypeId, u8>>,
849 pub(super) rec_group_elements: SnapshotList<Range<CoreTypeId>>,
852 pub(super) canonical_rec_groups: Option<Map<RecGroup, RecGroupId>>,
857
858 #[cfg(feature = "component-model")]
859 pub(super) component: ComponentTypeList,
860}
861
862impl TypeList {
863 pub fn get<T>(&self, id: T) -> Option<&T::Data>
864 where
865 T: TypeIdentifier,
866 {
867 T::list(self).get(id.index())
868 }
869
870 pub fn push<T>(&mut self, ty: T) -> T::Id
871 where
872 T: TypeData,
873 {
874 let index = u32::try_from(T::Id::list(self).len()).unwrap();
875 let id = T::Id::from_index(index);
876 T::Id::list_mut(self).push(ty);
877 id
878 }
879
880 pub fn intern_canonical_rec_group(
892 &mut self,
893 needs_type_canonicalization: bool,
894 mut rec_group: RecGroup,
895 ) -> (bool, RecGroupId) {
896 let rec_group_id = self.rec_group_elements.len();
897 let rec_group_id = u32::try_from(rec_group_id).unwrap();
898 let rec_group_id = RecGroupId::from_index(rec_group_id);
899
900 if needs_type_canonicalization {
901 let canonical_rec_groups = self
902 .canonical_rec_groups
903 .as_mut()
904 .expect("cannot intern into a committed list");
905 let entry = match canonical_rec_groups.entry(rec_group) {
906 Entry::Occupied(e) => return (false, *e.get()),
907 Entry::Vacant(e) => e,
908 };
909 rec_group = entry.key().clone();
910 entry.insert(rec_group_id);
911 }
912
913 let start = self.core_types.len();
914 let start = u32::try_from(start).unwrap();
915 let start = CoreTypeId::from_index(start);
916
917 for mut ty in rec_group.into_types() {
918 debug_assert_eq!(self.core_types.len(), self.core_type_to_supertype.len());
919 debug_assert_eq!(self.core_types.len(), self.core_type_to_rec_group.len());
920
921 self.core_type_to_supertype
922 .push(ty.supertype_idx.and_then(|idx| match idx.unpack() {
923 UnpackedIndex::RecGroup(offset) => {
924 Some(CoreTypeId::from_index(start.index + offset))
925 }
926 UnpackedIndex::Id(id) => Some(id),
927 UnpackedIndex::Module(_) => None,
930 }));
931 ty.remap_indices(&mut |index| {
932 if let UnpackedIndex::RecGroup(offset) = index.unpack() {
936 *index = UnpackedIndex::Id(CoreTypeId::from_index(start.index + offset))
937 .pack()
938 .unwrap();
939 }
940 Ok(())
941 })
942 .expect("cannot fail");
943 self.core_types.push(ty);
944 self.core_type_to_rec_group.push(rec_group_id);
945 }
946
947 let end = self.core_types.len();
948 let end = u32::try_from(end).unwrap();
949 let end = CoreTypeId::from_index(end);
950
951 let range = start..end;
952
953 self.rec_group_elements.push(range.clone());
954
955 return (true, rec_group_id);
956 }
957
958 pub fn intern_sub_type(&mut self, sub_ty: SubType, offset: usize) -> CoreTypeId {
961 let (_is_new, group_id) =
962 self.intern_canonical_rec_group(true, RecGroup::implicit(offset, sub_ty));
963 self[group_id].start
964 }
965
966 pub fn intern_func_type(&mut self, ty: FuncType, offset: usize) -> CoreTypeId {
969 self.intern_sub_type(SubType::func(ty, false), offset)
970 }
971
972 pub fn rec_group_local_id(
974 &self,
975 rec_group: RecGroupId,
976 index: u32,
977 offset: usize,
978 ) -> Result<CoreTypeId> {
979 let elems = &self[rec_group];
980 let len = elems.end.index() - elems.start.index();
981 let len = u32::try_from(len).unwrap();
982 if index < len {
983 let id = u32::try_from(elems.start.index()).unwrap() + index;
984 let id = CoreTypeId::from_index(id);
985 Ok(id)
986 } else {
987 bail!(
988 offset,
989 "unknown type {index}: type index out of rec group bounds"
990 )
991 }
992 }
993
994 pub fn rec_group_id_of(&self, id: CoreTypeId) -> RecGroupId {
996 self.core_type_to_rec_group[id.index()]
997 }
998
999 pub fn supertype_of(&self, id: CoreTypeId) -> Option<CoreTypeId> {
1001 self.core_type_to_supertype[id.index()]
1002 }
1003
1004 pub fn get_subtyping_depth(&self, id: CoreTypeId) -> u8 {
1007 let depth = self
1008 .core_type_to_depth
1009 .as_ref()
1010 .expect("cannot get subtype depth from a committed list")[&id];
1011 debug_assert!(usize::from(depth) <= crate::limits::MAX_WASM_SUBTYPING_DEPTH);
1012 depth
1013 }
1014
1015 pub fn set_subtyping_depth(&mut self, id: CoreTypeId, depth: u8) {
1018 debug_assert!(usize::from(depth) <= crate::limits::MAX_WASM_SUBTYPING_DEPTH);
1019 let map = self
1020 .core_type_to_depth
1021 .as_mut()
1022 .expect("cannot set a subtype depth in a committed list");
1023 debug_assert!(!map.contains_key(&id));
1024 map.insert(id, depth);
1025 }
1026
1027 pub fn at_canonicalized_packed_index(
1031 &self,
1032 rec_group: RecGroupId,
1033 index: PackedIndex,
1034 offset: usize,
1035 ) -> Result<CoreTypeId> {
1036 self.at_canonicalized_unpacked_index(rec_group, index.unpack(), offset)
1037 }
1038
1039 pub fn at_canonicalized_unpacked_index(
1043 &self,
1044 rec_group: RecGroupId,
1045 index: UnpackedIndex,
1046 offset: usize,
1047 ) -> Result<CoreTypeId> {
1048 match index {
1049 UnpackedIndex::Module(_) => panic!("not canonicalized"),
1050 UnpackedIndex::Id(id) => Ok(id),
1051 UnpackedIndex::RecGroup(idx) => self.rec_group_local_id(rec_group, idx, offset),
1052 }
1053 }
1054
1055 pub fn matches(&self, a: CoreTypeId, b: CoreTypeId) -> bool {
1057 let a = WithRecGroup::new(self, a);
1058 let a = WithRecGroup::map(a, |a| &self[a]);
1059
1060 let b = WithRecGroup::new(self, b);
1061 let b = WithRecGroup::map(b, |b| &self[b]);
1062
1063 Matches::matches(self, a, b)
1064 }
1065
1066 pub fn id_is_subtype(&self, mut a: CoreTypeId, b: CoreTypeId) -> bool {
1069 loop {
1070 if a == b {
1071 return true;
1072 }
1073
1074 a = match self.supertype_of(a) {
1077 Some(a) => a,
1078 None => return false,
1079 };
1080 }
1081 }
1082
1083 pub fn reftype_is_subtype(&self, a: RefType, b: RefType) -> bool {
1087 self.reftype_is_subtype_impl(a, None, b, None)
1091 }
1092
1093 pub(crate) fn reftype_is_subtype_impl(
1099 &self,
1100 a: RefType,
1101 a_group: Option<RecGroupId>,
1102 b: RefType,
1103 b_group: Option<RecGroupId>,
1104 ) -> bool {
1105 if a == b && a_group == b_group {
1106 return true;
1107 }
1108
1109 if a.is_nullable() && !b.is_nullable() {
1110 return false;
1111 }
1112
1113 let core_type_id = |group: Option<RecGroupId>, index: UnpackedIndex| -> CoreTypeId {
1114 if let Some(id) = index.as_core_type_id() {
1115 id
1116 } else {
1117 self.at_canonicalized_unpacked_index(group.unwrap(), index, usize::MAX)
1118 .expect("type references are checked during canonicalization")
1119 }
1120 };
1121
1122 let subtype = |group, index| -> &SubType {
1123 let id = core_type_id(group, index);
1124 &self[id]
1125 };
1126
1127 use AbstractHeapType::*;
1128 use CompositeInnerType as CT;
1129 use HeapType as HT;
1130 match (a.heap_type(), b.heap_type()) {
1131 (a, b) if a == b => true,
1132
1133 (
1134 HT::Abstract {
1135 shared: a_shared,
1136 ty: a_ty,
1137 },
1138 HT::Abstract {
1139 shared: b_shared,
1140 ty: b_ty,
1141 },
1142 ) => a_shared == b_shared && a_ty.is_subtype_of(b_ty),
1143
1144 (HT::Concrete(a), HT::Abstract { shared, ty })
1145 | (HT::Exact(a), HT::Abstract { shared, ty }) => {
1146 let a_ty = &subtype(a_group, a).composite_type;
1147 if a_ty.shared != shared {
1148 return false;
1149 }
1150 match ty {
1151 Any | Eq => matches!(a_ty.inner, CT::Array(_) | CT::Struct(_)),
1152 Struct => matches!(a_ty.inner, CT::Struct(_)),
1153 Array => matches!(a_ty.inner, CT::Array(_)),
1154 Func => matches!(a_ty.inner, CT::Func(_)),
1155 Cont => matches!(a_ty.inner, CT::Cont(_)),
1156 Extern | Exn | I31 | None | NoFunc | NoExtern | NoExn | NoCont => false,
1159 }
1160 }
1161
1162 (HT::Abstract { shared, ty }, HT::Concrete(b))
1163 | (HT::Abstract { shared, ty }, HT::Exact(b)) => {
1164 let b_ty = &subtype(b_group, b).composite_type;
1165 if shared != b_ty.shared {
1166 return false;
1167 }
1168 match ty {
1169 None => matches!(b_ty.inner, CT::Array(_) | CT::Struct(_)),
1170 NoFunc => matches!(b_ty.inner, CT::Func(_)),
1171 NoCont => matches!(b_ty.inner, CT::Cont(_)),
1172 Cont | Func | Extern | Exn | Any | Eq | Array | I31 | Struct | NoExtern
1175 | NoExn => false,
1176 }
1177 }
1178
1179 (HT::Concrete(a), HT::Concrete(b)) | (HT::Exact(a), HT::Concrete(b)) => {
1180 self.id_is_subtype(core_type_id(a_group, a), core_type_id(b_group, b))
1181 }
1182
1183 (HT::Exact(a), HT::Exact(b)) => core_type_id(a_group, a) == core_type_id(b_group, b),
1184
1185 (HT::Concrete(_), HT::Exact(_)) => false,
1186 }
1187 }
1188
1189 pub fn valtype_is_subtype(&self, a: ValType, b: ValType) -> bool {
1193 match (a, b) {
1194 (a, b) if a == b => true,
1195 (ValType::Ref(a), ValType::Ref(b)) => self.reftype_is_subtype(a, b),
1196 (ValType::Ref(_), _)
1197 | (ValType::I32, _)
1198 | (ValType::I64, _)
1199 | (ValType::F32, _)
1200 | (ValType::F64, _)
1201 | (ValType::V128, _) => false,
1202 }
1203 }
1204
1205 pub fn valtype_is_shared(&self, ty: ValType) -> bool {
1207 match ty {
1208 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => true,
1209 ValType::Ref(rt) => self.reftype_is_shared(rt),
1210 }
1211 }
1212
1213 pub fn reftype_is_shared(&self, ty: RefType) -> bool {
1218 match ty.heap_type() {
1219 HeapType::Abstract { shared, .. } => shared,
1220 HeapType::Concrete(index) | HeapType::Exact(index) => {
1221 self[index.as_core_type_id().unwrap()].composite_type.shared
1222 }
1223 }
1224 }
1225
1226 pub fn top_type(&self, heap_type: &HeapType) -> HeapType {
1231 use AbstractHeapType::*;
1232 match *heap_type {
1233 HeapType::Concrete(idx) | HeapType::Exact(idx) => {
1234 let ty = &self[idx.as_core_type_id().unwrap()].composite_type;
1235 let shared = ty.shared;
1236 match ty.inner {
1237 CompositeInnerType::Func(_) => HeapType::Abstract { shared, ty: Func },
1238 CompositeInnerType::Array(_) | CompositeInnerType::Struct(_) => {
1239 HeapType::Abstract { shared, ty: Any }
1240 }
1241 CompositeInnerType::Cont(_) => HeapType::Abstract { shared, ty: Cont },
1242 }
1243 }
1244 HeapType::Abstract { shared, ty } => {
1245 let ty = match ty {
1246 Func | NoFunc => Func,
1247 Extern | NoExtern => Extern,
1248 Any | Eq | Struct | Array | I31 | None => Any,
1249 Exn | NoExn => Exn,
1250 Cont | NoCont => Cont,
1251 };
1252 HeapType::Abstract { shared, ty }
1253 }
1254 }
1255 }
1256
1257 pub fn commit(&mut self) -> TypeList {
1258 TypeList {
1259 core_types: self.core_types.commit(),
1260 core_type_to_rec_group: self.core_type_to_rec_group.commit(),
1261 core_type_to_supertype: self.core_type_to_supertype.commit(),
1262 core_type_to_depth: None,
1263 rec_group_elements: self.rec_group_elements.commit(),
1264 canonical_rec_groups: None,
1265 #[cfg(feature = "component-model")]
1266 component: self.component.commit(),
1267 }
1268 }
1269}
1270
1271impl<T> Index<T> for TypeList
1272where
1273 T: TypeIdentifier,
1274{
1275 type Output = T::Data;
1276
1277 fn index(&self, id: T) -> &Self::Output {
1278 let arena = T::list(self);
1279 &arena[id.index()]
1280 }
1281}
1282
1283pub(crate) struct TypeAlloc {
1286 list: TypeList,
1287 #[cfg(feature = "component-model")]
1288 pub(super) component_alloc: ComponentTypeAlloc,
1289}
1290
1291impl Default for TypeAlloc {
1292 fn default() -> TypeAlloc {
1293 let mut ret = TypeAlloc {
1294 list: TypeList::default(),
1295 #[cfg(feature = "component-model")]
1296 component_alloc: ComponentTypeAlloc::default(),
1297 };
1298 ret.list.core_type_to_depth = Some(Default::default());
1299 ret.list.canonical_rec_groups = Some(Default::default());
1300 ret
1301 }
1302}
1303
1304impl Deref for TypeAlloc {
1305 type Target = TypeList;
1306 fn deref(&self) -> &TypeList {
1307 &self.list
1308 }
1309}
1310
1311impl DerefMut for TypeAlloc {
1312 fn deref_mut(&mut self) -> &mut TypeList {
1313 &mut self.list
1314 }
1315}
1316
1317impl<T> Index<T> for TypeAlloc
1318where
1319 T: TypeIdentifier,
1320{
1321 type Output = T::Data;
1322
1323 #[inline]
1324 fn index(&self, id: T) -> &T::Data {
1325 &self.list[id]
1326 }
1327}