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 FuncExact(CoreTypeId),
265}
266
267impl EntityType {
268 #[cfg(feature = "component-model")]
269 pub(crate) fn desc(&self) -> &'static str {
270 match self {
271 Self::Func(_) => "func",
272 Self::Table(_) => "table",
273 Self::Memory(_) => "memory",
274 Self::Global(_) => "global",
275 Self::Tag(_) => "tag",
276 Self::FuncExact(_) => "func_exact",
277 }
278 }
279
280 pub(crate) fn info(&self, types: &TypeList) -> TypeInfo {
281 match self {
282 Self::Func(id) | Self::Tag(id) | Self::FuncExact(id) => types[*id].type_info(types),
283 Self::Table(_) | Self::Memory(_) | Self::Global(_) => TypeInfo::new(),
284 }
285 }
286}
287
288#[allow(clippy::large_enum_variant)]
289pub(super) enum TypesKind {
290 Module(Arc<Module>),
291 #[cfg(feature = "component-model")]
292 Component(ComponentState),
293}
294
295pub struct Types {
299 id: ValidatorId,
300 pub(super) list: TypeList,
301 pub(super) kind: TypesKind,
302}
303
304#[derive(Clone, Copy)]
305pub(super) enum TypesRefKind<'a> {
306 Module(&'a Module),
307 #[cfg(feature = "component-model")]
308 Component(&'a ComponentState),
309}
310
311#[derive(Clone, Copy)]
315pub struct TypesRef<'a> {
316 id: ValidatorId,
317 pub(super) list: &'a TypeList,
318 pub(super) kind: TypesRefKind<'a>,
319}
320
321impl<'a> TypesRef<'a> {
322 pub(crate) fn from_module(id: ValidatorId, types: &'a TypeList, module: &'a Module) -> Self {
323 Self {
324 id,
325 list: types,
326 kind: TypesRefKind::Module(module),
327 }
328 }
329
330 #[cfg(feature = "component-model")]
331 pub(crate) fn from_component(
332 id: ValidatorId,
333 types: &'a TypeList,
334 component: &'a ComponentState,
335 ) -> Self {
336 Self {
337 id,
338 list: types,
339 kind: TypesRefKind::Component(component),
340 }
341 }
342
343 #[inline]
345 pub fn id(&self) -> ValidatorId {
346 self.id
347 }
348
349 pub fn get<T>(&self, id: T) -> Option<&'a T::Data>
353 where
354 T: TypeIdentifier,
355 {
356 self.list.get(id)
357 }
358
359 pub fn rec_group_id_of(&self, id: CoreTypeId) -> RecGroupId {
361 self.list.rec_group_id_of(id)
362 }
363
364 pub fn rec_group_elements(&self, id: RecGroupId) -> impl ExactSizeIterator<Item = CoreTypeId> {
366 let range = &self.list.rec_group_elements[id];
367 (range.start.index..range.end.index).map(|index| CoreTypeId { index })
368 }
369
370 pub fn supertype_of(&self, id: CoreTypeId) -> Option<CoreTypeId> {
372 self.list.supertype_of(id)
373 }
374
375 pub fn core_type_at_in_module(&self, index: u32) -> CoreTypeId {
386 match &self.kind {
387 TypesRefKind::Module(module) => module.types[index as usize].into(),
388 #[cfg(feature = "component-model")]
389 TypesRefKind::Component(_) => panic!("use `core_type_at_in_component` instead"),
390 }
391 }
392
393 pub fn core_type_count_in_module(&self) -> u32 {
398 match &self.kind {
399 TypesRefKind::Module(module) => module.types.len() as u32,
400 #[cfg(feature = "component-model")]
401 TypesRefKind::Component(_) => 0,
402 }
403 }
404
405 pub fn table_at(&self, index: u32) -> TableType {
411 let tables = match &self.kind {
412 TypesRefKind::Module(module) => &module.tables,
413 #[cfg(feature = "component-model")]
414 TypesRefKind::Component(component) => &component.core_tables,
415 };
416 tables[index as usize]
417 }
418
419 pub fn table_count(&self) -> u32 {
421 match &self.kind {
422 TypesRefKind::Module(module) => module.tables.len() as u32,
423 #[cfg(feature = "component-model")]
424 TypesRefKind::Component(component) => component.core_tables.len() as u32,
425 }
426 }
427
428 pub fn memory_at(&self, index: u32) -> MemoryType {
434 let memories = match &self.kind {
435 TypesRefKind::Module(module) => &module.memories,
436 #[cfg(feature = "component-model")]
437 TypesRefKind::Component(component) => &component.core_memories,
438 };
439
440 memories[index as usize]
441 }
442
443 pub fn memory_count(&self) -> u32 {
445 match &self.kind {
446 TypesRefKind::Module(module) => module.memories.len() as u32,
447 #[cfg(feature = "component-model")]
448 TypesRefKind::Component(component) => component.core_memories.len() as u32,
449 }
450 }
451
452 pub fn global_at(&self, index: u32) -> GlobalType {
458 let globals = match &self.kind {
459 TypesRefKind::Module(module) => &module.globals,
460 #[cfg(feature = "component-model")]
461 TypesRefKind::Component(component) => &component.core_globals,
462 };
463
464 globals[index as usize]
465 }
466
467 pub fn global_count(&self) -> u32 {
469 match &self.kind {
470 TypesRefKind::Module(module) => module.globals.len() as u32,
471 #[cfg(feature = "component-model")]
472 TypesRefKind::Component(component) => component.core_globals.len() as u32,
473 }
474 }
475
476 pub fn tag_at(&self, index: u32) -> CoreTypeId {
482 let tags = match &self.kind {
483 TypesRefKind::Module(module) => &module.tags,
484 #[cfg(feature = "component-model")]
485 TypesRefKind::Component(component) => &component.core_tags,
486 };
487 tags[index as usize]
488 }
489
490 pub fn tag_count(&self) -> u32 {
492 match &self.kind {
493 TypesRefKind::Module(module) => module.tags.len() as u32,
494 #[cfg(feature = "component-model")]
495 TypesRefKind::Component(component) => component.core_tags.len() as u32,
496 }
497 }
498
499 pub fn core_function_at(&self, index: u32) -> CoreTypeId {
505 match &self.kind {
506 TypesRefKind::Module(module) => module.types[module.functions[index as usize] as usize],
507 #[cfg(feature = "component-model")]
508 TypesRefKind::Component(component) => component.core_funcs[index as usize],
509 }
510 }
511
512 pub fn function_count(&self) -> u32 {
517 match &self.kind {
518 TypesRefKind::Module(module) => module.functions.len() as u32,
519 #[cfg(feature = "component-model")]
520 TypesRefKind::Component(component) => component.core_funcs.len() as u32,
521 }
522 }
523
524 pub fn element_at(&self, index: u32) -> RefType {
530 match &self.kind {
531 TypesRefKind::Module(module) => module.element_types[index as usize],
532 #[cfg(feature = "component-model")]
533 TypesRefKind::Component(_) => {
534 panic!("no elements on a component")
535 }
536 }
537 }
538
539 pub fn element_count(&self) -> u32 {
541 match &self.kind {
542 TypesRefKind::Module(module) => module.element_types.len() as u32,
543 #[cfg(feature = "component-model")]
544 TypesRefKind::Component(_) => 0,
545 }
546 }
547
548 pub fn entity_type_from_import(&self, import: &Import) -> Option<EntityType> {
550 match &self.kind {
551 TypesRefKind::Module(module) => Some(match import.ty {
552 TypeRef::Func(idx) => EntityType::Func(*module.types.get(idx as usize)?),
553 TypeRef::FuncExact(idx) => EntityType::FuncExact(*module.types.get(idx as usize)?),
554 TypeRef::Table(ty) => EntityType::Table(ty),
555 TypeRef::Memory(ty) => EntityType::Memory(ty),
556 TypeRef::Global(ty) => EntityType::Global(ty),
557 TypeRef::Tag(ty) => EntityType::Tag(*module.types.get(ty.func_type_idx as usize)?),
558 }),
559 #[cfg(feature = "component-model")]
560 TypesRefKind::Component(_) => None,
561 }
562 }
563
564 pub fn entity_type_from_export(&self, export: &Export) -> Option<EntityType> {
566 match &self.kind {
567 TypesRefKind::Module(module) => Some(match export.kind {
568 ExternalKind::Func | ExternalKind::FuncExact => EntityType::Func(
569 module.types[*module.functions.get(export.index as usize)? as usize],
570 ),
571 ExternalKind::Table => {
572 EntityType::Table(*module.tables.get(export.index as usize)?)
573 }
574 ExternalKind::Memory => {
575 EntityType::Memory(*module.memories.get(export.index as usize)?)
576 }
577 ExternalKind::Global => {
578 EntityType::Global(*module.globals.get(export.index as usize)?)
579 }
580 ExternalKind::Tag => EntityType::Tag(*module.tags.get(export.index as usize)?),
581 }),
582 #[cfg(feature = "component-model")]
583 TypesRefKind::Component(_) => None,
584 }
585 }
586
587 pub fn core_imports(
591 &self,
592 ) -> Option<impl Iterator<Item = (&'a str, &'a str, EntityType)> + 'a> {
593 match &self.kind {
594 TypesRefKind::Module(module) => Some(
595 module
596 .imports
597 .iter()
598 .flat_map(|((m, n), t)| t.iter().map(move |t| (m.as_str(), n.as_str(), *t))),
599 ),
600 #[cfg(feature = "component-model")]
601 TypesRefKind::Component(_) => None,
602 }
603 }
604
605 pub fn core_exports(&self) -> Option<impl Iterator<Item = (&'a str, EntityType)> + 'a> {
609 match &self.kind {
610 TypesRefKind::Module(module) => {
611 Some(module.exports.iter().map(|(n, t)| (n.as_str(), *t)))
612 }
613 #[cfg(feature = "component-model")]
614 TypesRefKind::Component(_) => None,
615 }
616 }
617}
618
619impl<T> Index<T> for TypesRef<'_>
620where
621 T: TypeIdentifier,
622{
623 type Output = T::Data;
624
625 fn index(&self, index: T) -> &Self::Output {
626 &self.list[index]
627 }
628}
629
630impl Types {
631 pub(crate) fn from_module(id: ValidatorId, types: TypeList, module: Arc<Module>) -> Self {
632 Self {
633 id,
634 list: types,
635 kind: TypesKind::Module(module),
636 }
637 }
638
639 #[cfg(feature = "component-model")]
640 pub(crate) fn from_component(
641 id: ValidatorId,
642 types: TypeList,
643 component: ComponentState,
644 ) -> Self {
645 Self {
646 id,
647 list: types,
648 kind: TypesKind::Component(component),
649 }
650 }
651
652 pub fn as_ref(&self) -> TypesRef<'_> {
654 TypesRef {
655 id: self.id,
656 list: &self.list,
657 kind: match &self.kind {
658 TypesKind::Module(module) => TypesRefKind::Module(module),
659 #[cfg(feature = "component-model")]
660 TypesKind::Component(component) => TypesRefKind::Component(component),
661 },
662 }
663 }
664}
665
666impl<T> Index<T> for Types
667where
668 T: TypeIdentifier,
669{
670 type Output = T::Data;
671
672 fn index(&self, id: T) -> &Self::Output {
673 &self.list[id]
674 }
675}
676
677#[doc(hidden)]
691#[derive(Debug)]
692pub struct SnapshotList<T> {
693 snapshots: Vec<Arc<Snapshot<T>>>,
703
704 snapshots_total: usize,
706
707 cur: Vec<T>,
709}
710
711#[derive(Debug)]
712struct Snapshot<T> {
713 prior_types: usize,
714 items: Vec<T>,
715}
716
717impl<T> SnapshotList<T> {
718 pub(crate) fn get(&self, index: usize) -> Option<&T> {
720 if index >= self.snapshots_total {
722 return self.cur.get(index - self.snapshots_total);
723 }
724 let i = match self
728 .snapshots
729 .binary_search_by_key(&index, |snapshot| snapshot.prior_types)
730 {
731 Ok(i) => i,
732 Err(i) => i - 1,
733 };
734 let snapshot = &self.snapshots[i];
735 Some(&snapshot.items[index - snapshot.prior_types])
736 }
737
738 pub(crate) fn push(&mut self, val: T) {
740 self.cur.push(val);
741 }
742
743 pub(crate) fn len(&self) -> usize {
745 self.cur.len() + self.snapshots_total
746 }
747
748 #[cfg(feature = "component-model")]
750 pub(crate) fn truncate(&mut self, len: usize) {
751 assert!(len >= self.snapshots_total);
752 self.cur.truncate(len - self.snapshots_total);
753 }
754
755 pub(crate) fn commit(&mut self) -> SnapshotList<T> {
762 let len = self.cur.len();
767 if len > 0 {
768 self.cur.shrink_to_fit();
769 self.snapshots.push(Arc::new(Snapshot {
770 prior_types: self.snapshots_total,
771 items: mem::take(&mut self.cur),
772 }));
773 self.snapshots_total += len;
774 }
775 SnapshotList {
776 snapshots: self.snapshots.clone(),
777 snapshots_total: self.snapshots_total,
778 cur: Vec::new(),
779 }
780 }
781}
782
783impl<T> Index<usize> for SnapshotList<T> {
784 type Output = T;
785
786 #[inline]
787 fn index(&self, index: usize) -> &T {
788 match self.get(index) {
789 Some(x) => x,
790 None => panic!(
791 "out-of-bounds indexing into `SnapshotList`: index is {index}, but length is {}",
792 self.len()
793 ),
794 }
795 }
796}
797
798impl<T, U> Index<U> for SnapshotList<T>
799where
800 U: TypeIdentifier<Data = T>,
801{
802 type Output = T;
803
804 #[inline]
805 fn index(&self, id: U) -> &T {
806 self.get(id.index()).unwrap()
807 }
808}
809
810impl<T> Default for SnapshotList<T> {
811 fn default() -> SnapshotList<T> {
812 SnapshotList {
813 snapshots: Vec::new(),
814 snapshots_total: 0,
815 cur: Vec::new(),
816 }
817 }
818}
819
820#[derive(Default, Debug)]
828#[doc(hidden)]
830pub struct TypeList {
831 pub(super) core_types: SnapshotList<SubType>,
835 pub(super) core_type_to_rec_group: SnapshotList<RecGroupId>,
839 pub(super) core_type_to_supertype: SnapshotList<Option<CoreTypeId>>,
843 pub(super) core_type_to_depth: Option<IndexMap<CoreTypeId, u8>>,
848 pub(super) rec_group_elements: SnapshotList<Range<CoreTypeId>>,
851 pub(super) canonical_rec_groups: Option<Map<RecGroup, RecGroupId>>,
856
857 #[cfg(feature = "component-model")]
858 pub(super) component: ComponentTypeList,
859}
860
861impl TypeList {
862 pub fn get<T>(&self, id: T) -> Option<&T::Data>
863 where
864 T: TypeIdentifier,
865 {
866 T::list(self).get(id.index())
867 }
868
869 pub fn push<T>(&mut self, ty: T) -> T::Id
870 where
871 T: TypeData,
872 {
873 let index = u32::try_from(T::Id::list(self).len()).unwrap();
874 let id = T::Id::from_index(index);
875 T::Id::list_mut(self).push(ty);
876 id
877 }
878
879 pub fn intern_canonical_rec_group(
891 &mut self,
892 needs_type_canonicalization: bool,
893 mut rec_group: RecGroup,
894 ) -> (bool, RecGroupId) {
895 let rec_group_id = self.rec_group_elements.len();
896 let rec_group_id = u32::try_from(rec_group_id).unwrap();
897 let rec_group_id = RecGroupId::from_index(rec_group_id);
898
899 if needs_type_canonicalization {
900 let canonical_rec_groups = self
901 .canonical_rec_groups
902 .as_mut()
903 .expect("cannot intern into a committed list");
904 let entry = match canonical_rec_groups.entry(rec_group) {
905 Entry::Occupied(e) => return (false, *e.get()),
906 Entry::Vacant(e) => e,
907 };
908 rec_group = entry.key().clone();
909 entry.insert(rec_group_id);
910 }
911
912 let start = self.core_types.len();
913 let start = u32::try_from(start).unwrap();
914 let start = CoreTypeId::from_index(start);
915
916 for mut ty in rec_group.into_types() {
917 debug_assert_eq!(self.core_types.len(), self.core_type_to_supertype.len());
918 debug_assert_eq!(self.core_types.len(), self.core_type_to_rec_group.len());
919
920 self.core_type_to_supertype
921 .push(ty.supertype_idx.and_then(|idx| match idx.unpack() {
922 UnpackedIndex::RecGroup(offset) => {
923 Some(CoreTypeId::from_index(start.index + offset))
924 }
925 UnpackedIndex::Id(id) => Some(id),
926 UnpackedIndex::Module(_) => None,
929 }));
930 ty.remap_indices(&mut |index| {
931 if let UnpackedIndex::RecGroup(offset) = index.unpack() {
935 *index = UnpackedIndex::Id(CoreTypeId::from_index(start.index + offset))
936 .pack()
937 .unwrap();
938 }
939 Ok(())
940 })
941 .expect("cannot fail");
942 self.core_types.push(ty);
943 self.core_type_to_rec_group.push(rec_group_id);
944 }
945
946 let end = self.core_types.len();
947 let end = u32::try_from(end).unwrap();
948 let end = CoreTypeId::from_index(end);
949
950 let range = start..end;
951
952 self.rec_group_elements.push(range.clone());
953
954 return (true, rec_group_id);
955 }
956
957 pub fn intern_sub_type(&mut self, sub_ty: SubType, offset: usize) -> CoreTypeId {
960 let (_is_new, group_id) =
961 self.intern_canonical_rec_group(true, RecGroup::implicit(offset, sub_ty));
962 self[group_id].start
963 }
964
965 pub fn intern_func_type(&mut self, ty: FuncType, offset: usize) -> CoreTypeId {
968 self.intern_sub_type(SubType::func(ty, false), offset)
969 }
970
971 pub fn rec_group_local_id(
973 &self,
974 rec_group: RecGroupId,
975 index: u32,
976 offset: usize,
977 ) -> Result<CoreTypeId> {
978 let elems = &self[rec_group];
979 let len = elems.end.index() - elems.start.index();
980 let len = u32::try_from(len).unwrap();
981 if index < len {
982 let id = u32::try_from(elems.start.index()).unwrap() + index;
983 let id = CoreTypeId::from_index(id);
984 Ok(id)
985 } else {
986 bail!(
987 offset,
988 "unknown type {index}: type index out of rec group bounds"
989 )
990 }
991 }
992
993 pub fn rec_group_id_of(&self, id: CoreTypeId) -> RecGroupId {
995 self.core_type_to_rec_group[id.index()]
996 }
997
998 pub fn supertype_of(&self, id: CoreTypeId) -> Option<CoreTypeId> {
1000 self.core_type_to_supertype[id.index()]
1001 }
1002
1003 pub fn get_subtyping_depth(&self, id: CoreTypeId) -> u8 {
1006 let depth = self
1007 .core_type_to_depth
1008 .as_ref()
1009 .expect("cannot get subtype depth from a committed list")[&id];
1010 debug_assert!(usize::from(depth) <= crate::limits::MAX_WASM_SUBTYPING_DEPTH);
1011 depth
1012 }
1013
1014 pub fn set_subtyping_depth(&mut self, id: CoreTypeId, depth: u8) {
1017 debug_assert!(usize::from(depth) <= crate::limits::MAX_WASM_SUBTYPING_DEPTH);
1018 let map = self
1019 .core_type_to_depth
1020 .as_mut()
1021 .expect("cannot set a subtype depth in a committed list");
1022 debug_assert!(!map.contains_key(&id));
1023 map.insert(id, depth);
1024 }
1025
1026 pub fn at_canonicalized_packed_index(
1030 &self,
1031 rec_group: RecGroupId,
1032 index: PackedIndex,
1033 offset: usize,
1034 ) -> Result<CoreTypeId> {
1035 self.at_canonicalized_unpacked_index(rec_group, index.unpack(), offset)
1036 }
1037
1038 pub fn at_canonicalized_unpacked_index(
1042 &self,
1043 rec_group: RecGroupId,
1044 index: UnpackedIndex,
1045 offset: usize,
1046 ) -> Result<CoreTypeId> {
1047 match index {
1048 UnpackedIndex::Module(_) => panic!("not canonicalized"),
1049 UnpackedIndex::Id(id) => Ok(id),
1050 UnpackedIndex::RecGroup(idx) => self.rec_group_local_id(rec_group, idx, offset),
1051 }
1052 }
1053
1054 pub fn matches(&self, a: CoreTypeId, b: CoreTypeId) -> bool {
1056 let a = WithRecGroup::new(self, a);
1057 let a = WithRecGroup::map(a, |a| &self[a]);
1058
1059 let b = WithRecGroup::new(self, b);
1060 let b = WithRecGroup::map(b, |b| &self[b]);
1061
1062 Matches::matches(self, a, b)
1063 }
1064
1065 pub fn id_is_subtype(&self, mut a: CoreTypeId, b: CoreTypeId) -> bool {
1068 loop {
1069 if a == b {
1070 return true;
1071 }
1072
1073 a = match self.supertype_of(a) {
1076 Some(a) => a,
1077 None => return false,
1078 };
1079 }
1080 }
1081
1082 pub fn reftype_is_subtype(&self, a: RefType, b: RefType) -> bool {
1086 self.reftype_is_subtype_impl(a, None, b, None)
1090 }
1091
1092 pub(crate) fn reftype_is_subtype_impl(
1098 &self,
1099 a: RefType,
1100 a_group: Option<RecGroupId>,
1101 b: RefType,
1102 b_group: Option<RecGroupId>,
1103 ) -> bool {
1104 if a == b && a_group == b_group {
1105 return true;
1106 }
1107
1108 if a.is_nullable() && !b.is_nullable() {
1109 return false;
1110 }
1111
1112 let core_type_id = |group: Option<RecGroupId>, index: UnpackedIndex| -> CoreTypeId {
1113 if let Some(id) = index.as_core_type_id() {
1114 id
1115 } else {
1116 self.at_canonicalized_unpacked_index(group.unwrap(), index, usize::MAX)
1117 .expect("type references are checked during canonicalization")
1118 }
1119 };
1120
1121 let subtype = |group, index| -> &SubType {
1122 let id = core_type_id(group, index);
1123 &self[id]
1124 };
1125
1126 use AbstractHeapType::*;
1127 use CompositeInnerType as CT;
1128 use HeapType as HT;
1129 match (a.heap_type(), b.heap_type()) {
1130 (a, b) if a == b => true,
1131
1132 (
1133 HT::Abstract {
1134 shared: a_shared,
1135 ty: a_ty,
1136 },
1137 HT::Abstract {
1138 shared: b_shared,
1139 ty: b_ty,
1140 },
1141 ) => a_shared == b_shared && a_ty.is_subtype_of(b_ty),
1142
1143 (HT::Concrete(a), HT::Abstract { shared, ty })
1144 | (HT::Exact(a), HT::Abstract { shared, ty }) => {
1145 let a_ty = &subtype(a_group, a).composite_type;
1146 if a_ty.shared != shared {
1147 return false;
1148 }
1149 match ty {
1150 Any | Eq => matches!(a_ty.inner, CT::Array(_) | CT::Struct(_)),
1151 Struct => matches!(a_ty.inner, CT::Struct(_)),
1152 Array => matches!(a_ty.inner, CT::Array(_)),
1153 Func => matches!(a_ty.inner, CT::Func(_)),
1154 Cont => matches!(a_ty.inner, CT::Cont(_)),
1155 Extern | Exn | I31 | None | NoFunc | NoExtern | NoExn | NoCont => false,
1158 }
1159 }
1160
1161 (HT::Abstract { shared, ty }, HT::Concrete(b))
1162 | (HT::Abstract { shared, ty }, HT::Exact(b)) => {
1163 let b_ty = &subtype(b_group, b).composite_type;
1164 if shared != b_ty.shared {
1165 return false;
1166 }
1167 match ty {
1168 None => matches!(b_ty.inner, CT::Array(_) | CT::Struct(_)),
1169 NoFunc => matches!(b_ty.inner, CT::Func(_)),
1170 NoCont => matches!(b_ty.inner, CT::Cont(_)),
1171 Cont | Func | Extern | Exn | Any | Eq | Array | I31 | Struct | NoExtern
1174 | NoExn => false,
1175 }
1176 }
1177
1178 (HT::Concrete(a), HT::Concrete(b)) | (HT::Exact(a), HT::Concrete(b)) => {
1179 self.id_is_subtype(core_type_id(a_group, a), core_type_id(b_group, b))
1180 }
1181
1182 (HT::Exact(a), HT::Exact(b)) => core_type_id(a_group, a) == core_type_id(b_group, b),
1183
1184 (HT::Concrete(_), HT::Exact(_)) => false,
1185 }
1186 }
1187
1188 pub fn valtype_is_subtype(&self, a: ValType, b: ValType) -> bool {
1192 match (a, b) {
1193 (a, b) if a == b => true,
1194 (ValType::Ref(a), ValType::Ref(b)) => self.reftype_is_subtype(a, b),
1195 (ValType::Ref(_), _)
1196 | (ValType::I32, _)
1197 | (ValType::I64, _)
1198 | (ValType::F32, _)
1199 | (ValType::F64, _)
1200 | (ValType::V128, _) => false,
1201 }
1202 }
1203
1204 pub fn valtype_is_shared(&self, ty: ValType) -> bool {
1206 match ty {
1207 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => true,
1208 ValType::Ref(rt) => self.reftype_is_shared(rt),
1209 }
1210 }
1211
1212 pub fn reftype_is_shared(&self, ty: RefType) -> bool {
1217 match ty.heap_type() {
1218 HeapType::Abstract { shared, .. } => shared,
1219 HeapType::Concrete(index) | HeapType::Exact(index) => {
1220 self[index.as_core_type_id().unwrap()].composite_type.shared
1221 }
1222 }
1223 }
1224
1225 pub fn top_type(&self, heap_type: &HeapType) -> HeapType {
1230 use AbstractHeapType::*;
1231 match *heap_type {
1232 HeapType::Concrete(idx) | HeapType::Exact(idx) => {
1233 let ty = &self[idx.as_core_type_id().unwrap()].composite_type;
1234 let shared = ty.shared;
1235 match ty.inner {
1236 CompositeInnerType::Func(_) => HeapType::Abstract { shared, ty: Func },
1237 CompositeInnerType::Array(_) | CompositeInnerType::Struct(_) => {
1238 HeapType::Abstract { shared, ty: Any }
1239 }
1240 CompositeInnerType::Cont(_) => HeapType::Abstract { shared, ty: Cont },
1241 }
1242 }
1243 HeapType::Abstract { shared, ty } => {
1244 let ty = match ty {
1245 Func | NoFunc => Func,
1246 Extern | NoExtern => Extern,
1247 Any | Eq | Struct | Array | I31 | None => Any,
1248 Exn | NoExn => Exn,
1249 Cont | NoCont => Cont,
1250 };
1251 HeapType::Abstract { shared, ty }
1252 }
1253 }
1254 }
1255
1256 pub fn commit(&mut self) -> TypeList {
1257 TypeList {
1258 core_types: self.core_types.commit(),
1259 core_type_to_rec_group: self.core_type_to_rec_group.commit(),
1260 core_type_to_supertype: self.core_type_to_supertype.commit(),
1261 core_type_to_depth: None,
1262 rec_group_elements: self.rec_group_elements.commit(),
1263 canonical_rec_groups: None,
1264 #[cfg(feature = "component-model")]
1265 component: self.component.commit(),
1266 }
1267 }
1268}
1269
1270impl<T> Index<T> for TypeList
1271where
1272 T: TypeIdentifier,
1273{
1274 type Output = T::Data;
1275
1276 fn index(&self, id: T) -> &Self::Output {
1277 let arena = T::list(self);
1278 &arena[id.index()]
1279 }
1280}
1281
1282pub(crate) struct TypeAlloc {
1285 list: TypeList,
1286 #[cfg(feature = "component-model")]
1287 pub(super) component_alloc: ComponentTypeAlloc,
1288}
1289
1290impl Default for TypeAlloc {
1291 fn default() -> TypeAlloc {
1292 let mut ret = TypeAlloc {
1293 list: TypeList::default(),
1294 #[cfg(feature = "component-model")]
1295 component_alloc: ComponentTypeAlloc::default(),
1296 };
1297 ret.list.core_type_to_depth = Some(Default::default());
1298 ret.list.canonical_rec_groups = Some(Default::default());
1299 ret
1300 }
1301}
1302
1303impl Deref for TypeAlloc {
1304 type Target = TypeList;
1305 fn deref(&self) -> &TypeList {
1306 &self.list
1307 }
1308}
1309
1310impl DerefMut for TypeAlloc {
1311 fn deref_mut(&mut self) -> &mut TypeList {
1312 &mut self.list
1313 }
1314}
1315
1316impl<T> Index<T> for TypeAlloc
1317where
1318 T: TypeIdentifier,
1319{
1320 type Output = T::Data;
1321
1322 #[inline]
1323 fn index(&self, id: T) -> &T::Data {
1324 &self.list[id]
1325 }
1326}