Next Generation WASM Microkernel Operating System
1// Copyright 2025 Jonas Kruckenberg
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8use alloc::string::{String, ToString};
9use alloc::vec::Vec;
10use core::fmt;
11use core::fmt::{Display, Write};
12
13use anyhow::{bail, ensure};
14
15use crate::wasm::Engine;
16use crate::wasm::indices::{CanonicalizedTypeIndex, VMSharedTypeIndex};
17use crate::wasm::translate::{
18 EntityType, Global, Memory, ModuleTypes, Table, Tag, WasmCompositeType, WasmCompositeTypeInner,
19 WasmFieldType, WasmFuncType, WasmHeapType, WasmHeapTypeInner, WasmRefType, WasmStorageType,
20 WasmSubType, WasmValType,
21};
22use crate::wasm::type_registry::RegisteredType;
23
24/// Indicator of whether a global value, struct's field, or array type's
25/// elements are mutable or not.
26#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
27pub enum Mutability {
28 /// The global value, struct field, or array elements are constant and the
29 /// value does not change.
30 Const,
31 /// The value of the global, struct field, or array elements can change over
32 /// time.
33 Var,
34}
35
36impl Mutability {
37 /// Is this constant?
38 #[inline]
39 pub fn is_const(self) -> bool {
40 self == Self::Const
41 }
42
43 /// Is this variable?
44 #[inline]
45 pub fn is_var(self) -> bool {
46 self == Self::Var
47 }
48}
49
50/// Indicator of whether a type is final or not.
51///
52/// Final types may not be the supertype of other types.
53#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
54pub enum Finality {
55 /// The associated type is final.
56 Final,
57 /// The associated type is not final.
58 NonFinal,
59}
60
61impl Finality {
62 /// Is this final?
63 #[inline]
64 pub fn is_final(self) -> bool {
65 self == Self::Final
66 }
67
68 /// Is this non-final?
69 #[inline]
70 pub fn is_non_final(self) -> bool {
71 self == Self::NonFinal
72 }
73}
74
75/// Possible value types in WebAssembly.
76///
77/// # Subtyping and Equality
78///
79/// `ValType` does not implement `Eq`, because reference types have a subtyping
80/// relationship, and so 99.99% of the time you actually want to check whether
81/// one type matches (i.e. is a subtype of) another type. You can use the
82/// [`ValType::matches`] and [`Val::matches_ty`][crate::wasm::Val::matches_ty] methods
83/// to perform these types of checks. If, however, you are in that 0.01%
84/// scenario where you need to check precise equality between types, you can use
85/// the [`ValType::eq`] method.
86#[derive(Clone, Hash)]
87pub enum ValType {
88 // NB: the ordering of variants here is intended to match the ordering in
89 // `wasmtime_environ::WasmType` to help improve codegen when converting.
90 //
91 /// Signed 32 bit integer.
92 I32,
93 /// Signed 64 bit integer.
94 I64,
95 /// Floating point 32 bit integer.
96 F32,
97 /// Floating point 64 bit integer.
98 F64,
99 /// A 128 bit number.
100 V128,
101 /// An opaque reference to some type on the heap.
102 Ref(RefType),
103}
104
105impl fmt::Debug for ValType {
106 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107 fmt::Display::fmt(self, f)
108 }
109}
110
111impl Display for ValType {
112 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
113 match self {
114 ValType::I32 => write!(f, "i32"),
115 ValType::I64 => write!(f, "i64"),
116 ValType::F32 => write!(f, "f32"),
117 ValType::F64 => write!(f, "f64"),
118 ValType::V128 => write!(f, "v128"),
119 ValType::Ref(r) => Display::fmt(r, f),
120 }
121 }
122}
123
124impl ValType {
125 /// The `externref` type, aka `(ref null extern)`.
126 pub const EXTERNREF: Self = ValType::Ref(RefType::EXTERNREF);
127
128 /// The `nullexternref` type, aka `(ref null noextern)`.
129 pub const NULLEXTERNREF: Self = ValType::Ref(RefType::NULLEXTERNREF);
130
131 /// The `funcref` type, aka `(ref null func)`.
132 pub const FUNCREF: Self = ValType::Ref(RefType::FUNCREF);
133
134 /// The `nullfuncref` type, aka `(ref null nofunc)`.
135 pub const NULLFUNCREF: Self = ValType::Ref(RefType::NULLFUNCREF);
136
137 /// The `anyref` type, aka `(ref null any)`.
138 pub const ANYREF: Self = ValType::Ref(RefType::ANYREF);
139
140 /// The `eqref` type, aka `(ref null eq)`.
141 pub const EQREF: Self = ValType::Ref(RefType::EQREF);
142
143 /// The `i31ref` type, aka `(ref null i31)`.
144 pub const I31REF: Self = ValType::Ref(RefType::I31REF);
145
146 /// The `arrayref` type, aka `(ref null array)`.
147 pub const ARRAYREF: Self = ValType::Ref(RefType::ARRAYREF);
148
149 /// The `structref` type, aka `(ref null struct)`.
150 pub const STRUCTREF: Self = ValType::Ref(RefType::STRUCTREF);
151
152 /// The `nullref` type, aka `(ref null none)`.
153 pub const NULLREF: Self = ValType::Ref(RefType::NULLREF);
154
155 /// Returns true if `ValType` matches any of the numeric types. (e.g. `I32`,
156 /// `I64`, `F32`, `F64`).
157 #[inline]
158 pub fn is_num(&self) -> bool {
159 matches!(
160 self,
161 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64
162 )
163 }
164
165 /// Is this the `i32` type?
166 #[inline]
167 pub fn is_i32(&self) -> bool {
168 matches!(self, ValType::I32)
169 }
170
171 /// Is this the `i64` type?
172 #[inline]
173 pub fn is_i64(&self) -> bool {
174 matches!(self, ValType::I64)
175 }
176
177 /// Is this the `f32` type?
178 #[inline]
179 pub fn is_f32(&self) -> bool {
180 matches!(self, ValType::F32)
181 }
182
183 /// Is this the `f64` type?
184 #[inline]
185 pub fn is_f64(&self) -> bool {
186 matches!(self, ValType::F64)
187 }
188
189 /// Is this the `v128` type?
190 #[inline]
191 pub fn is_v128(&self) -> bool {
192 matches!(self, ValType::V128)
193 }
194
195 /// Returns true if `ValType` is any kind of reference type.
196 #[inline]
197 pub fn is_ref(&self) -> bool {
198 matches!(self, ValType::Ref(_))
199 }
200
201 /// Is this the `funcref` (aka `(ref null func)`) type?
202 #[inline]
203 pub fn is_funcref(&self) -> bool {
204 matches!(
205 self,
206 ValType::Ref(RefType {
207 nullable: true,
208 heap_type: HeapType {
209 inner: HeapTypeInner::Func,
210 shared: _
211 }
212 })
213 )
214 }
215
216 /// Is this the `externref` (aka `(ref null extern)`) type?
217 #[inline]
218 pub fn is_externref(&self) -> bool {
219 matches!(
220 self,
221 ValType::Ref(RefType {
222 nullable: true,
223 heap_type: HeapType {
224 inner: HeapTypeInner::Extern,
225 shared: _
226 }
227 })
228 )
229 }
230
231 /// Is this the `anyref` (aka `(ref null any)`) type?
232 #[inline]
233 pub fn is_anyref(&self) -> bool {
234 matches!(
235 self,
236 ValType::Ref(RefType {
237 nullable: true,
238 heap_type: HeapType {
239 inner: HeapTypeInner::Any,
240 shared: _
241 }
242 })
243 )
244 }
245
246 /// Get the underlying reference type, if this value type is a reference
247 /// type.
248 #[inline]
249 pub fn as_ref(&self) -> Option<&RefType> {
250 match self {
251 ValType::Ref(r) => Some(r),
252 _ => None,
253 }
254 }
255
256 /// Get the underlying reference type, panicking if this value type is not a
257 /// reference type.
258 #[inline]
259 pub fn unwrap_ref(&self) -> &RefType {
260 self.as_ref()
261 .expect("ValType::unwrap_ref on a non-reference type")
262 }
263
264 /// Does this value type match the other type?
265 ///
266 /// That is, is this value type a subtype of the other?
267 ///
268 /// # Panics
269 ///
270 /// Panics if either type is associated with a different engine from the
271 /// other.
272 pub fn matches(&self, other: &ValType) -> bool {
273 match (self, other) {
274 (Self::I32, Self::I32) => true,
275 (Self::I64, Self::I64) => true,
276 (Self::F32, Self::F32) => true,
277 (Self::F64, Self::F64) => true,
278 (Self::V128, Self::V128) => true,
279 (Self::Ref(a), Self::Ref(b)) => a.matches(b),
280 (Self::I32 | Self::I64 | Self::F32 | Self::F64 | Self::V128 | Self::Ref(_), _) => false,
281 }
282 }
283
284 /// Is value type `a` precisely equal to value type `b`?
285 ///
286 /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
287 /// are not exactly the same value type.
288 ///
289 /// # Panics
290 ///
291 /// Panics if either type is associated with a different engine.
292 pub fn eq(a: &Self, b: &Self) -> bool {
293 a.matches(b) && b.matches(a)
294 }
295
296 pub fn ensure_matches(&self, engine: &Engine, other: &ValType) -> crate::Result<()> {
297 if !self.comes_from_same_engine(engine) || !other.comes_from_same_engine(engine) {
298 bail!("type used with wrong engine");
299 }
300 if self.matches(other) {
301 Ok(())
302 } else {
303 bail!("type mismatch: expected {other}, found {self}")
304 }
305 }
306
307 pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
308 match self {
309 Self::I32 | Self::I64 | Self::F32 | Self::F64 | Self::V128 => true,
310 Self::Ref(r) => r.comes_from_same_engine(engine),
311 }
312 }
313
314 pub(crate) fn to_wasm_type(&self) -> WasmValType {
315 match self {
316 Self::I32 => WasmValType::I32,
317 Self::I64 => WasmValType::I64,
318 Self::F32 => WasmValType::F32,
319 Self::F64 => WasmValType::F64,
320 Self::V128 => WasmValType::V128,
321 Self::Ref(r) => WasmValType::Ref(r.to_wasm_type()),
322 }
323 }
324
325 #[inline]
326 pub(crate) fn from_wasm_type(engine: &Engine, ty: &WasmValType) -> Self {
327 match ty {
328 WasmValType::I32 => Self::I32,
329 WasmValType::I64 => Self::I64,
330 WasmValType::F32 => Self::F32,
331 WasmValType::F64 => Self::F64,
332 WasmValType::V128 => Self::V128,
333 WasmValType::Ref(r) => Self::Ref(RefType::from_wasm_type(engine, r)),
334 }
335 }
336}
337
338/// Opaque references to data in the Wasm heap or to host data.
339///
340/// # Subtyping and Equality
341///
342/// `RefType` does not implement `Eq`, because reference types have a subtyping
343/// relationship, and so 99.99% of the time you actually want to check whether
344/// one type matches (i.e. is a subtype of) another type. You can use the
345/// [`RefType::matches`] and [`Ref::matches_ty`][crate::Ref::matches_ty] methods
346/// to perform these types of checks. If, however, you are in that 0.01%
347/// scenario where you need to check precise equality between types, you can use
348/// the [`RefType::eq`] method.
349#[derive(Clone, Hash)]
350pub struct RefType {
351 nullable: bool,
352 heap_type: HeapType,
353}
354
355impl fmt::Debug for RefType {
356 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
357 Display::fmt(self, f)
358 }
359}
360
361impl fmt::Display for RefType {
362 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
363 write!(f, "(ref ")?;
364 if self.is_nullable() {
365 write!(f, "null ")?;
366 }
367 write!(f, "{})", self.heap_type())
368 }
369}
370
371impl RefType {
372 /// The `externref` type, aka `(ref null extern)`.
373 pub const EXTERNREF: Self = RefType {
374 nullable: true,
375 heap_type: HeapType::EXTERN,
376 };
377
378 /// The `nullexternref` type, aka `(ref null noextern)`.
379 pub const NULLEXTERNREF: Self = RefType {
380 nullable: true,
381 heap_type: HeapType::NOEXTERN,
382 };
383
384 /// The `funcref` type, aka `(ref null func)`.
385 pub const FUNCREF: Self = RefType {
386 nullable: true,
387 heap_type: HeapType::FUNC,
388 };
389
390 /// The `nullfuncref` type, aka `(ref null nofunc)`.
391 pub const NULLFUNCREF: Self = RefType {
392 nullable: true,
393 heap_type: HeapType::NOFUNC,
394 };
395
396 /// The `anyref` type, aka `(ref null any)`.
397 pub const ANYREF: Self = RefType {
398 nullable: true,
399 heap_type: HeapType::ANY,
400 };
401
402 /// The `eqref` type, aka `(ref null eq)`.
403 pub const EQREF: Self = RefType {
404 nullable: true,
405 heap_type: HeapType::EQ,
406 };
407
408 /// The `i31ref` type, aka `(ref null i31)`.
409 pub const I31REF: Self = RefType {
410 nullable: true,
411 heap_type: HeapType::I31,
412 };
413
414 /// The `arrayref` type, aka `(ref null array)`.
415 pub const ARRAYREF: Self = RefType {
416 nullable: true,
417 heap_type: HeapType::ARRAY,
418 };
419
420 /// The `structref` type, aka `(ref null struct)`.
421 pub const STRUCTREF: Self = RefType {
422 nullable: true,
423 heap_type: HeapType::STRUCT,
424 };
425
426 /// The `nullref` type, aka `(ref null none)`.
427 pub const NULLREF: Self = RefType {
428 nullable: true,
429 heap_type: HeapType::NONE,
430 };
431
432 /// Construct a new reference type.
433 pub fn new(nullable: bool, heap_type: HeapType) -> RefType {
434 RefType {
435 nullable,
436 heap_type,
437 }
438 }
439
440 /// Can this type of reference be null?
441 pub fn is_nullable(&self) -> bool {
442 self.nullable
443 }
444
445 /// The heap type that this is a reference to.
446 #[inline]
447 pub fn heap_type(&self) -> &HeapType {
448 &self.heap_type
449 }
450
451 /// Does this reference type match the other?
452 ///
453 /// That is, is this reference type a subtype of the other?
454 ///
455 /// # Panics
456 ///
457 /// Panics if either type is associated with a different engine from the
458 /// other.
459 pub fn matches(&self, other: &RefType) -> bool {
460 if self.is_nullable() && !other.is_nullable() {
461 return false;
462 }
463 self.heap_type().matches(other.heap_type())
464 }
465
466 /// Is reference type `a` precisely equal to reference type `b`?
467 ///
468 /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
469 /// are not exactly the same reference type.
470 ///
471 /// # Panics
472 ///
473 /// Panics if either type is associated with a different engine.
474 pub fn eq(a: &RefType, b: &RefType) -> bool {
475 a.matches(b) && b.matches(a)
476 }
477
478 pub fn ensure_matches(&self, engine: &Engine, other: &RefType) -> crate::Result<()> {
479 if !self.comes_from_same_engine(engine) || !other.comes_from_same_engine(engine) {
480 bail!("type used with wrong engine");
481 }
482 if self.matches(other) {
483 Ok(())
484 } else {
485 bail!("type mismatch: expected {other}, found {self}")
486 }
487 }
488
489 pub(super) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
490 self.heap_type().comes_from_same_engine(engine)
491 }
492
493 pub(super) fn to_wasm_type(&self) -> WasmRefType {
494 WasmRefType {
495 nullable: self.is_nullable(),
496 heap_type: self.heap_type().to_wasm_type(),
497 }
498 }
499
500 pub(super) fn from_wasm_type(engine: &Engine, ty: &WasmRefType) -> RefType {
501 RefType {
502 nullable: ty.nullable,
503 heap_type: HeapType::from_wasm_type(engine, &ty.heap_type),
504 }
505 }
506}
507
508#[derive(Debug, Clone, Hash)]
509pub struct HeapType {
510 pub shared: bool,
511 pub inner: HeapTypeInner,
512}
513
514#[derive(Debug, Clone, Hash)]
515pub enum HeapTypeInner {
516 /// The abstract `extern` heap type represents external host data.
517 ///
518 /// This is the top type for the external type hierarchy, and therefore is
519 /// the common supertype of all external reference types.
520 Extern,
521 /// The abstract `noextern` heap type represents the null external
522 /// reference.
523 ///
524 /// This is the bottom type for the external type hierarchy, and therefore
525 /// is the common subtype of all external reference types.
526 NoExtern,
527
528 /// The abstract `func` heap type represents a reference to any kind of
529 /// function.
530 ///
531 /// This is the top type for the function references type hierarchy, and is
532 /// therefore a supertype of every function reference.
533 Func,
534 /// A reference to a function of a specific, concrete type.
535 ///
536 /// These are subtypes of `func` and supertypes of `nofunc`.
537 ConcreteFunc(FuncType),
538 /// The abstract `nofunc` heap type represents the null function reference.
539 ///
540 /// This is the bottom type for the function references type hierarchy, and
541 /// therefore `nofunc` is a subtype of all function reference types.
542 NoFunc,
543
544 /// The abstract `any` heap type represents all internal Wasm data.
545 ///
546 /// This is the top type of the internal type hierarchy, and is therefore a
547 /// supertype of all internal types (such as `eq`, `i31`, `struct`s, and
548 /// `array`s).
549 Any,
550 /// The abstract `eq` heap type represenets all internal Wasm references
551 /// that can be compared for equality.
552 ///
553 /// This is a subtype of `any` and a supertype of `i31`, `array`, `struct`,
554 /// and `none` heap types.
555 Eq,
556 /// The `i31` heap type represents unboxed 31-bit integers.
557 ///
558 /// This is a subtype of `any` and `eq`, and a supertype of `none`.
559 I31,
560 /// The abstract `array` heap type represents a reference to any kind of
561 /// array.
562 ///
563 /// This is a subtype of `any` and `eq`, and a supertype of all concrete
564 /// array types, as well as a supertype of the abstract `none` heap type.
565 Array,
566 /// A reference to an array of a specific, concrete type.
567 ///
568 /// These are subtypes of the `array` heap type (therefore also a subtype of
569 /// `any` and `eq`) and supertypes of the `none` heap type.
570 ConcreteArray(ArrayType),
571 /// The abstract `struct` heap type represents a reference to any kind of
572 /// struct.
573 ///
574 /// This is a subtype of `any` and `eq`, and a supertype of all concrete
575 /// struct types, as well as a supertype of the abstract `none` heap type.
576 Struct,
577 /// A reference to an struct of a specific, concrete type.
578 ///
579 /// These are subtypes of the `struct` heap type (therefore also a subtype
580 /// of `any` and `eq`) and supertypes of the `none` heap type.
581 ConcreteStruct(StructType),
582 /// The abstract `none` heap type represents the null internal reference.
583 ///
584 /// This is the bottom type for the internal type hierarchy, and therefore
585 /// `none` is a subtype of internal types.
586 None,
587
588 /// The abstract `exn` heap type represents exception references.
589 ///
590 /// This is the top type for the exception type hierarchy, and therefore is
591 /// the common supertype of all exception reference types.
592 Exn,
593 /// The abstract `noexn` heap type represents the null exception reference.
594 ///
595 /// This is the bottom type for the exception type hierarchy, and therefore
596 /// is the common subtype of all exception reference types.
597 NoExn,
598
599 /// The abstract `cont` heap type represents continuation references.
600 ///
601 /// This is the top type for the continuation type hierarchy, and therefore is
602 /// the common supertype of all continuation reference types.
603 Cont,
604 /// The abstract `nocont` heap type represents the null continuation reference.
605 ///
606 /// This is the bottom type for the continuation type hierarchy, and therefore
607 /// is the common subtype of all continuation reference types.
608 NoCont,
609}
610
611impl Display for HeapType {
612 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
613 if self.shared {
614 f.write_str("shared ")?;
615 }
616 match &self.inner {
617 HeapTypeInner::Extern => write!(f, "extern"),
618 HeapTypeInner::NoExtern => write!(f, "noextern"),
619 HeapTypeInner::Func => write!(f, "func"),
620 HeapTypeInner::NoFunc => write!(f, "nofunc"),
621 HeapTypeInner::Any => write!(f, "any"),
622 HeapTypeInner::Eq => write!(f, "eq"),
623 HeapTypeInner::I31 => write!(f, "i31"),
624 HeapTypeInner::Array => write!(f, "array"),
625 HeapTypeInner::Struct => write!(f, "struct"),
626 HeapTypeInner::None => write!(f, "none"),
627 HeapTypeInner::ConcreteFunc(ty) => write!(f, "(concrete func {:?})", ty.type_index()),
628 HeapTypeInner::ConcreteArray(ty) => write!(f, "(concrete array {:?})", ty.type_index()),
629 HeapTypeInner::ConcreteStruct(ty) => {
630 write!(f, "(concrete struct {:?})", ty.type_index())
631 }
632 HeapTypeInner::Exn => write!(f, "exn"),
633 HeapTypeInner::NoExn => write!(f, "noexn"),
634 HeapTypeInner::Cont => write!(f, "cont"),
635 HeapTypeInner::NoCont => write!(f, "nocont"),
636 }
637 }
638}
639
640impl HeapType {
641 pub const FUNC: Self = HeapType {
642 shared: false,
643 inner: HeapTypeInner::Func,
644 };
645 pub const NOFUNC: Self = HeapType {
646 shared: false,
647 inner: HeapTypeInner::NoFunc,
648 };
649 pub const EXTERN: Self = HeapType {
650 shared: false,
651 inner: HeapTypeInner::Extern,
652 };
653 pub const NOEXTERN: Self = HeapType {
654 shared: false,
655 inner: HeapTypeInner::NoExtern,
656 };
657 pub const ANY: Self = HeapType {
658 shared: false,
659 inner: HeapTypeInner::Any,
660 };
661 pub const EQ: Self = HeapType {
662 shared: false,
663 inner: HeapTypeInner::Eq,
664 };
665 pub const I31: Self = HeapType {
666 shared: false,
667 inner: HeapTypeInner::I31,
668 };
669 pub const ARRAY: Self = HeapType {
670 shared: false,
671 inner: HeapTypeInner::Array,
672 };
673 pub const STRUCT: Self = HeapType {
674 shared: false,
675 inner: HeapTypeInner::Struct,
676 };
677 pub const NONE: Self = HeapType {
678 shared: false,
679 inner: HeapTypeInner::None,
680 };
681 pub const EXN: Self = HeapType {
682 shared: false,
683 inner: HeapTypeInner::Exn,
684 };
685 pub const NOEXN: Self = HeapType {
686 shared: false,
687 inner: HeapTypeInner::NoExn,
688 };
689 pub const CONT: Self = HeapType {
690 shared: false,
691 inner: HeapTypeInner::Cont,
692 };
693 pub const NOCONT: Self = HeapType {
694 shared: false,
695 inner: HeapTypeInner::NoCont,
696 };
697 pub const fn concrete_func(f: FuncType) -> HeapType {
698 HeapType {
699 shared: false,
700 inner: HeapTypeInner::ConcreteFunc(f),
701 }
702 }
703
704 /// Is this the abstract `extern` heap type?
705 pub fn is_extern(&self) -> bool {
706 matches!(self.inner, HeapTypeInner::Extern)
707 }
708
709 /// Is this the abstract `func` heap type?
710 pub fn is_func(&self) -> bool {
711 matches!(self.inner, HeapTypeInner::Func)
712 }
713
714 /// Is this the abstract `nofunc` heap type?
715 pub fn is_no_func(&self) -> bool {
716 matches!(self.inner, HeapTypeInner::NoFunc)
717 }
718
719 /// Is this the abstract `any` heap type?
720 pub fn is_any(&self) -> bool {
721 matches!(self.inner, HeapTypeInner::Any)
722 }
723
724 /// Is this the abstract `i31` heap type?
725 pub fn is_i31(&self) -> bool {
726 matches!(self.inner, HeapTypeInner::I31)
727 }
728
729 /// Is this the abstract `none` heap type?
730 pub fn is_none(&self) -> bool {
731 matches!(self.inner, HeapTypeInner::None)
732 }
733
734 /// Is this an abstract type?
735 ///
736 /// Types that are not abstract are concrete, user-defined types.
737 pub fn is_abstract(&self) -> bool {
738 !self.is_concrete()
739 }
740
741 /// Is this a concrete, user-defined heap type?
742 ///
743 /// Types that are not concrete, user-defined types are abstract types.
744 #[inline]
745 pub fn is_concrete(&self) -> bool {
746 matches!(
747 self.inner,
748 HeapTypeInner::ConcreteFunc(_)
749 | HeapTypeInner::ConcreteArray(_)
750 | HeapTypeInner::ConcreteStruct(_)
751 )
752 }
753
754 /// Is this a concrete, user-defined function type?
755 pub fn is_concrete_func(&self) -> bool {
756 matches!(self.inner, HeapTypeInner::ConcreteFunc(_))
757 }
758
759 /// Get the underlying concrete, user-defined function type, if any.
760 ///
761 /// Returns `None` if this is not a concrete function type.
762 pub fn as_concrete_func(&self) -> Option<&FuncType> {
763 match &self.inner {
764 HeapTypeInner::ConcreteFunc(f) => Some(f),
765 _ => None,
766 }
767 }
768
769 /// Get the underlying concrete, user-defined type, panicking if this is not
770 /// a concrete function type.
771 pub fn unwrap_concrete_func(&self) -> &FuncType {
772 self.as_concrete_func().unwrap()
773 }
774
775 /// Is this a concrete, user-defined array type?
776 pub fn is_concrete_array(&self) -> bool {
777 matches!(self.inner, HeapTypeInner::ConcreteArray(_))
778 }
779
780 /// Get the underlying concrete, user-defined array type, if any.
781 ///
782 /// Returns `None` for if this is not a concrete array type.
783 pub fn as_concrete_array(&self) -> Option<&ArrayType> {
784 match &self.inner {
785 HeapTypeInner::ConcreteArray(f) => Some(f),
786 _ => None,
787 }
788 }
789
790 /// Get the underlying concrete, user-defined type, panicking if this is not
791 /// a concrete array type.
792 pub fn unwrap_concrete_array(&self) -> &ArrayType {
793 self.as_concrete_array().unwrap()
794 }
795
796 /// Is this a concrete, user-defined struct type?
797 pub fn is_concrete_struct(&self) -> bool {
798 matches!(self.inner, HeapTypeInner::ConcreteStruct(_))
799 }
800
801 /// Get the underlying concrete, user-defined struct type, if any.
802 ///
803 /// Returns `None` for if this is not a concrete struct type.
804 pub fn as_concrete_struct(&self) -> Option<&StructType> {
805 match &self.inner {
806 HeapTypeInner::ConcreteStruct(f) => Some(f),
807 _ => None,
808 }
809 }
810
811 /// Get the underlying concrete, user-defined type, panicking if this is not
812 /// a concrete struct type.
813 pub fn unwrap_concrete_struct(&self) -> &StructType {
814 self.as_concrete_struct().unwrap()
815 }
816
817 pub fn is_shared(&self) -> bool {
818 self.shared
819 }
820
821 /// Get the top type of this heap type's type hierarchy.
822 ///
823 /// The returned heap type is a supertype of all types in this heap type's
824 /// type hierarchy.
825 pub fn top(&self) -> HeapType {
826 let inner = match self.inner {
827 HeapTypeInner::Func | HeapTypeInner::ConcreteFunc(_) | HeapTypeInner::NoFunc => {
828 HeapTypeInner::Func
829 }
830
831 HeapTypeInner::Extern | HeapTypeInner::NoExtern => HeapTypeInner::Extern,
832
833 HeapTypeInner::Any
834 | HeapTypeInner::Eq
835 | HeapTypeInner::I31
836 | HeapTypeInner::Array
837 | HeapTypeInner::ConcreteArray(_)
838 | HeapTypeInner::Struct
839 | HeapTypeInner::ConcreteStruct(_)
840 | HeapTypeInner::None => HeapTypeInner::Any,
841
842 HeapTypeInner::Exn | HeapTypeInner::NoExn => HeapTypeInner::Exn,
843 HeapTypeInner::Cont | HeapTypeInner::NoCont => HeapTypeInner::Cont,
844 };
845
846 HeapType {
847 shared: self.shared,
848 inner,
849 }
850 }
851
852 /// Is this the top type within its type hierarchy?
853 #[inline]
854 pub fn is_top(&self) -> bool {
855 matches!(
856 self.inner,
857 HeapTypeInner::Any
858 | HeapTypeInner::Extern
859 | HeapTypeInner::Func
860 | HeapTypeInner::Exn
861 | HeapTypeInner::Cont
862 )
863 }
864
865 /// Get the bottom type of this heap type's type hierarchy.
866 ///
867 /// The returned heap type is a subtype of all types in this heap type's
868 /// type hierarchy.
869 pub fn bottom(&self) -> HeapType {
870 let inner = match self.inner {
871 HeapTypeInner::Extern | HeapTypeInner::NoExtern => HeapTypeInner::NoExtern,
872
873 HeapTypeInner::Func | HeapTypeInner::ConcreteFunc(_) | HeapTypeInner::NoFunc => {
874 HeapTypeInner::NoFunc
875 }
876
877 HeapTypeInner::Any
878 | HeapTypeInner::Eq
879 | HeapTypeInner::I31
880 | HeapTypeInner::Array
881 | HeapTypeInner::ConcreteArray(_)
882 | HeapTypeInner::Struct
883 | HeapTypeInner::ConcreteStruct(_)
884 | HeapTypeInner::None => HeapTypeInner::None,
885
886 HeapTypeInner::Exn | HeapTypeInner::NoExn => HeapTypeInner::NoExn,
887 HeapTypeInner::Cont | HeapTypeInner::NoCont => HeapTypeInner::NoCont,
888 };
889
890 HeapType {
891 shared: self.shared,
892 inner,
893 }
894 }
895
896 /// Is this the bottom type within its type hierarchy?
897 #[inline]
898 pub fn is_bottom(&self) -> bool {
899 matches!(
900 self.inner,
901 HeapTypeInner::None
902 | HeapTypeInner::NoExtern
903 | HeapTypeInner::NoFunc
904 | HeapTypeInner::NoExn
905 | HeapTypeInner::NoCont
906 )
907 }
908
909 /// Does this heap type match the other heap type?
910 ///
911 /// That is, is this heap type a subtype of the other?
912 ///
913 /// # Panics
914 ///
915 /// Panics if either type is associated with a different engine from the
916 /// other.
917 pub fn matches(&self, other: &HeapType) -> bool {
918 match (&self.inner, &other.inner) {
919 (HeapTypeInner::Extern, HeapTypeInner::Extern) => true,
920 (HeapTypeInner::Extern, _) => false,
921
922 (HeapTypeInner::NoExtern, HeapTypeInner::NoExtern | HeapTypeInner::Extern) => true,
923 (HeapTypeInner::NoExtern, _) => false,
924
925 (
926 HeapTypeInner::NoFunc,
927 HeapTypeInner::NoFunc | HeapTypeInner::ConcreteFunc(_) | HeapTypeInner::Func,
928 ) => true,
929 (HeapTypeInner::NoFunc, _) => false,
930
931 (HeapTypeInner::ConcreteFunc(_), HeapTypeInner::Func) => true,
932 (HeapTypeInner::ConcreteFunc(a), HeapTypeInner::ConcreteFunc(b)) => {
933 assert!(a.comes_from_same_engine(b.engine()));
934 a.engine()
935 .type_registry()
936 .is_subtype(a.type_index(), b.type_index())
937 }
938 (HeapTypeInner::ConcreteFunc(_), _) => false,
939
940 (HeapTypeInner::Func, HeapTypeInner::Func) => true,
941 (HeapTypeInner::Func, _) => false,
942
943 (
944 HeapTypeInner::None,
945 HeapTypeInner::None
946 | HeapTypeInner::ConcreteArray(_)
947 | HeapTypeInner::Array
948 | HeapTypeInner::ConcreteStruct(_)
949 | HeapTypeInner::Struct
950 | HeapTypeInner::I31
951 | HeapTypeInner::Eq
952 | HeapTypeInner::Any,
953 ) => true,
954 (HeapTypeInner::None, _) => false,
955
956 (
957 HeapTypeInner::ConcreteArray(_),
958 HeapTypeInner::Array | HeapTypeInner::Eq | HeapTypeInner::Any,
959 ) => true,
960 (HeapTypeInner::ConcreteArray(a), HeapTypeInner::ConcreteArray(b)) => {
961 assert!(a.comes_from_same_engine(b.engine()));
962 a.engine()
963 .type_registry()
964 .is_subtype(a.type_index(), b.type_index())
965 }
966 (HeapTypeInner::ConcreteArray(_), _) => false,
967
968 (
969 HeapTypeInner::Array,
970 HeapTypeInner::Array | HeapTypeInner::Eq | HeapTypeInner::Any,
971 ) => true,
972 (HeapTypeInner::Array, _) => false,
973
974 (
975 HeapTypeInner::ConcreteStruct(_),
976 HeapTypeInner::Struct | HeapTypeInner::Eq | HeapTypeInner::Any,
977 ) => true,
978 (HeapTypeInner::ConcreteStruct(a), HeapTypeInner::ConcreteStruct(b)) => {
979 assert!(a.comes_from_same_engine(b.engine()));
980 a.engine()
981 .type_registry()
982 .is_subtype(a.type_index(), b.type_index())
983 }
984 (HeapTypeInner::ConcreteStruct(_), _) => false,
985
986 (
987 HeapTypeInner::Struct,
988 HeapTypeInner::Struct | HeapTypeInner::Eq | HeapTypeInner::Any,
989 ) => true,
990 (HeapTypeInner::Struct, _) => false,
991
992 (HeapTypeInner::I31, HeapTypeInner::I31 | HeapTypeInner::Eq | HeapTypeInner::Any) => {
993 true
994 }
995 (HeapTypeInner::I31, _) => false,
996
997 (HeapTypeInner::Eq, HeapTypeInner::Eq | HeapTypeInner::Any) => true,
998 (HeapTypeInner::Eq, _) => false,
999
1000 (HeapTypeInner::Any, HeapTypeInner::Any) => true,
1001 (HeapTypeInner::Any, _) => false,
1002
1003 (HeapTypeInner::Exn, HeapTypeInner::Exn) => true,
1004 (HeapTypeInner::Exn, _) => false,
1005 (HeapTypeInner::NoExn, HeapTypeInner::NoExn | HeapTypeInner::Exn) => true,
1006 (HeapTypeInner::NoExn, _) => false,
1007
1008 (HeapTypeInner::Cont, HeapTypeInner::Cont) => true,
1009 (HeapTypeInner::Cont, _) => false,
1010 // (
1011 // HeapTypeInner::ConcreteCont(_),
1012 // HeapTypeInner::Cont,
1013 // ) => true,
1014 // (HeapTypeInner::ConcreteCont(_a), HeapTypeInner::ConcreteCont(_b)) => {
1015 // // assert!(a.comes_from_same_engine(b.engine()));
1016 // // a.engine()
1017 // // .type_registry()
1018 // // .is_subtype(a.type_index(), b.type_index())
1019 // todo!()
1020 // }
1021 // (HeapTypeInner::ConcreteCont(_), _) => false,
1022 (HeapTypeInner::NoCont, HeapTypeInner::NoCont | HeapTypeInner::Cont) => true,
1023 (HeapTypeInner::NoCont, _) => false,
1024 }
1025 }
1026
1027 /// Is heap type `a` precisely equal to heap type `b`?
1028 ///
1029 /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
1030 /// are not exactly the same heap type.
1031 ///
1032 /// # Panics
1033 ///
1034 /// Panics if either type is associated with a different engine from the
1035 /// other.
1036 pub fn eq(a: &HeapType, b: &HeapType) -> bool {
1037 a.matches(b) && b.matches(a)
1038 }
1039
1040 pub(crate) fn ensure_matches(&self, engine: &Engine, other: &HeapType) -> crate::Result<()> {
1041 if !self.comes_from_same_engine(engine) || !other.comes_from_same_engine(engine) {
1042 bail!("type used with wrong engine");
1043 }
1044 if self.matches(other) {
1045 Ok(())
1046 } else {
1047 bail!("type mismatch: expected {other}, found {self}");
1048 }
1049 }
1050
1051 pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
1052 match &self.inner {
1053 HeapTypeInner::Extern
1054 | HeapTypeInner::NoExtern
1055 | HeapTypeInner::Func
1056 | HeapTypeInner::NoFunc
1057 | HeapTypeInner::Any
1058 | HeapTypeInner::Eq
1059 | HeapTypeInner::I31
1060 | HeapTypeInner::Array
1061 | HeapTypeInner::Struct
1062 | HeapTypeInner::None
1063 | HeapTypeInner::Exn
1064 | HeapTypeInner::NoExn
1065 | HeapTypeInner::Cont
1066 | HeapTypeInner::NoCont => true,
1067 HeapTypeInner::ConcreteFunc(ty) => ty.comes_from_same_engine(engine),
1068 HeapTypeInner::ConcreteArray(ty) => ty.comes_from_same_engine(engine),
1069 HeapTypeInner::ConcreteStruct(ty) => ty.comes_from_same_engine(engine),
1070 }
1071 }
1072
1073 pub(crate) fn as_registered_type(&self) -> Option<&RegisteredType> {
1074 match &self.inner {
1075 HeapTypeInner::ConcreteFunc(f) => Some(&f.registered_type),
1076 HeapTypeInner::ConcreteArray(a) => Some(&a.registered_type),
1077 HeapTypeInner::ConcreteStruct(a) => Some(&a.registered_type),
1078
1079 HeapTypeInner::Extern
1080 | HeapTypeInner::NoExtern
1081 | HeapTypeInner::Func
1082 | HeapTypeInner::NoFunc
1083 | HeapTypeInner::Any
1084 | HeapTypeInner::Eq
1085 | HeapTypeInner::I31
1086 | HeapTypeInner::Array
1087 | HeapTypeInner::Struct
1088 | HeapTypeInner::None
1089 | HeapTypeInner::Exn
1090 | HeapTypeInner::NoExn
1091 | HeapTypeInner::Cont
1092 | HeapTypeInner::NoCont => None,
1093 }
1094 }
1095
1096 pub(crate) fn to_wasm_type(&self) -> WasmHeapType {
1097 let inner = match &self.inner {
1098 HeapTypeInner::Extern => WasmHeapTypeInner::Extern,
1099 HeapTypeInner::NoExtern => WasmHeapTypeInner::NoExtern,
1100 HeapTypeInner::Func => WasmHeapTypeInner::Func,
1101 HeapTypeInner::NoFunc => WasmHeapTypeInner::NoFunc,
1102 HeapTypeInner::Any => WasmHeapTypeInner::Any,
1103 HeapTypeInner::Eq => WasmHeapTypeInner::Eq,
1104 HeapTypeInner::I31 => WasmHeapTypeInner::I31,
1105 HeapTypeInner::Array => WasmHeapTypeInner::Array,
1106 HeapTypeInner::Struct => WasmHeapTypeInner::Struct,
1107 HeapTypeInner::None => WasmHeapTypeInner::None,
1108 HeapTypeInner::ConcreteFunc(f) => {
1109 WasmHeapTypeInner::ConcreteFunc(CanonicalizedTypeIndex::Engine(f.type_index()))
1110 }
1111 HeapTypeInner::ConcreteArray(a) => {
1112 WasmHeapTypeInner::ConcreteArray(CanonicalizedTypeIndex::Engine(a.type_index()))
1113 }
1114 HeapTypeInner::ConcreteStruct(a) => {
1115 WasmHeapTypeInner::ConcreteStruct(CanonicalizedTypeIndex::Engine(a.type_index()))
1116 }
1117 HeapTypeInner::Exn => WasmHeapTypeInner::Exn,
1118 HeapTypeInner::NoExn => WasmHeapTypeInner::NoExn,
1119 HeapTypeInner::Cont => WasmHeapTypeInner::Cont,
1120 HeapTypeInner::NoCont => WasmHeapTypeInner::NoCont,
1121 };
1122 WasmHeapType {
1123 shared: self.shared,
1124 inner,
1125 }
1126 }
1127
1128 pub(crate) fn from_wasm_type(engine: &Engine, ty: &WasmHeapType) -> HeapType {
1129 let inner = match ty.inner {
1130 WasmHeapTypeInner::Extern => HeapTypeInner::Extern,
1131 WasmHeapTypeInner::NoExtern => HeapTypeInner::NoExtern,
1132 WasmHeapTypeInner::Func => HeapTypeInner::Func,
1133 WasmHeapTypeInner::NoFunc => HeapTypeInner::NoFunc,
1134 WasmHeapTypeInner::Any => HeapTypeInner::Any,
1135 WasmHeapTypeInner::Eq => HeapTypeInner::Eq,
1136 WasmHeapTypeInner::I31 => HeapTypeInner::I31,
1137 WasmHeapTypeInner::Array => HeapTypeInner::Array,
1138 WasmHeapTypeInner::Struct => HeapTypeInner::Struct,
1139 WasmHeapTypeInner::None => HeapTypeInner::None,
1140 WasmHeapTypeInner::ConcreteFunc(CanonicalizedTypeIndex::Engine(idx)) => {
1141 HeapTypeInner::ConcreteFunc(FuncType::from_shared_type_index(engine, idx))
1142 }
1143 WasmHeapTypeInner::ConcreteArray(CanonicalizedTypeIndex::Engine(idx)) => {
1144 HeapTypeInner::ConcreteArray(ArrayType::from_shared_type_index(engine, idx))
1145 }
1146 WasmHeapTypeInner::ConcreteStruct(CanonicalizedTypeIndex::Engine(idx)) => {
1147 HeapTypeInner::ConcreteStruct(StructType::from_shared_type_index(engine, idx))
1148 }
1149
1150 WasmHeapTypeInner::ConcreteFunc(
1151 CanonicalizedTypeIndex::Module(_) | CanonicalizedTypeIndex::RecGroup(_),
1152 )
1153 | WasmHeapTypeInner::ConcreteArray(
1154 CanonicalizedTypeIndex::Module(_) | CanonicalizedTypeIndex::RecGroup(_),
1155 )
1156 | WasmHeapTypeInner::ConcreteStruct(
1157 CanonicalizedTypeIndex::Module(_) | CanonicalizedTypeIndex::RecGroup(_),
1158 ) => {
1159 panic!(
1160 "HeapTypeInner::from_wasm_type on non-canonicalized-for-runtime-usage heap type"
1161 )
1162 }
1163
1164 WasmHeapTypeInner::Exn => HeapTypeInner::Exn,
1165 WasmHeapTypeInner::NoExn => HeapTypeInner::NoExn,
1166
1167 WasmHeapTypeInner::Cont => HeapTypeInner::Cont,
1168 WasmHeapTypeInner::ConcreteCont(_) => todo!(),
1169 WasmHeapTypeInner::NoCont => HeapTypeInner::NoCont,
1170 };
1171 HeapType {
1172 inner,
1173 shared: ty.shared,
1174 }
1175 }
1176}
1177
1178/// A list of all possible types which can be externally referenced from a
1179/// WebAssembly module.
1180///
1181/// This list can be found in [`ImportType`] or [`ExportType`], so these types
1182/// can either be imported or exported.
1183#[derive(Debug, Clone)]
1184pub enum ExternType {
1185 /// This external type is the type of a WebAssembly function.
1186 Func(FuncType),
1187 /// This external type is the type of a WebAssembly global.
1188 Global(GlobalType),
1189 /// This external type is the type of a WebAssembly table.
1190 Table(TableType),
1191 /// This external type is the type of a WebAssembly memory.
1192 Memory(MemoryType),
1193 /// This external type is the type of a WebAssembly tag.
1194 Tag(TagType),
1195}
1196
1197/// The storage type of a `struct` field or `array` element.
1198///
1199/// This is either a packed 8- or -16 bit integer, or else it is some unpacked
1200/// Wasm value type.
1201#[derive(Clone, Hash)]
1202pub enum StorageType {
1203 /// `i8`, an 8-bit integer.
1204 I8,
1205 /// `i16`, a 16-bit integer.
1206 I16,
1207 /// A value type.
1208 ValType(ValType),
1209}
1210impl fmt::Display for StorageType {
1211 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1212 match self {
1213 StorageType::I8 => write!(f, "i8"),
1214 StorageType::I16 => write!(f, "i16"),
1215 StorageType::ValType(ty) => fmt::Display::fmt(ty, f),
1216 }
1217 }
1218}
1219
1220impl StorageType {
1221 pub(super) fn from_wasm_type(engine: &Engine, ty: &WasmStorageType) -> Self {
1222 match ty {
1223 WasmStorageType::I8 => Self::I8,
1224 WasmStorageType::I16 => Self::I16,
1225 WasmStorageType::Val(ty) => Self::ValType(ValType::from_wasm_type(engine, ty)),
1226 }
1227 }
1228}
1229
1230/// The type of a `struct` field or an `array`'s elements.
1231///
1232/// This is a pair of both the field's storage type and its mutability
1233/// (i.e. whether the field can be updated or not).
1234#[derive(Clone, Hash)]
1235pub struct FieldType {
1236 mutability: Mutability,
1237 element_type: StorageType,
1238}
1239impl fmt::Display for FieldType {
1240 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1241 if self.mutability.is_var() {
1242 write!(f, "(mut {})", self.element_type)
1243 } else {
1244 fmt::Display::fmt(&self.element_type, f)
1245 }
1246 }
1247}
1248
1249impl FieldType {
1250 /// Construct a new field type from the given parts.
1251 #[inline]
1252 pub fn new(mutability: Mutability, element_type: StorageType) -> Self {
1253 Self {
1254 mutability,
1255 element_type,
1256 }
1257 }
1258
1259 /// Get whether or not this field type is mutable.
1260 #[inline]
1261 pub fn mutability(&self) -> Mutability {
1262 self.mutability
1263 }
1264
1265 /// Get this field type's storage type.
1266 #[inline]
1267 pub fn element_type(&self) -> &StorageType {
1268 &self.element_type
1269 }
1270
1271 pub(super) fn from_wasm_type(engine: &Engine, ty: &WasmFieldType) -> Self {
1272 Self {
1273 mutability: if ty.mutable {
1274 Mutability::Var
1275 } else {
1276 Mutability::Const
1277 },
1278 element_type: StorageType::from_wasm_type(engine, &ty.element_type),
1279 }
1280 }
1281}
1282
1283/// The type of a WebAssembly struct.
1284///
1285/// WebAssembly structs are a static, fixed-length, ordered sequence of
1286/// fields. Fields are named by index, not an identifier. Each field is mutable
1287/// or constant and stores unpacked [`Val`][crate::wasm::Val]s or packed 8-/16-bit
1288/// integers.
1289///
1290/// # Subtyping and Equality
1291///
1292/// `StructType` does not implement `Eq`, because reference types have a
1293/// subtyping relationship, and so 99.99% of the time you actually want to check
1294/// whether one type matches (i.e. is a subtype of) another type. You can use
1295/// the [`StructType::matches`] method to perform these types of checks. If,
1296/// however, you are in that 0.01% scenario where you need to check precise
1297/// equality between types, you can use the [`StructType::eq`] method.
1298//
1299// TODO: Once we have struct values, update above docs with a reference to the
1300// future `Struct::matches_ty` method
1301#[derive(Debug, Clone, Hash)]
1302pub struct StructType {
1303 registered_type: RegisteredType,
1304}
1305impl fmt::Display for StructType {
1306 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1307 write!(f, "(struct")?;
1308 for field in self.fields() {
1309 write!(f, " (field {field})")?;
1310 }
1311 write!(f, ")")?;
1312 Ok(())
1313 }
1314}
1315
1316impl StructType {
1317 pub fn fields(&self) -> impl ExactSizeIterator<Item = FieldType> {
1318 let engine = self.engine();
1319
1320 self.registered_type
1321 .unwrap_struct()
1322 .fields
1323 .iter()
1324 .map(|wasm_ty| FieldType::from_wasm_type(engine, wasm_ty))
1325 }
1326
1327 pub(super) fn engine(&self) -> &Engine {
1328 self.registered_type.engine()
1329 }
1330 pub(super) fn comes_from_same_engine(&self, other: &Engine) -> bool {
1331 Engine::same(self.engine(), other)
1332 }
1333 pub(crate) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> StructType {
1334 let ty = engine.type_registry().root(engine, index).expect(
1335 "VMSharedTypeIndex is not registered in the Engine! Wrong \
1336 engine? Didn't root the index somewhere?",
1337 );
1338 Self::from_registered_type(ty)
1339 }
1340 pub(crate) fn from_registered_type(registered_type: RegisteredType) -> Self {
1341 debug_assert!(registered_type.is_struct());
1342 Self { registered_type }
1343 }
1344 pub(crate) fn type_index(&self) -> VMSharedTypeIndex {
1345 self.registered_type.index()
1346 }
1347}
1348
1349/// The type of a WebAssembly array.
1350///
1351/// WebAssembly arrays are dynamically-sized, but not resizable. They contain
1352/// either unpacked [`Val`][crate::Val]s or packed 8-/16-bit integers.
1353///
1354/// # Subtyping and Equality
1355///
1356/// `ArrayType` does not implement `Eq`, because reference types have a
1357/// subtyping relationship, and so 99.99% of the time you actually want to check
1358/// whether one type matches (i.e. is a subtype of) another type. You can use
1359/// the [`ArrayType::matches`] method to perform these types of checks. If,
1360/// however, you are in that 0.01% scenario where you need to check precise
1361/// equality between types, you can use the [`ArrayType::eq`] method.
1362//
1363// TODO: Once we have array values, update above docs with a reference to the
1364// future `Array::matches_ty` method
1365#[derive(Debug, Clone, Hash)]
1366pub struct ArrayType {
1367 registered_type: RegisteredType,
1368}
1369impl fmt::Display for ArrayType {
1370 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1371 let field_ty = self.field_type();
1372 write!(f, "(array (field {field_ty}))")?;
1373 Ok(())
1374 }
1375}
1376
1377impl ArrayType {
1378 pub fn field_type(&self) -> FieldType {
1379 todo!()
1380 }
1381 pub(crate) fn type_index(&self) -> VMSharedTypeIndex {
1382 self.registered_type.index()
1383 }
1384 pub(super) fn engine(&self) -> &Engine {
1385 self.registered_type.engine()
1386 }
1387 pub(super) fn comes_from_same_engine(&self, other: &Engine) -> bool {
1388 Engine::same(self.engine(), other)
1389 }
1390 pub(crate) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> ArrayType {
1391 let ty = engine.type_registry().root(engine, index).expect(
1392 "VMSharedTypeIndex is not registered in the Engine! Wrong \
1393 engine? Didn't root the index somewhere?",
1394 );
1395 Self::from_registered_type(ty)
1396 }
1397 pub(crate) fn from_registered_type(registered_type: RegisteredType) -> Self {
1398 debug_assert!(registered_type.is_array());
1399 Self { registered_type }
1400 }
1401}
1402
1403/// The type of a WebAssembly function.
1404///
1405/// WebAssembly functions can have 0 or more parameters and results.
1406///
1407/// # Subtyping and Equality
1408///
1409/// `FuncType` does not implement `Eq`, because reference types have a subtyping
1410/// relationship, and so 99.99% of the time you actually want to check whether
1411/// one type matches (i.e. is a subtype of) another type. You can use the
1412/// [`FuncType::matches`] and [`Func::matches_ty`][crate::Func::matches_ty]
1413/// methods to perform these types of checks. If, however, you are in that 0.01%
1414/// scenario where you need to check precise equality between types, you can use
1415/// the [`FuncType::eq`] method.
1416#[derive(Debug, Clone, Hash)]
1417pub struct FuncType {
1418 registered_type: RegisteredType,
1419}
1420impl Display for FuncType {
1421 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1422 write!(f, "(type (func")?;
1423 if self.params().len() > 0 {
1424 write!(f, " (param")?;
1425 for p in self.params() {
1426 write!(f, " {p}")?;
1427 }
1428 write!(f, ")")?;
1429 }
1430 if self.results().len() > 0 {
1431 write!(f, " (result")?;
1432 for r in self.results() {
1433 write!(f, " {r}")?;
1434 }
1435 write!(f, ")")?;
1436 }
1437 write!(f, "))")
1438 }
1439}
1440
1441impl FuncType {
1442 /// Creates a new function type from the given parameters and results.
1443 ///
1444 /// The function type returned will represent a function which takes
1445 /// `params` as arguments and returns `results` when it is finished.
1446 ///
1447 /// The resulting function type will be final and without a supertype.
1448 ///
1449 /// # Panics
1450 ///
1451 /// Panics if any parameter or value type is not associated with the given
1452 /// engine.
1453 pub fn new(
1454 engine: &Engine,
1455 params: impl IntoIterator<Item = ValType>,
1456 results: impl IntoIterator<Item = ValType>,
1457 ) -> Self {
1458 Self::with_finality_and_supertype(engine, Finality::Final, None, params, results)
1459 .expect("cannot fail without a supertype")
1460 }
1461
1462 /// Create a new function type with the given finality, supertype, parameter
1463 /// types, and result types.
1464 ///
1465 /// Returns an error if the supertype is final, or if this function type
1466 /// does not match the supertype.
1467 ///
1468 /// # Panics
1469 ///
1470 /// Panics if any parameter or value type is not associated with the given
1471 /// engine.
1472 pub fn with_finality_and_supertype(
1473 engine: &Engine,
1474 finality: Finality,
1475 supertype: Option<&Self>,
1476 params: impl IntoIterator<Item = ValType>,
1477 results: impl IntoIterator<Item = ValType>,
1478 ) -> crate::Result<Self> {
1479 let params = params.into_iter();
1480 let results = results.into_iter();
1481
1482 let mut wasm_params = Vec::with_capacity({
1483 let size_hint = params.size_hint();
1484 let cap = size_hint.1.unwrap_or(size_hint.0);
1485 // Only reserve space if we have a supertype, as that is the only time
1486 // that this vec is used.
1487 usize::from(supertype.is_some()) * cap
1488 });
1489
1490 let mut wasm_results = Vec::with_capacity({
1491 let size_hint = results.size_hint();
1492 let cap = size_hint.1.unwrap_or(size_hint.0);
1493 // Same as above.
1494 usize::from(supertype.is_some()) * cap
1495 });
1496
1497 // Keep any of our parameters' and results' `RegisteredType`s alive
1498 // across `Self::from_wasm_func_type`. If one of our given `ValType`s is
1499 // the only thing keeping a type in the registry, we don't want to
1500 // unregister it when we convert the `ValType` into a `WasmValType` just
1501 // before we register our new `WasmFuncType` that will reference it.
1502 let mut registrations = smallvec::SmallVec::<[_; 4]>::new();
1503
1504 let mut to_wasm_type = |ty: ValType, vec: &mut Vec<_>| {
1505 assert!(ty.comes_from_same_engine(engine));
1506
1507 if supertype.is_some() {
1508 vec.push(ty.clone());
1509 }
1510
1511 if let Some(r) = ty.as_ref()
1512 && let Some(r) = r.heap_type().as_registered_type()
1513 {
1514 registrations.push(r.clone());
1515 }
1516
1517 ty.to_wasm_type()
1518 };
1519
1520 let wasm_func_ty = WasmFuncType {
1521 params: params.map(|p| to_wasm_type(p, &mut wasm_params)).collect(),
1522 results: results
1523 .map(|r| to_wasm_type(r, &mut wasm_results))
1524 .collect(),
1525 };
1526
1527 if let Some(supertype) = supertype {
1528 assert!(supertype.comes_from_same_engine(engine));
1529 ensure!(
1530 supertype.finality().is_non_final(),
1531 "cannot create a subtype of a final supertype"
1532 );
1533 ensure!(
1534 Self::matches_impl(
1535 wasm_params.iter().cloned(),
1536 supertype.params(),
1537 wasm_results.iter().cloned(),
1538 supertype.results()
1539 ),
1540 "function type must match its supertype: found (func{params}{results}), expected \
1541 {supertype}",
1542 params = if wasm_params.is_empty() {
1543 String::new()
1544 } else {
1545 let mut s = " (params".to_string();
1546 for p in &wasm_params {
1547 write!(&mut s, " {p}").unwrap();
1548 }
1549 s.push(')');
1550 s
1551 },
1552 results = if wasm_results.is_empty() {
1553 String::new()
1554 } else {
1555 let mut s = " (results".to_string();
1556 for r in &wasm_results {
1557 write!(&mut s, " {r}").unwrap();
1558 }
1559 s.push(')');
1560 s
1561 },
1562 );
1563 }
1564
1565 Ok(Self::from_wasm_func_type(
1566 engine,
1567 finality.is_final(),
1568 supertype.map(|ty| ty.type_index().into()),
1569 wasm_func_ty,
1570 ))
1571 }
1572
1573 pub fn param(&self, i: usize) -> Option<ValType> {
1574 let engine = self.engine();
1575
1576 self.registered_type
1577 .unwrap_func()
1578 .params
1579 .get(i)
1580 .map(|ty| ValType::from_wasm_type(engine, ty))
1581 }
1582
1583 pub fn params(&self) -> impl ExactSizeIterator<Item = ValType> + '_ {
1584 let engine = self.engine();
1585
1586 self.registered_type
1587 .unwrap_func()
1588 .params
1589 .iter()
1590 .map(|ty| ValType::from_wasm_type(engine, ty))
1591 }
1592
1593 pub fn result(&self, i: usize) -> Option<ValType> {
1594 let engine = self.engine();
1595 self.registered_type
1596 .unwrap_func()
1597 .results
1598 .get(i)
1599 .map(|ty| ValType::from_wasm_type(engine, ty))
1600 }
1601
1602 pub fn results(&self) -> impl ExactSizeIterator<Item = ValType> + '_ {
1603 let engine = self.engine();
1604
1605 self.registered_type
1606 .unwrap_func()
1607 .results
1608 .iter()
1609 .map(|ty| ValType::from_wasm_type(engine, ty))
1610 }
1611
1612 /// Get the finality of this function type.
1613 pub fn finality(&self) -> Finality {
1614 if self.registered_type.is_final {
1615 Finality::Final
1616 } else {
1617 Finality::NonFinal
1618 }
1619 }
1620
1621 /// Get the supertype of this function type, if any.
1622 pub fn supertype(&self) -> Option<Self> {
1623 self.registered_type
1624 .supertype
1625 .map(|ty| Self::from_shared_type_index(self.engine(), ty.unwrap_engine_type_index()))
1626 }
1627
1628 pub(super) fn type_index(&self) -> VMSharedTypeIndex {
1629 self.registered_type.index()
1630 }
1631
1632 pub(super) fn engine(&self) -> &Engine {
1633 self.registered_type.engine()
1634 }
1635
1636 /// Does this function type match the other function type?
1637 ///
1638 /// That is, is this function type a subtype of the other function type?
1639 ///
1640 /// # Panics
1641 ///
1642 /// Panics if either type is associated with a different engine from the
1643 /// other.
1644 pub fn matches(&self, other: &FuncType) -> bool {
1645 assert!(self.comes_from_same_engine(other.engine()));
1646
1647 // Avoid matching on structure for subtyping checks when we have
1648 // precisely the same type.
1649 if self.type_index() == other.type_index() {
1650 return true;
1651 }
1652
1653 Self::matches_impl(
1654 self.params(),
1655 other.params(),
1656 self.results(),
1657 other.results(),
1658 )
1659 }
1660
1661 fn matches_impl(
1662 a_params: impl ExactSizeIterator<Item = ValType>,
1663 b_params: impl ExactSizeIterator<Item = ValType>,
1664 a_results: impl ExactSizeIterator<Item = ValType>,
1665 b_results: impl ExactSizeIterator<Item = ValType>,
1666 ) -> bool {
1667 a_params.len() == b_params.len()
1668 && a_results.len() == b_results.len()
1669 // Params are contravariant and results are covariant. For more
1670 // details and a refresher on variance, read
1671 // https://github.com/bytecodealliance/wasm-tools/blob/f1d89a4/crates/wasmparser/src/readers/core/types/matches.rs#L137-L174
1672 && a_params
1673 .zip(b_params)
1674 .all(|(a, b)| b.matches(&a))
1675 && a_results
1676 .zip(b_results)
1677 .all(|(a, b)| a.matches(&b))
1678 }
1679
1680 pub(super) fn comes_from_same_engine(&self, other: &Engine) -> bool {
1681 Engine::same(self.engine(), other)
1682 }
1683 pub(super) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> FuncType {
1684 let ty = engine.type_registry().root(engine, index).expect(
1685 "VMSharedTypeIndex is not registered in the Engine! Wrong \
1686 engine? Didn't root the index somewhere?",
1687 );
1688 Self::from_registered_type(ty)
1689 }
1690 pub(super) fn from_registered_type(registered_type: RegisteredType) -> Self {
1691 debug_assert!(registered_type.is_func());
1692 Self { registered_type }
1693 }
1694 pub(super) fn into_registered_type(self) -> RegisteredType {
1695 self.registered_type
1696 }
1697
1698 pub(super) fn from_wasm_func_type(
1699 engine: &Engine,
1700 is_final: bool,
1701 supertype: Option<CanonicalizedTypeIndex>,
1702 ty: WasmFuncType,
1703 ) -> Self {
1704 let registered_type = engine.type_registry().register_type(
1705 engine,
1706 WasmSubType {
1707 is_final,
1708 supertype,
1709 composite_type: WasmCompositeType {
1710 shared: false,
1711 inner: WasmCompositeTypeInner::Func(ty),
1712 },
1713 },
1714 );
1715
1716 Self { registered_type }
1717 }
1718}
1719
1720/// A descriptor for a table in a WebAssembly module.
1721///
1722/// Tables are contiguous chunks of a specific element, typically a `funcref` or
1723/// an `externref`. The most common use for tables is a function table through
1724/// which `call_indirect` can invoke other functions.
1725#[derive(Debug, Clone, Hash)]
1726pub struct TableType {
1727 // Keep a `wasmtime::RefType` so that `TableType::element` doesn't need to
1728 // take an `&Engine`.
1729 element: RefType,
1730 ty: Table,
1731}
1732
1733impl TableType {
1734 /// Returns the element value type of this table.
1735 pub fn element(&self) -> &RefType {
1736 &self.element
1737 }
1738
1739 /// Returns minimum number of elements this table must have
1740 pub fn minimum(&self) -> u64 {
1741 self.ty.limits.min
1742 }
1743
1744 /// Returns the optionally-specified maximum number of elements this table
1745 /// can have.
1746 ///
1747 /// If this returns `None` then the table is not limited in size.
1748 pub fn maximum(&self) -> Option<u64> {
1749 self.ty.limits.max
1750 }
1751
1752 pub(super) fn to_wasm_table(&self) -> &Table {
1753 &self.ty
1754 }
1755
1756 pub(super) fn from_wasm_table(engine: &Engine, table: &Table) -> Self {
1757 let element = RefType::from_wasm_type(engine, &table.element_type);
1758
1759 Self {
1760 element,
1761 ty: table.clone(),
1762 }
1763 }
1764}
1765
1766/// A descriptor for a WebAssembly memory type.
1767///
1768/// Memories are described in units of pages (64KB) and represent contiguous
1769/// chunks of addressable memory.
1770#[derive(Debug, Clone, Hash)]
1771pub struct MemoryType {
1772 ty: Memory,
1773}
1774
1775impl MemoryType {
1776 pub(super) fn from_wasm_memory(memory: &Memory) -> Self {
1777 Self { ty: memory.clone() }
1778 }
1779}
1780
1781/// A WebAssembly global descriptor.
1782///
1783/// This type describes an instance of a global in a WebAssembly module. Globals
1784/// are local to an [`Instance`](crate::wasm::Instance) and are either immutable or
1785/// mutable.
1786#[derive(Debug, Clone, Hash)]
1787pub struct GlobalType {
1788 content: ValType,
1789 mutability: Mutability,
1790}
1791
1792impl GlobalType {
1793 pub fn content(&self) -> &ValType {
1794 &self.content
1795 }
1796
1797 pub fn mutability(&self) -> Mutability {
1798 self.mutability
1799 }
1800
1801 pub(super) fn to_wasm_global(&self) -> Global {
1802 Global {
1803 content_type: self.content.to_wasm_type(),
1804 mutable: self.mutability == Mutability::Const,
1805 shared: false,
1806 }
1807 }
1808
1809 pub(super) fn from_wasm_global(engine: &Engine, ty: &Global) -> Self {
1810 let content = ValType::from_wasm_type(engine, &ty.content_type);
1811 Self {
1812 content,
1813 mutability: if ty.mutable {
1814 Mutability::Var
1815 } else {
1816 Mutability::Const
1817 },
1818 }
1819 }
1820}
1821
1822/// A descriptor for a tag in a WebAssembly module.
1823///
1824/// This type describes an instance of a tag in a WebAssembly
1825/// module. Tags are local to an [`Instance`](crate::wasm::Instance).
1826#[derive(Debug, Clone, Hash)]
1827pub struct TagType {
1828 ty: FuncType,
1829}
1830
1831impl TagType {
1832 pub(super) fn from_wasm_tag(engine: &Engine, ty: Tag) -> Self {
1833 let ty = FuncType::from_shared_type_index(engine, ty.signature.unwrap_engine_type_index());
1834
1835 Self { ty }
1836 }
1837}
1838
1839/// A descriptor for an imported value into a wasm module.
1840///
1841/// This type is primarily accessed from the
1842/// [`Module::imports`](crate::wasm::Module::imports) API. Each [`ImportType`]
1843/// describes an import into the wasm module with the module/name that it's
1844/// imported from as well as the type of item that's being imported.
1845#[derive(Clone)]
1846pub struct ImportType<'module> {
1847 /// The module of the import.
1848 module: &'module str,
1849
1850 /// The field of the import.
1851 name: &'module str,
1852
1853 /// The type of the import.
1854 ty: EntityType,
1855 types: &'module ModuleTypes,
1856 engine: &'module Engine,
1857}
1858
1859impl fmt::Debug for ImportType<'_> {
1860 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1861 f.debug_struct("ImportType")
1862 .field("module", &self.module)
1863 .field("name", &self.name)
1864 .field("ty", &self.ty)
1865 .finish()
1866 }
1867}
1868
1869/// A descriptor for an exported WebAssembly value.
1870///
1871/// This type is primarily accessed from the
1872/// [`Module::exports`](crate::wasm::Module::exports) accessor and describes what
1873/// names are exported from a wasm module and the type of the item that is
1874/// exported.
1875#[derive(Clone)]
1876pub struct ExportType<'module> {
1877 /// The name of the export.
1878 name: &'module str,
1879
1880 /// The type of the export.
1881 ty: EntityType,
1882 types: &'module ModuleTypes,
1883 engine: &'module Engine,
1884}
1885
1886impl fmt::Debug for ExportType<'_> {
1887 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1888 f.debug_struct("ExportType")
1889 .field("name", &self.name)
1890 .field("ty", &self.ty)
1891 .finish()
1892 }
1893}