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}
103pub(crate) use define_type_id;
104
105#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
108#[repr(C)]
109pub struct CoreTypeId {
110 index: u32,
111}
112
113#[test]
114fn assert_core_type_id_small() {
115 assert!(core::mem::size_of::<CoreTypeId>() <= 4);
116}
117
118impl TypeIdentifier for CoreTypeId {
119 type Data = SubType;
120
121 fn from_index(index: u32) -> Self {
122 CoreTypeId { index }
123 }
124
125 fn list(types: &TypeList) -> &SnapshotList<Self::Data> {
126 &types.core_types
127 }
128
129 fn list_mut(types: &mut TypeList) -> &mut SnapshotList<Self::Data> {
130 &mut types.core_types
131 }
132
133 fn index(&self) -> usize {
134 usize::try_from(self.index).unwrap()
135 }
136}
137
138impl TypeData for SubType {
139 type Id = CoreTypeId;
140 const IS_CORE_SUB_TYPE: bool = true;
141 fn type_info(&self, _types: &TypeList) -> TypeInfo {
142 let size = 1 + match &self.composite_type.inner {
144 CompositeInnerType::Func(ty) => 1 + (ty.params().len() + ty.results().len()) as u32,
145 CompositeInnerType::Array(_) => 2,
146 CompositeInnerType::Struct(ty) => 1 + 2 * ty.fields.len() as u32,
147 CompositeInnerType::Cont(_) => 1,
148 };
149 TypeInfo::core(size)
150 }
151}
152
153define_type_id!(
154 RecGroupId,
155 Range<CoreTypeId>,
156 rec_group_elements,
157 "recursion group"
158);
159
160impl TypeData for Range<CoreTypeId> {
161 type Id = RecGroupId;
162 const IS_CORE_SUB_TYPE: bool = true;
163 fn type_info(&self, _types: &TypeList) -> TypeInfo {
164 let size = self.end.index() - self.start.index();
165 TypeInfo::core(u32::try_from(size).unwrap())
166 }
167}
168
169#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
192#[doc(hidden)]
194pub struct TypeInfo(u32);
195
196impl TypeInfo {
197 pub(crate) fn new() -> TypeInfo {
202 TypeInfo::_new(1, false)
203 }
204
205 #[cfg(feature = "component-model")]
208 pub(crate) fn borrow() -> TypeInfo {
209 TypeInfo::_new(1, true)
210 }
211
212 pub(crate) fn core(size: u32) -> TypeInfo {
215 TypeInfo::_new(size, false)
216 }
217
218 fn _new(size: u32, contains_borrow: bool) -> TypeInfo {
219 assert!(size < (1 << 24));
220 TypeInfo(size | ((contains_borrow as u32) << 31))
221 }
222
223 #[cfg(feature = "component-model")]
232 pub(crate) fn combine(&mut self, other: TypeInfo, offset: usize) -> Result<()> {
233 *self = TypeInfo::_new(
234 super::combine_type_sizes(self.size(), other.size(), offset)?,
235 self.contains_borrow() || other.contains_borrow(),
236 );
237 Ok(())
238 }
239
240 pub(crate) fn size(&self) -> u32 {
241 self.0 & 0xffffff
242 }
243
244 #[cfg(feature = "component-model")]
245 pub(crate) fn contains_borrow(&self) -> bool {
246 (self.0 >> 31) != 0
247 }
248}
249
250#[derive(Debug, Clone, Copy, PartialEq, Eq)]
252pub enum EntityType {
253 Func(CoreTypeId),
255 Table(TableType),
257 Memory(MemoryType),
259 Global(GlobalType),
261 Tag(CoreTypeId),
263}
264
265impl EntityType {
266 #[cfg(feature = "component-model")]
267 pub(crate) fn desc(&self) -> &'static str {
268 match self {
269 Self::Func(_) => "func",
270 Self::Table(_) => "table",
271 Self::Memory(_) => "memory",
272 Self::Global(_) => "global",
273 Self::Tag(_) => "tag",
274 }
275 }
276
277 pub(crate) fn info(&self, types: &TypeList) -> TypeInfo {
278 match self {
279 Self::Func(id) | Self::Tag(id) => types[*id].type_info(types),
280 Self::Table(_) | Self::Memory(_) | Self::Global(_) => TypeInfo::new(),
281 }
282 }
283}
284
285#[allow(clippy::large_enum_variant)]
286pub(super) enum TypesKind {
287 Module(Arc<Module>),
288 #[cfg(feature = "component-model")]
289 Component(ComponentState),
290}
291
292pub struct Types {
296 id: ValidatorId,
297 pub(super) list: TypeList,
298 pub(super) kind: TypesKind,
299}
300
301#[derive(Clone, Copy)]
302pub(super) enum TypesRefKind<'a> {
303 Module(&'a Module),
304 #[cfg(feature = "component-model")]
305 Component(&'a ComponentState),
306}
307
308#[derive(Clone, Copy)]
312pub struct TypesRef<'a> {
313 id: ValidatorId,
314 pub(super) list: &'a TypeList,
315 pub(super) kind: TypesRefKind<'a>,
316}
317
318impl<'a> TypesRef<'a> {
319 pub(crate) fn from_module(id: ValidatorId, types: &'a TypeList, module: &'a Module) -> Self {
320 Self {
321 id,
322 list: types,
323 kind: TypesRefKind::Module(module),
324 }
325 }
326
327 #[cfg(feature = "component-model")]
328 pub(crate) fn from_component(
329 id: ValidatorId,
330 types: &'a TypeList,
331 component: &'a ComponentState,
332 ) -> Self {
333 Self {
334 id,
335 list: types,
336 kind: TypesRefKind::Component(component),
337 }
338 }
339
340 #[inline]
342 pub fn id(&self) -> ValidatorId {
343 self.id
344 }
345
346 pub fn get<T>(&self, id: T) -> Option<&'a T::Data>
350 where
351 T: TypeIdentifier,
352 {
353 self.list.get(id)
354 }
355
356 pub fn rec_group_id_of(&self, id: CoreTypeId) -> RecGroupId {
358 self.list.rec_group_id_of(id)
359 }
360
361 pub fn rec_group_elements(&self, id: RecGroupId) -> impl ExactSizeIterator<Item = CoreTypeId> {
363 let range = &self.list.rec_group_elements[id];
364 (range.start.index..range.end.index).map(|index| CoreTypeId { index })
365 }
366
367 pub fn supertype_of(&self, id: CoreTypeId) -> Option<CoreTypeId> {
369 self.list.supertype_of(id)
370 }
371
372 pub fn core_type_at_in_module(&self, index: u32) -> CoreTypeId {
383 match &self.kind {
384 TypesRefKind::Module(module) => module.types[index as usize].into(),
385 #[cfg(feature = "component-model")]
386 TypesRefKind::Component(_) => panic!("use `core_type_at_in_component` instead"),
387 }
388 }
389
390 pub fn core_type_count_in_module(&self) -> u32 {
395 match &self.kind {
396 TypesRefKind::Module(module) => module.types.len() as u32,
397 #[cfg(feature = "component-model")]
398 TypesRefKind::Component(_) => 0,
399 }
400 }
401
402 pub fn table_at(&self, index: u32) -> TableType {
408 let tables = match &self.kind {
409 TypesRefKind::Module(module) => &module.tables,
410 #[cfg(feature = "component-model")]
411 TypesRefKind::Component(component) => &component.core_tables,
412 };
413 tables[index as usize]
414 }
415
416 pub fn table_count(&self) -> u32 {
418 match &self.kind {
419 TypesRefKind::Module(module) => module.tables.len() as u32,
420 #[cfg(feature = "component-model")]
421 TypesRefKind::Component(component) => component.core_tables.len() as u32,
422 }
423 }
424
425 pub fn memory_at(&self, index: u32) -> MemoryType {
431 let memories = match &self.kind {
432 TypesRefKind::Module(module) => &module.memories,
433 #[cfg(feature = "component-model")]
434 TypesRefKind::Component(component) => &component.core_memories,
435 };
436
437 memories[index as usize]
438 }
439
440 pub fn memory_count(&self) -> u32 {
442 match &self.kind {
443 TypesRefKind::Module(module) => module.memories.len() as u32,
444 #[cfg(feature = "component-model")]
445 TypesRefKind::Component(component) => component.core_memories.len() as u32,
446 }
447 }
448
449 pub fn global_at(&self, index: u32) -> GlobalType {
455 let globals = match &self.kind {
456 TypesRefKind::Module(module) => &module.globals,
457 #[cfg(feature = "component-model")]
458 TypesRefKind::Component(component) => &component.core_globals,
459 };
460
461 globals[index as usize]
462 }
463
464 pub fn global_count(&self) -> u32 {
466 match &self.kind {
467 TypesRefKind::Module(module) => module.globals.len() as u32,
468 #[cfg(feature = "component-model")]
469 TypesRefKind::Component(component) => component.core_globals.len() as u32,
470 }
471 }
472
473 pub fn tag_at(&self, index: u32) -> CoreTypeId {
479 let tags = match &self.kind {
480 TypesRefKind::Module(module) => &module.tags,
481 #[cfg(feature = "component-model")]
482 TypesRefKind::Component(component) => &component.core_tags,
483 };
484 tags[index as usize]
485 }
486
487 pub fn tag_count(&self) -> u32 {
489 match &self.kind {
490 TypesRefKind::Module(module) => module.tags.len() as u32,
491 #[cfg(feature = "component-model")]
492 TypesRefKind::Component(component) => component.core_tags.len() as u32,
493 }
494 }
495
496 pub fn core_function_at(&self, index: u32) -> CoreTypeId {
502 match &self.kind {
503 TypesRefKind::Module(module) => module.types[module.functions[index as usize] as usize],
504 #[cfg(feature = "component-model")]
505 TypesRefKind::Component(component) => component.core_funcs[index as usize],
506 }
507 }
508
509 pub fn function_count(&self) -> u32 {
514 match &self.kind {
515 TypesRefKind::Module(module) => module.functions.len() as u32,
516 #[cfg(feature = "component-model")]
517 TypesRefKind::Component(component) => component.core_funcs.len() as u32,
518 }
519 }
520
521 pub fn element_at(&self, index: u32) -> RefType {
527 match &self.kind {
528 TypesRefKind::Module(module) => module.element_types[index as usize],
529 #[cfg(feature = "component-model")]
530 TypesRefKind::Component(_) => {
531 panic!("no elements on a component")
532 }
533 }
534 }
535
536 pub fn element_count(&self) -> u32 {
538 match &self.kind {
539 TypesRefKind::Module(module) => module.element_types.len() as u32,
540 #[cfg(feature = "component-model")]
541 TypesRefKind::Component(_) => 0,
542 }
543 }
544
545 pub fn entity_type_from_import(&self, import: &Import) -> Option<EntityType> {
547 match &self.kind {
548 TypesRefKind::Module(module) => Some(match import.ty {
549 TypeRef::Func(idx) => EntityType::Func(*module.types.get(idx as usize)?),
550 TypeRef::Table(ty) => EntityType::Table(ty),
551 TypeRef::Memory(ty) => EntityType::Memory(ty),
552 TypeRef::Global(ty) => EntityType::Global(ty),
553 TypeRef::Tag(ty) => EntityType::Tag(*module.types.get(ty.func_type_idx as usize)?),
554 }),
555 #[cfg(feature = "component-model")]
556 TypesRefKind::Component(_) => None,
557 }
558 }
559
560 pub fn entity_type_from_export(&self, export: &Export) -> Option<EntityType> {
562 match &self.kind {
563 TypesRefKind::Module(module) => Some(match export.kind {
564 ExternalKind::Func => EntityType::Func(
565 module.types[*module.functions.get(export.index as usize)? as usize],
566 ),
567 ExternalKind::Table => {
568 EntityType::Table(*module.tables.get(export.index as usize)?)
569 }
570 ExternalKind::Memory => {
571 EntityType::Memory(*module.memories.get(export.index as usize)?)
572 }
573 ExternalKind::Global => {
574 EntityType::Global(*module.globals.get(export.index as usize)?)
575 }
576 ExternalKind::Tag => EntityType::Tag(*module.tags.get(export.index as usize)?),
577 }),
578 #[cfg(feature = "component-model")]
579 TypesRefKind::Component(_) => None,
580 }
581 }
582
583 pub fn core_imports(
587 &self,
588 ) -> Option<impl Iterator<Item = (&'a str, &'a str, EntityType)> + 'a> {
589 match &self.kind {
590 TypesRefKind::Module(module) => Some(
591 module
592 .imports
593 .iter()
594 .flat_map(|((m, n), t)| t.iter().map(move |t| (m.as_str(), n.as_str(), *t))),
595 ),
596 #[cfg(feature = "component-model")]
597 TypesRefKind::Component(_) => None,
598 }
599 }
600
601 pub fn core_exports(&self) -> Option<impl Iterator<Item = (&'a str, EntityType)> + 'a> {
605 match &self.kind {
606 TypesRefKind::Module(module) => {
607 Some(module.exports.iter().map(|(n, t)| (n.as_str(), *t)))
608 }
609 #[cfg(feature = "component-model")]
610 TypesRefKind::Component(_) => None,
611 }
612 }
613}
614
615impl<T> Index<T> for TypesRef<'_>
616where
617 T: TypeIdentifier,
618{
619 type Output = T::Data;
620
621 fn index(&self, index: T) -> &Self::Output {
622 &self.list[index]
623 }
624}
625
626impl Types {
627 pub(crate) fn from_module(id: ValidatorId, types: TypeList, module: Arc<Module>) -> Self {
628 Self {
629 id,
630 list: types,
631 kind: TypesKind::Module(module),
632 }
633 }
634
635 #[cfg(feature = "component-model")]
636 pub(crate) fn from_component(
637 id: ValidatorId,
638 types: TypeList,
639 component: ComponentState,
640 ) -> Self {
641 Self {
642 id,
643 list: types,
644 kind: TypesKind::Component(component),
645 }
646 }
647
648 pub fn as_ref(&self) -> TypesRef<'_> {
650 TypesRef {
651 id: self.id,
652 list: &self.list,
653 kind: match &self.kind {
654 TypesKind::Module(module) => TypesRefKind::Module(module),
655 #[cfg(feature = "component-model")]
656 TypesKind::Component(component) => TypesRefKind::Component(component),
657 },
658 }
659 }
660}
661
662impl<T> Index<T> for Types
663where
664 T: TypeIdentifier,
665{
666 type Output = T::Data;
667
668 fn index(&self, id: T) -> &Self::Output {
669 &self.list[id]
670 }
671}
672
673#[doc(hidden)]
687#[derive(Debug)]
688pub struct SnapshotList<T> {
689 snapshots: Vec<Arc<Snapshot<T>>>,
699
700 snapshots_total: usize,
702
703 cur: Vec<T>,
705}
706
707#[derive(Debug)]
708struct Snapshot<T> {
709 prior_types: usize,
710 items: Vec<T>,
711}
712
713impl<T> SnapshotList<T> {
714 pub(crate) fn get(&self, index: usize) -> Option<&T> {
716 if index >= self.snapshots_total {
718 return self.cur.get(index - self.snapshots_total);
719 }
720 let i = match self
724 .snapshots
725 .binary_search_by_key(&index, |snapshot| snapshot.prior_types)
726 {
727 Ok(i) => i,
728 Err(i) => i - 1,
729 };
730 let snapshot = &self.snapshots[i];
731 Some(&snapshot.items[index - snapshot.prior_types])
732 }
733
734 pub(crate) fn push(&mut self, val: T) {
736 self.cur.push(val);
737 }
738
739 pub(crate) fn len(&self) -> usize {
741 self.cur.len() + self.snapshots_total
742 }
743
744 #[cfg(feature = "component-model")]
746 pub(crate) fn truncate(&mut self, len: usize) {
747 assert!(len >= self.snapshots_total);
748 self.cur.truncate(len - self.snapshots_total);
749 }
750
751 pub(crate) fn commit(&mut self) -> SnapshotList<T> {
758 let len = self.cur.len();
763 if len > 0 {
764 self.cur.shrink_to_fit();
765 self.snapshots.push(Arc::new(Snapshot {
766 prior_types: self.snapshots_total,
767 items: mem::take(&mut self.cur),
768 }));
769 self.snapshots_total += len;
770 }
771 SnapshotList {
772 snapshots: self.snapshots.clone(),
773 snapshots_total: self.snapshots_total,
774 cur: Vec::new(),
775 }
776 }
777}
778
779impl<T> Index<usize> for SnapshotList<T> {
780 type Output = T;
781
782 #[inline]
783 fn index(&self, index: usize) -> &T {
784 match self.get(index) {
785 Some(x) => x,
786 None => panic!(
787 "out-of-bounds indexing into `SnapshotList`: index is {index}, but length is {}",
788 self.len()
789 ),
790 }
791 }
792}
793
794impl<T, U> Index<U> for SnapshotList<T>
795where
796 U: TypeIdentifier<Data = T>,
797{
798 type Output = T;
799
800 #[inline]
801 fn index(&self, id: U) -> &T {
802 self.get(id.index()).unwrap()
803 }
804}
805
806impl<T> Default for SnapshotList<T> {
807 fn default() -> SnapshotList<T> {
808 SnapshotList {
809 snapshots: Vec::new(),
810 snapshots_total: 0,
811 cur: Vec::new(),
812 }
813 }
814}
815
816#[derive(Default, Debug)]
824#[doc(hidden)]
826pub struct TypeList {
827 pub(super) core_types: SnapshotList<SubType>,
831 pub(super) core_type_to_rec_group: SnapshotList<RecGroupId>,
835 pub(super) core_type_to_supertype: SnapshotList<Option<CoreTypeId>>,
839 pub(super) core_type_to_depth: Option<IndexMap<CoreTypeId, u8>>,
844 pub(super) rec_group_elements: SnapshotList<Range<CoreTypeId>>,
847 pub(super) canonical_rec_groups: Option<Map<RecGroup, RecGroupId>>,
852
853 #[cfg(feature = "component-model")]
854 pub(super) component: ComponentTypeList,
855}
856
857impl TypeList {
858 pub fn get<T>(&self, id: T) -> Option<&T::Data>
859 where
860 T: TypeIdentifier,
861 {
862 T::list(self).get(id.index())
863 }
864
865 pub fn push<T>(&mut self, ty: T) -> T::Id
866 where
867 T: TypeData,
868 {
869 let index = u32::try_from(T::Id::list(self).len()).unwrap();
870 let id = T::Id::from_index(index);
871 T::Id::list_mut(self).push(ty);
872 id
873 }
874
875 pub fn intern_canonical_rec_group(
887 &mut self,
888 needs_type_canonicalization: bool,
889 mut rec_group: RecGroup,
890 ) -> (bool, RecGroupId) {
891 let rec_group_id = self.rec_group_elements.len();
892 let rec_group_id = u32::try_from(rec_group_id).unwrap();
893 let rec_group_id = RecGroupId::from_index(rec_group_id);
894
895 if needs_type_canonicalization {
896 let canonical_rec_groups = self
897 .canonical_rec_groups
898 .as_mut()
899 .expect("cannot intern into a committed list");
900 let entry = match canonical_rec_groups.entry(rec_group) {
901 Entry::Occupied(e) => return (false, *e.get()),
902 Entry::Vacant(e) => e,
903 };
904 rec_group = entry.key().clone();
905 entry.insert(rec_group_id);
906 }
907
908 let start = self.core_types.len();
909 let start = u32::try_from(start).unwrap();
910 let start = CoreTypeId::from_index(start);
911
912 for mut ty in rec_group.into_types() {
913 debug_assert_eq!(self.core_types.len(), self.core_type_to_supertype.len());
914 debug_assert_eq!(self.core_types.len(), self.core_type_to_rec_group.len());
915
916 self.core_type_to_supertype
917 .push(ty.supertype_idx.and_then(|idx| match idx.unpack() {
918 UnpackedIndex::RecGroup(offset) => {
919 Some(CoreTypeId::from_index(start.index + offset))
920 }
921 UnpackedIndex::Id(id) => Some(id),
922 UnpackedIndex::Module(_) => None,
925 }));
926 ty.remap_indices(&mut |index| {
927 if let UnpackedIndex::RecGroup(offset) = index.unpack() {
931 *index = UnpackedIndex::Id(CoreTypeId::from_index(start.index + offset))
932 .pack()
933 .unwrap();
934 }
935 Ok(())
936 })
937 .expect("cannot fail");
938 self.core_types.push(ty);
939 self.core_type_to_rec_group.push(rec_group_id);
940 }
941
942 let end = self.core_types.len();
943 let end = u32::try_from(end).unwrap();
944 let end = CoreTypeId::from_index(end);
945
946 let range = start..end;
947
948 self.rec_group_elements.push(range.clone());
949
950 return (true, rec_group_id);
951 }
952
953 pub fn intern_sub_type(&mut self, sub_ty: SubType, offset: usize) -> CoreTypeId {
956 let (_is_new, group_id) =
957 self.intern_canonical_rec_group(true, RecGroup::implicit(offset, sub_ty));
958 self[group_id].start
959 }
960
961 pub fn intern_func_type(&mut self, ty: FuncType, offset: usize) -> CoreTypeId {
964 self.intern_sub_type(SubType::func(ty, false), offset)
965 }
966
967 pub fn rec_group_local_id(
969 &self,
970 rec_group: RecGroupId,
971 index: u32,
972 offset: usize,
973 ) -> Result<CoreTypeId> {
974 let elems = &self[rec_group];
975 let len = elems.end.index() - elems.start.index();
976 let len = u32::try_from(len).unwrap();
977 if index < len {
978 let id = u32::try_from(elems.start.index()).unwrap() + index;
979 let id = CoreTypeId::from_index(id);
980 Ok(id)
981 } else {
982 bail!(
983 offset,
984 "unknown type {index}: type index out of rec group bounds"
985 )
986 }
987 }
988
989 pub fn rec_group_id_of(&self, id: CoreTypeId) -> RecGroupId {
991 self.core_type_to_rec_group[id.index()]
992 }
993
994 pub fn supertype_of(&self, id: CoreTypeId) -> Option<CoreTypeId> {
996 self.core_type_to_supertype[id.index()]
997 }
998
999 pub fn get_subtyping_depth(&self, id: CoreTypeId) -> u8 {
1002 let depth = self
1003 .core_type_to_depth
1004 .as_ref()
1005 .expect("cannot get subtype depth from a committed list")[&id];
1006 debug_assert!(usize::from(depth) <= crate::limits::MAX_WASM_SUBTYPING_DEPTH);
1007 depth
1008 }
1009
1010 pub fn set_subtyping_depth(&mut self, id: CoreTypeId, depth: u8) {
1013 debug_assert!(usize::from(depth) <= crate::limits::MAX_WASM_SUBTYPING_DEPTH);
1014 let map = self
1015 .core_type_to_depth
1016 .as_mut()
1017 .expect("cannot set a subtype depth in a committed list");
1018 debug_assert!(!map.contains_key(&id));
1019 map.insert(id, depth);
1020 }
1021
1022 pub fn at_canonicalized_packed_index(
1026 &self,
1027 rec_group: RecGroupId,
1028 index: PackedIndex,
1029 offset: usize,
1030 ) -> Result<CoreTypeId> {
1031 self.at_canonicalized_unpacked_index(rec_group, index.unpack(), offset)
1032 }
1033
1034 pub fn at_canonicalized_unpacked_index(
1038 &self,
1039 rec_group: RecGroupId,
1040 index: UnpackedIndex,
1041 offset: usize,
1042 ) -> Result<CoreTypeId> {
1043 match index {
1044 UnpackedIndex::Module(_) => panic!("not canonicalized"),
1045 UnpackedIndex::Id(id) => Ok(id),
1046 UnpackedIndex::RecGroup(idx) => self.rec_group_local_id(rec_group, idx, offset),
1047 }
1048 }
1049
1050 pub fn matches(&self, a: CoreTypeId, b: CoreTypeId) -> bool {
1052 let a = WithRecGroup::new(self, a);
1053 let a = WithRecGroup::map(a, |a| &self[a]);
1054
1055 let b = WithRecGroup::new(self, b);
1056 let b = WithRecGroup::map(b, |b| &self[b]);
1057
1058 Matches::matches(self, a, b)
1059 }
1060
1061 pub fn id_is_subtype(&self, mut a: CoreTypeId, b: CoreTypeId) -> bool {
1064 loop {
1065 if a == b {
1066 return true;
1067 }
1068
1069 a = match self.supertype_of(a) {
1072 Some(a) => a,
1073 None => return false,
1074 };
1075 }
1076 }
1077
1078 pub fn reftype_is_subtype(&self, a: RefType, b: RefType) -> bool {
1082 self.reftype_is_subtype_impl(a, None, b, None)
1086 }
1087
1088 pub(crate) fn reftype_is_subtype_impl(
1094 &self,
1095 a: RefType,
1096 a_group: Option<RecGroupId>,
1097 b: RefType,
1098 b_group: Option<RecGroupId>,
1099 ) -> bool {
1100 if a == b && a_group == b_group {
1101 return true;
1102 }
1103
1104 if a.is_nullable() && !b.is_nullable() {
1105 return false;
1106 }
1107
1108 let core_type_id = |group: Option<RecGroupId>, index: UnpackedIndex| -> CoreTypeId {
1109 if let Some(id) = index.as_core_type_id() {
1110 id
1111 } else {
1112 self.at_canonicalized_unpacked_index(group.unwrap(), index, usize::MAX)
1113 .expect("type references are checked during canonicalization")
1114 }
1115 };
1116
1117 let subtype = |group, index| -> &SubType {
1118 let id = core_type_id(group, index);
1119 &self[id]
1120 };
1121
1122 use AbstractHeapType::*;
1123 use CompositeInnerType as CT;
1124 use HeapType as HT;
1125 match (a.heap_type(), b.heap_type()) {
1126 (a, b) if a == b => true,
1127
1128 (
1129 HT::Abstract {
1130 shared: a_shared,
1131 ty: a_ty,
1132 },
1133 HT::Abstract {
1134 shared: b_shared,
1135 ty: b_ty,
1136 },
1137 ) => a_shared == b_shared && a_ty.is_subtype_of(b_ty),
1138
1139 (HT::Concrete(a), HT::Abstract { shared, ty }) => {
1140 let a_ty = &subtype(a_group, a).composite_type;
1141 if a_ty.shared != shared {
1142 return false;
1143 }
1144 match ty {
1145 Any | Eq => matches!(a_ty.inner, CT::Array(_) | CT::Struct(_)),
1146 Struct => matches!(a_ty.inner, CT::Struct(_)),
1147 Array => matches!(a_ty.inner, CT::Array(_)),
1148 Func => matches!(a_ty.inner, CT::Func(_)),
1149 Cont => matches!(a_ty.inner, CT::Cont(_)),
1150 Extern | Exn | I31 | None | NoFunc | NoExtern | NoExn | NoCont => false,
1153 }
1154 }
1155
1156 (HT::Abstract { shared, ty }, HT::Concrete(b)) => {
1157 let b_ty = &subtype(b_group, b).composite_type;
1158 if shared != b_ty.shared {
1159 return false;
1160 }
1161 match ty {
1162 None => matches!(b_ty.inner, CT::Array(_) | CT::Struct(_)),
1163 NoFunc => matches!(b_ty.inner, CT::Func(_)),
1164 NoCont => matches!(b_ty.inner, CT::Cont(_)),
1165 Cont | Func | Extern | Exn | Any | Eq | Array | I31 | Struct | NoExtern
1168 | NoExn => false,
1169 }
1170 }
1171
1172 (HT::Concrete(a), HT::Concrete(b)) => {
1173 self.id_is_subtype(core_type_id(a_group, a), core_type_id(b_group, b))
1174 }
1175 }
1176 }
1177
1178 pub fn valtype_is_subtype(&self, a: ValType, b: ValType) -> bool {
1182 match (a, b) {
1183 (a, b) if a == b => true,
1184 (ValType::Ref(a), ValType::Ref(b)) => self.reftype_is_subtype(a, b),
1185 (ValType::Ref(_), _)
1186 | (ValType::I32, _)
1187 | (ValType::I64, _)
1188 | (ValType::F32, _)
1189 | (ValType::F64, _)
1190 | (ValType::V128, _) => false,
1191 }
1192 }
1193
1194 pub fn valtype_is_shared(&self, ty: ValType) -> bool {
1196 match ty {
1197 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => true,
1198 ValType::Ref(rt) => self.reftype_is_shared(rt),
1199 }
1200 }
1201
1202 pub fn reftype_is_shared(&self, ty: RefType) -> bool {
1207 match ty.heap_type() {
1208 HeapType::Abstract { shared, .. } => shared,
1209 HeapType::Concrete(index) => {
1210 self[index.as_core_type_id().unwrap()].composite_type.shared
1211 }
1212 }
1213 }
1214
1215 pub fn top_type(&self, heap_type: &HeapType) -> HeapType {
1220 use AbstractHeapType::*;
1221 match *heap_type {
1222 HeapType::Concrete(idx) => {
1223 let ty = &self[idx.as_core_type_id().unwrap()].composite_type;
1224 let shared = ty.shared;
1225 match ty.inner {
1226 CompositeInnerType::Func(_) => HeapType::Abstract { shared, ty: Func },
1227 CompositeInnerType::Array(_) | CompositeInnerType::Struct(_) => {
1228 HeapType::Abstract { shared, ty: Any }
1229 }
1230 CompositeInnerType::Cont(_) => HeapType::Abstract { shared, ty: Cont },
1231 }
1232 }
1233 HeapType::Abstract { shared, ty } => {
1234 let ty = match ty {
1235 Func | NoFunc => Func,
1236 Extern | NoExtern => Extern,
1237 Any | Eq | Struct | Array | I31 | None => Any,
1238 Exn | NoExn => Exn,
1239 Cont | NoCont => Cont,
1240 };
1241 HeapType::Abstract { shared, ty }
1242 }
1243 }
1244 }
1245
1246 pub fn commit(&mut self) -> TypeList {
1247 TypeList {
1248 core_types: self.core_types.commit(),
1249 core_type_to_rec_group: self.core_type_to_rec_group.commit(),
1250 core_type_to_supertype: self.core_type_to_supertype.commit(),
1251 core_type_to_depth: None,
1252 rec_group_elements: self.rec_group_elements.commit(),
1253 canonical_rec_groups: None,
1254 #[cfg(feature = "component-model")]
1255 component: self.component.commit(),
1256 }
1257 }
1258}
1259
1260impl<T> Index<T> for TypeList
1261where
1262 T: TypeIdentifier,
1263{
1264 type Output = T::Data;
1265
1266 fn index(&self, id: T) -> &Self::Output {
1267 let arena = T::list(self);
1268 &arena[id.index()]
1269 }
1270}
1271
1272pub(crate) struct TypeAlloc {
1275 list: TypeList,
1276 #[cfg(feature = "component-model")]
1277 pub(super) component_alloc: ComponentTypeAlloc,
1278}
1279
1280impl Default for TypeAlloc {
1281 fn default() -> TypeAlloc {
1282 let mut ret = TypeAlloc {
1283 list: TypeList::default(),
1284 #[cfg(feature = "component-model")]
1285 component_alloc: ComponentTypeAlloc::default(),
1286 };
1287 ret.list.core_type_to_depth = Some(Default::default());
1288 ret.list.canonical_rec_groups = Some(Default::default());
1289 ret
1290 }
1291}
1292
1293impl Deref for TypeAlloc {
1294 type Target = TypeList;
1295 fn deref(&self) -> &TypeList {
1296 &self.list
1297 }
1298}
1299
1300impl DerefMut for TypeAlloc {
1301 fn deref_mut(&mut self) -> &mut TypeList {
1302 &mut self.list
1303 }
1304}
1305
1306impl<T> Index<T> for TypeAlloc
1307where
1308 T: TypeIdentifier,
1309{
1310 type Output = T::Data;
1311
1312 #[inline]
1313 fn index(&self, id: T) -> &T::Data {
1314 &self.list[id]
1315 }
1316}