wasmtime/runtime/
types.rs

1use crate::prelude::*;
2use crate::runtime::Memory as RuntimeMemory;
3use crate::runtime::externals::Global as RuntimeGlobal;
4use crate::runtime::externals::Table as RuntimeTable;
5use crate::{AsContextMut, Extern, Func, Val};
6use crate::{Engine, type_registry::RegisteredType};
7use core::fmt::{self, Display, Write};
8use wasmtime_environ::{
9    EngineOrModuleTypeIndex, EntityType, Global, IndexType, Limits, Memory, ModuleTypes, Table,
10    Tag, TypeTrace, VMSharedTypeIndex, WasmArrayType, WasmCompositeInnerType, WasmCompositeType,
11    WasmFieldType, WasmFuncType, WasmHeapType, WasmRefType, WasmStorageType, WasmStructType,
12    WasmSubType, WasmValType,
13};
14
15pub(crate) mod matching;
16
17// Type Representations
18
19// Type attributes
20
21/// Indicator of whether a global value, struct's field, or array type's
22/// elements are mutable or not.
23#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
24pub enum Mutability {
25    /// The global value, struct field, or array elements are constant and the
26    /// value does not change.
27    Const,
28    /// The value of the global, struct field, or array elements can change over
29    /// time.
30    Var,
31}
32
33impl Mutability {
34    /// Is this constant?
35    #[inline]
36    pub fn is_const(&self) -> bool {
37        *self == Self::Const
38    }
39
40    /// Is this variable?
41    #[inline]
42    pub fn is_var(&self) -> bool {
43        *self == Self::Var
44    }
45}
46
47/// Indicator of whether a type is final or not.
48///
49/// Final types may not be the supertype of other types.
50#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
51pub enum Finality {
52    /// The associated type is final.
53    Final,
54    /// The associated type is not final.
55    NonFinal,
56}
57
58impl Finality {
59    /// Is this final?
60    #[inline]
61    pub fn is_final(&self) -> bool {
62        *self == Self::Final
63    }
64
65    /// Is this non-final?
66    #[inline]
67    pub fn is_non_final(&self) -> bool {
68        *self == Self::NonFinal
69    }
70}
71
72// Value Types
73
74/// A list of all possible value types in WebAssembly.
75///
76/// # Subtyping and Equality
77///
78/// `ValType` does not implement `Eq`, because reference types have a subtyping
79/// relationship, and so 99.99% of the time you actually want to check whether
80/// one type matches (i.e. is a subtype of) another type. You can use the
81/// [`ValType::matches`] and [`Val::matches_ty`][crate::Val::matches_ty] methods
82/// to perform these types of checks. If, however, you are in that 0.01%
83/// scenario where you need to check precise equality between types, you can use
84/// the [`ValType::eq`] method.
85#[derive(Clone, Hash)]
86pub enum ValType {
87    // NB: the ordering of variants here is intended to match the ordering in
88    // `wasmtime_environ::WasmType` to help improve codegen when converting.
89    //
90    /// Signed 32 bit integer.
91    I32,
92    /// Signed 64 bit integer.
93    I64,
94    /// Floating point 32 bit integer.
95    F32,
96    /// Floating point 64 bit integer.
97    F64,
98    /// A 128 bit number.
99    V128,
100    /// An opaque reference to some type on the heap.
101    Ref(RefType),
102}
103
104impl fmt::Debug for ValType {
105    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106        fmt::Display::fmt(self, f)
107    }
108}
109
110impl Display for ValType {
111    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
112        match self {
113            ValType::I32 => write!(f, "i32"),
114            ValType::I64 => write!(f, "i64"),
115            ValType::F32 => write!(f, "f32"),
116            ValType::F64 => write!(f, "f64"),
117            ValType::V128 => write!(f, "v128"),
118            ValType::Ref(r) => Display::fmt(r, f),
119        }
120    }
121}
122
123impl From<RefType> for ValType {
124    #[inline]
125    fn from(r: RefType) -> Self {
126        ValType::Ref(r)
127    }
128}
129
130impl ValType {
131    /// The `externref` type, aka `(ref null extern)`.
132    pub const EXTERNREF: Self = ValType::Ref(RefType::EXTERNREF);
133
134    /// The `nullexternref` type, aka `(ref null noextern)`.
135    pub const NULLEXTERNREF: Self = ValType::Ref(RefType::NULLEXTERNREF);
136
137    /// The `funcref` type, aka `(ref null func)`.
138    pub const FUNCREF: Self = ValType::Ref(RefType::FUNCREF);
139
140    /// The `nullfuncref` type, aka `(ref null nofunc)`.
141    pub const NULLFUNCREF: Self = ValType::Ref(RefType::NULLFUNCREF);
142
143    /// The `anyref` type, aka `(ref null any)`.
144    pub const ANYREF: Self = ValType::Ref(RefType::ANYREF);
145
146    /// The `eqref` type, aka `(ref null eq)`.
147    pub const EQREF: Self = ValType::Ref(RefType::EQREF);
148
149    /// The `i31ref` type, aka `(ref null i31)`.
150    pub const I31REF: Self = ValType::Ref(RefType::I31REF);
151
152    /// The `arrayref` type, aka `(ref null array)`.
153    pub const ARRAYREF: Self = ValType::Ref(RefType::ARRAYREF);
154
155    /// The `structref` type, aka `(ref null struct)`.
156    pub const STRUCTREF: Self = ValType::Ref(RefType::STRUCTREF);
157
158    /// The `nullref` type, aka `(ref null none)`.
159    pub const NULLREF: Self = ValType::Ref(RefType::NULLREF);
160
161    /// The `contref` type, aka `(ref null cont)`.
162    pub const CONTREF: Self = ValType::Ref(RefType::CONTREF);
163
164    /// The `nullcontref` type, aka. `(ref null nocont)`.
165    pub const NULLCONTREF: Self = ValType::Ref(RefType::NULLCONTREF);
166
167    /// Returns true if `ValType` matches any of the numeric types. (e.g. `I32`,
168    /// `I64`, `F32`, `F64`).
169    #[inline]
170    pub fn is_num(&self) -> bool {
171        match self {
172            ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 => true,
173            _ => false,
174        }
175    }
176
177    /// Is this the `i32` type?
178    #[inline]
179    pub fn is_i32(&self) -> bool {
180        matches!(self, ValType::I32)
181    }
182
183    /// Is this the `i64` type?
184    #[inline]
185    pub fn is_i64(&self) -> bool {
186        matches!(self, ValType::I64)
187    }
188
189    /// Is this the `f32` type?
190    #[inline]
191    pub fn is_f32(&self) -> bool {
192        matches!(self, ValType::F32)
193    }
194
195    /// Is this the `f64` type?
196    #[inline]
197    pub fn is_f64(&self) -> bool {
198        matches!(self, ValType::F64)
199    }
200
201    /// Is this the `v128` type?
202    #[inline]
203    pub fn is_v128(&self) -> bool {
204        matches!(self, ValType::V128)
205    }
206
207    /// Returns true if `ValType` is any kind of reference type.
208    #[inline]
209    pub fn is_ref(&self) -> bool {
210        matches!(self, ValType::Ref(_))
211    }
212
213    /// Is this the `funcref` (aka `(ref null func)`) type?
214    #[inline]
215    pub fn is_funcref(&self) -> bool {
216        matches!(
217            self,
218            ValType::Ref(RefType {
219                is_nullable: true,
220                heap_type: HeapType::Func
221            })
222        )
223    }
224
225    /// Is this the `externref` (aka `(ref null extern)`) type?
226    #[inline]
227    pub fn is_externref(&self) -> bool {
228        matches!(
229            self,
230            ValType::Ref(RefType {
231                is_nullable: true,
232                heap_type: HeapType::Extern
233            })
234        )
235    }
236
237    /// Is this the `anyref` (aka `(ref null any)`) type?
238    #[inline]
239    pub fn is_anyref(&self) -> bool {
240        matches!(
241            self,
242            ValType::Ref(RefType {
243                is_nullable: true,
244                heap_type: HeapType::Any
245            })
246        )
247    }
248
249    /// Is this the `contref` (aka `(ref null cont)`) type?
250    #[inline]
251    pub fn is_contref(&self) -> bool {
252        matches!(
253            self,
254            ValType::Ref(RefType {
255                is_nullable: true,
256                heap_type: HeapType::Cont
257            })
258        )
259    }
260
261    /// Get the underlying reference type, if this value type is a reference
262    /// type.
263    #[inline]
264    pub fn as_ref(&self) -> Option<&RefType> {
265        match self {
266            ValType::Ref(r) => Some(r),
267            _ => None,
268        }
269    }
270
271    /// Get the underlying reference type, panicking if this value type is not a
272    /// reference type.
273    #[inline]
274    pub fn unwrap_ref(&self) -> &RefType {
275        self.as_ref()
276            .expect("ValType::unwrap_ref on a non-reference type")
277    }
278
279    /// Does this value type match the other type?
280    ///
281    /// That is, is this value type a subtype of the other?
282    ///
283    /// # Panics
284    ///
285    /// Panics if either type is associated with a different engine from the
286    /// other.
287    pub fn matches(&self, other: &ValType) -> bool {
288        match (self, other) {
289            (Self::I32, Self::I32) => true,
290            (Self::I64, Self::I64) => true,
291            (Self::F32, Self::F32) => true,
292            (Self::F64, Self::F64) => true,
293            (Self::V128, Self::V128) => true,
294            (Self::Ref(a), Self::Ref(b)) => a.matches(b),
295            (Self::I32, _)
296            | (Self::I64, _)
297            | (Self::F32, _)
298            | (Self::F64, _)
299            | (Self::V128, _)
300            | (Self::Ref(_), _) => false,
301        }
302    }
303
304    /// Is value type `a` precisely equal to value type `b`?
305    ///
306    /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
307    /// are not exactly the same value type.
308    ///
309    /// # Panics
310    ///
311    /// Panics if either type is associated with a different engine.
312    pub fn eq(a: &Self, b: &Self) -> bool {
313        a.matches(b) && b.matches(a)
314    }
315
316    /// Is this a `VMGcRef` type that is not i31 and is not an uninhabited
317    /// bottom type?
318    #[inline]
319    pub(crate) fn is_vmgcref_type_and_points_to_object(&self) -> bool {
320        match self {
321            ValType::Ref(r) => r.is_vmgcref_type_and_points_to_object(),
322            ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => false,
323        }
324    }
325
326    pub(crate) fn ensure_matches(&self, engine: &Engine, other: &ValType) -> Result<()> {
327        if !self.comes_from_same_engine(engine) || !other.comes_from_same_engine(engine) {
328            bail!("type used with wrong engine");
329        }
330        if self.matches(other) {
331            Ok(())
332        } else {
333            bail!("type mismatch: expected {other}, found {self}")
334        }
335    }
336
337    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
338        match self {
339            Self::I32 | Self::I64 | Self::F32 | Self::F64 | Self::V128 => true,
340            Self::Ref(r) => r.comes_from_same_engine(engine),
341        }
342    }
343
344    pub(crate) fn to_wasm_type(&self) -> WasmValType {
345        match self {
346            Self::I32 => WasmValType::I32,
347            Self::I64 => WasmValType::I64,
348            Self::F32 => WasmValType::F32,
349            Self::F64 => WasmValType::F64,
350            Self::V128 => WasmValType::V128,
351            Self::Ref(r) => WasmValType::Ref(r.to_wasm_type()),
352        }
353    }
354
355    #[inline]
356    pub(crate) fn from_wasm_type(engine: &Engine, ty: &WasmValType) -> Self {
357        match ty {
358            WasmValType::I32 => Self::I32,
359            WasmValType::I64 => Self::I64,
360            WasmValType::F32 => Self::F32,
361            WasmValType::F64 => Self::F64,
362            WasmValType::V128 => Self::V128,
363            WasmValType::Ref(r) => Self::Ref(RefType::from_wasm_type(engine, r)),
364        }
365    }
366    /// Construct a default value. Returns None for non-nullable Ref types, which have no default.
367    pub fn default_value(&self) -> Option<Val> {
368        match self {
369            ValType::I32 => Some(Val::I32(0)),
370            ValType::I64 => Some(Val::I64(0)),
371            ValType::F32 => Some(Val::F32(0)),
372            ValType::F64 => Some(Val::F64(0)),
373            ValType::V128 => Some(Val::V128(0.into())),
374            ValType::Ref(r) => {
375                if r.is_nullable() {
376                    Some(Val::null_ref(r.heap_type()))
377                } else {
378                    None
379                }
380            }
381        }
382    }
383}
384
385/// Opaque references to data in the Wasm heap or to host data.
386///
387/// # Subtyping and Equality
388///
389/// `RefType` does not implement `Eq`, because reference types have a subtyping
390/// relationship, and so 99.99% of the time you actually want to check whether
391/// one type matches (i.e. is a subtype of) another type. You can use the
392/// [`RefType::matches`] and [`Ref::matches_ty`][crate::Ref::matches_ty] methods
393/// to perform these types of checks. If, however, you are in that 0.01%
394/// scenario where you need to check precise equality between types, you can use
395/// the [`RefType::eq`] method.
396#[derive(Clone, Hash)]
397pub struct RefType {
398    is_nullable: bool,
399    heap_type: HeapType,
400}
401
402impl fmt::Debug for RefType {
403    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
404        Display::fmt(self, f)
405    }
406}
407
408impl fmt::Display for RefType {
409    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
410        write!(f, "(ref ")?;
411        if self.is_nullable() {
412            write!(f, "null ")?;
413        }
414        write!(f, "{})", self.heap_type())
415    }
416}
417
418impl RefType {
419    /// The `externref` type, aka `(ref null extern)`.
420    pub const EXTERNREF: Self = RefType {
421        is_nullable: true,
422        heap_type: HeapType::Extern,
423    };
424
425    /// The `nullexternref` type, aka `(ref null noextern)`.
426    pub const NULLEXTERNREF: Self = RefType {
427        is_nullable: true,
428        heap_type: HeapType::NoExtern,
429    };
430
431    /// The `funcref` type, aka `(ref null func)`.
432    pub const FUNCREF: Self = RefType {
433        is_nullable: true,
434        heap_type: HeapType::Func,
435    };
436
437    /// The `nullfuncref` type, aka `(ref null nofunc)`.
438    pub const NULLFUNCREF: Self = RefType {
439        is_nullable: true,
440        heap_type: HeapType::NoFunc,
441    };
442
443    /// The `anyref` type, aka `(ref null any)`.
444    pub const ANYREF: Self = RefType {
445        is_nullable: true,
446        heap_type: HeapType::Any,
447    };
448
449    /// The `eqref` type, aka `(ref null eq)`.
450    pub const EQREF: Self = RefType {
451        is_nullable: true,
452        heap_type: HeapType::Eq,
453    };
454
455    /// The `i31ref` type, aka `(ref null i31)`.
456    pub const I31REF: Self = RefType {
457        is_nullable: true,
458        heap_type: HeapType::I31,
459    };
460
461    /// The `arrayref` type, aka `(ref null array)`.
462    pub const ARRAYREF: Self = RefType {
463        is_nullable: true,
464        heap_type: HeapType::Array,
465    };
466
467    /// The `structref` type, aka `(ref null struct)`.
468    pub const STRUCTREF: Self = RefType {
469        is_nullable: true,
470        heap_type: HeapType::Struct,
471    };
472
473    /// The `nullref` type, aka `(ref null none)`.
474    pub const NULLREF: Self = RefType {
475        is_nullable: true,
476        heap_type: HeapType::None,
477    };
478
479    /// The `contref` type, aka `(ref null cont)`.
480    pub const CONTREF: Self = RefType {
481        is_nullable: true,
482        heap_type: HeapType::Cont,
483    };
484
485    /// The `nullcontref` type, aka `(ref null nocont)`.
486    pub const NULLCONTREF: Self = RefType {
487        is_nullable: true,
488        heap_type: HeapType::NoCont,
489    };
490
491    /// Construct a new reference type.
492    pub fn new(is_nullable: bool, heap_type: HeapType) -> RefType {
493        RefType {
494            is_nullable,
495            heap_type,
496        }
497    }
498
499    /// Can this type of reference be null?
500    pub fn is_nullable(&self) -> bool {
501        self.is_nullable
502    }
503
504    /// The heap type that this is a reference to.
505    #[inline]
506    pub fn heap_type(&self) -> &HeapType {
507        &self.heap_type
508    }
509
510    /// Does this reference type match the other?
511    ///
512    /// That is, is this reference type a subtype of the other?
513    ///
514    /// # Panics
515    ///
516    /// Panics if either type is associated with a different engine from the
517    /// other.
518    pub fn matches(&self, other: &RefType) -> bool {
519        if self.is_nullable() && !other.is_nullable() {
520            return false;
521        }
522        self.heap_type().matches(other.heap_type())
523    }
524
525    /// Is reference type `a` precisely equal to reference type `b`?
526    ///
527    /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
528    /// are not exactly the same reference type.
529    ///
530    /// # Panics
531    ///
532    /// Panics if either type is associated with a different engine.
533    pub fn eq(a: &RefType, b: &RefType) -> bool {
534        a.matches(b) && b.matches(a)
535    }
536
537    pub(crate) fn ensure_matches(&self, engine: &Engine, other: &RefType) -> Result<()> {
538        if !self.comes_from_same_engine(engine) || !other.comes_from_same_engine(engine) {
539            bail!("type used with wrong engine");
540        }
541        if self.matches(other) {
542            Ok(())
543        } else {
544            bail!("type mismatch: expected {other}, found {self}")
545        }
546    }
547
548    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
549        self.heap_type().comes_from_same_engine(engine)
550    }
551
552    pub(crate) fn to_wasm_type(&self) -> WasmRefType {
553        WasmRefType {
554            nullable: self.is_nullable(),
555            heap_type: self.heap_type().to_wasm_type(),
556        }
557    }
558
559    pub(crate) fn from_wasm_type(engine: &Engine, ty: &WasmRefType) -> RefType {
560        RefType {
561            is_nullable: ty.nullable,
562            heap_type: HeapType::from_wasm_type(engine, &ty.heap_type),
563        }
564    }
565
566    pub(crate) fn is_vmgcref_type_and_points_to_object(&self) -> bool {
567        self.heap_type().is_vmgcref_type_and_points_to_object()
568    }
569}
570
571/// The heap types that can Wasm can have references to.
572///
573/// # Subtyping Hierarchy
574///
575/// Wasm has three different heap type hierarchies:
576///
577/// 1. Function types
578/// 2. External types
579/// 3. Internal types
580///
581/// Each hierarchy has a top type (the common supertype of which everything else
582/// in its hierarchy is a subtype of) and a bottom type (the common subtype of
583/// which everything else in its hierarchy is supertype of).
584///
585/// ## Function Types Hierarchy
586///
587/// The top of the function types hierarchy is `func`; the bottom is
588/// `nofunc`. In between are all the concrete function types.
589///
590/// ```text
591///                          func
592///                       /  /  \  \
593///      ,----------------  /    \  -------------------------.
594///     /                  /      \                           \
595///    |              ,----        -----------.                |
596///    |              |                       |                |
597///    |              |                       |                |
598/// (func)    (func (param i32))    (func (param i32 i32))    ...
599///    |              |                       |                |
600///    |              |                       |                |
601///    |              `---.        ,----------'                |
602///     \                  \      /                           /
603///      `---------------.  \    /  ,------------------------'
604///                       \  \  /  /
605///                         nofunc
606/// ```
607///
608/// Additionally, some concrete function types are sub- or supertypes of other
609/// concrete function types, if that was declared in their definition. For
610/// simplicity, this isn't depicted in the diagram above.
611///
612/// ## External
613///
614/// The top of the external types hierarchy is `extern`; the bottom is
615/// `noextern`. There are no concrete types in this hierarchy.
616///
617/// ```text
618///  extern
619///    |
620/// noextern
621/// ```
622///
623/// ## Internal
624///
625/// The top of the internal types hierarchy is `any`; the bottom is `none`. The
626/// `eq` type is the common supertype of all types that can be compared for
627/// equality. The `struct` and `array` types are the common supertypes of all
628/// concrete struct and array types respectively. The `i31` type represents
629/// unboxed 31-bit integers.
630///
631/// ```text
632///                                   any
633///                                  / | \
634///    ,----------------------------'  |  `--------------------------.
635///   /                                |                              \
636///  |                        .--------'                               |
637///  |                        |                                        |
638///  |                      struct                                   array
639///  |                     /  |   \                                 /  |   \
640/// i31             ,-----'   |    '-----.                   ,-----'   |    `-----.
641///  |             /          |           \                 /          |           \
642///  |            |           |            |               |           |            |
643///  |        (struct)    (struct i32)    ...        (array i32)    (array i64)    ...
644///  |            |           |            |               |           |            |
645///  |             \          |           /                 \          |           /
646///   \             `-----.   |    ,-----'                   `-----.   |    ,-----'
647///    \                   \  |   /                                 \  |   /
648///     \                   \ |  /                                   \ |  /
649///      \                   \| /                                     \| /
650///       \                   |/                                       |/
651///        \                  |                                        |
652///         \                 |                                       /
653///          \                '--------.                             /
654///           \                        |                            /
655///            `--------------------.  |   ,-----------------------'
656///                                  \ |  /
657///                                   none
658/// ```
659///
660/// Additionally, concrete struct and array types can be subtypes of other
661/// concrete struct and array types respectively, if that was declared in their
662/// definitions. Once again, this is omitted from the above diagram for
663/// simplicity.
664///
665/// # Subtyping and Equality
666///
667/// `HeapType` does not implement `Eq`, because heap types have a subtyping
668/// relationship, and so 99.99% of the time you actually want to check whether
669/// one type matches (i.e. is a subtype of) another type. You can use the
670/// [`HeapType::matches`] method to perform these types of checks. If, however,
671/// you are in that 0.01% scenario where you need to check precise equality
672/// between types, you can use the [`HeapType::eq`] method.
673#[derive(Debug, Clone, Hash)]
674pub enum HeapType {
675    /// The abstract `extern` heap type represents external host data.
676    ///
677    /// This is the top type for the external type hierarchy, and therefore is
678    /// the common supertype of all external reference types.
679    Extern,
680
681    /// The abstract `noextern` heap type represents the null external
682    /// reference.
683    ///
684    /// This is the bottom type for the external type hierarchy, and therefore
685    /// is the common subtype of all external reference types.
686    NoExtern,
687
688    /// The abstract `func` heap type represents a reference to any kind of
689    /// function.
690    ///
691    /// This is the top type for the function references type hierarchy, and is
692    /// therefore a supertype of every function reference.
693    Func,
694
695    /// A reference to a function of a specific, concrete type.
696    ///
697    /// These are subtypes of `func` and supertypes of `nofunc`.
698    ConcreteFunc(FuncType),
699
700    /// The abstract `nofunc` heap type represents the null function reference.
701    ///
702    /// This is the bottom type for the function references type hierarchy, and
703    /// therefore `nofunc` is a subtype of all function reference types.
704    NoFunc,
705
706    /// The abstract `any` heap type represents all internal Wasm data.
707    ///
708    /// This is the top type of the internal type hierarchy, and is therefore a
709    /// supertype of all internal types (such as `eq`, `i31`, `struct`s, and
710    /// `array`s).
711    Any,
712
713    /// The abstract `eq` heap type represenets all internal Wasm references
714    /// that can be compared for equality.
715    ///
716    /// This is a subtype of `any` and a supertype of `i31`, `array`, `struct`,
717    /// and `none` heap types.
718    Eq,
719
720    /// The `i31` heap type represents unboxed 31-bit integers.
721    ///
722    /// This is a subtype of `any` and `eq`, and a supertype of `none`.
723    I31,
724
725    /// The abstract `array` heap type represents a reference to any kind of
726    /// array.
727    ///
728    /// This is a subtype of `any` and `eq`, and a supertype of all concrete
729    /// array types, as well as a supertype of the abstract `none` heap type.
730    Array,
731
732    /// A reference to an array of a specific, concrete type.
733    ///
734    /// These are subtypes of the `array` heap type (therefore also a subtype of
735    /// `any` and `eq`) and supertypes of the `none` heap type.
736    ConcreteArray(ArrayType),
737
738    /// The abstract `struct` heap type represents a reference to any kind of
739    /// struct.
740    ///
741    /// This is a subtype of `any` and `eq`, and a supertype of all concrete
742    /// struct types, as well as a supertype of the abstract `none` heap type.
743    Struct,
744
745    /// A reference to an struct of a specific, concrete type.
746    ///
747    /// These are subtypes of the `struct` heap type (therefore also a subtype
748    /// of `any` and `eq`) and supertypes of the `none` heap type.
749    ConcreteStruct(StructType),
750
751    /// A reference to a continuation of a specific, concrete type.
752    ///
753    /// These are subtypes of `cont` and supertypes of `nocont`.
754    ConcreteCont(ContType),
755
756    /// The `cont` heap type represents a reference to any kind of continuation.
757    ///
758    /// This is the top type for the continuation objects type hierarchy, and is
759    /// therefore a supertype of every continuation object.
760    Cont,
761
762    /// The `nocont` heap type represents the null continuation object.
763    ///
764    /// This is the bottom type for the continuation objects type hierarchy, and
765    /// therefore `nocont` is a subtype of all continuation object types.
766    NoCont,
767
768    /// The abstract `none` heap type represents the null internal reference.
769    ///
770    /// This is the bottom type for the internal type hierarchy, and therefore
771    /// `none` is a subtype of internal types.
772    None,
773}
774
775impl Display for HeapType {
776    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
777        match self {
778            HeapType::Extern => write!(f, "extern"),
779            HeapType::NoExtern => write!(f, "noextern"),
780            HeapType::Func => write!(f, "func"),
781            HeapType::NoFunc => write!(f, "nofunc"),
782            HeapType::Any => write!(f, "any"),
783            HeapType::Eq => write!(f, "eq"),
784            HeapType::I31 => write!(f, "i31"),
785            HeapType::Array => write!(f, "array"),
786            HeapType::Struct => write!(f, "struct"),
787            HeapType::None => write!(f, "none"),
788            HeapType::ConcreteFunc(ty) => write!(f, "(concrete func {:?})", ty.type_index()),
789            HeapType::ConcreteArray(ty) => write!(f, "(concrete array {:?})", ty.type_index()),
790            HeapType::ConcreteStruct(ty) => write!(f, "(concrete struct {:?})", ty.type_index()),
791            HeapType::ConcreteCont(ty) => write!(f, "(concrete cont {:?})", ty.type_index()),
792            HeapType::Cont => write!(f, "cont"),
793            HeapType::NoCont => write!(f, "nocont"),
794        }
795    }
796}
797
798impl From<FuncType> for HeapType {
799    #[inline]
800    fn from(f: FuncType) -> Self {
801        HeapType::ConcreteFunc(f)
802    }
803}
804
805impl From<ArrayType> for HeapType {
806    #[inline]
807    fn from(a: ArrayType) -> Self {
808        HeapType::ConcreteArray(a)
809    }
810}
811
812impl From<StructType> for HeapType {
813    #[inline]
814    fn from(s: StructType) -> Self {
815        HeapType::ConcreteStruct(s)
816    }
817}
818
819impl From<ContType> for HeapType {
820    #[inline]
821    fn from(f: ContType) -> Self {
822        HeapType::ConcreteCont(f)
823    }
824}
825
826impl HeapType {
827    /// Is this the abstract `extern` heap type?
828    pub fn is_extern(&self) -> bool {
829        matches!(self, HeapType::Extern)
830    }
831
832    /// Is this the abstract `func` heap type?
833    pub fn is_func(&self) -> bool {
834        matches!(self, HeapType::Func)
835    }
836
837    /// Is this the abstract `nofunc` heap type?
838    pub fn is_no_func(&self) -> bool {
839        matches!(self, HeapType::NoFunc)
840    }
841
842    /// Is this the abstract `any` heap type?
843    pub fn is_any(&self) -> bool {
844        matches!(self, HeapType::Any)
845    }
846
847    /// Is this the abstract `i31` heap type?
848    pub fn is_i31(&self) -> bool {
849        matches!(self, HeapType::I31)
850    }
851
852    /// Is this the abstract `none` heap type?
853    pub fn is_none(&self) -> bool {
854        matches!(self, HeapType::None)
855    }
856
857    /// Is this the abstract `cont` heap type?
858    pub fn is_cont(&self) -> bool {
859        matches!(self, HeapType::Cont)
860    }
861
862    /// Is this an abstract type?
863    ///
864    /// Types that are not abstract are concrete, user-defined types.
865    pub fn is_abstract(&self) -> bool {
866        !self.is_concrete()
867    }
868
869    /// Is this a concrete, user-defined heap type?
870    ///
871    /// Types that are not concrete, user-defined types are abstract types.
872    #[inline]
873    pub fn is_concrete(&self) -> bool {
874        matches!(
875            self,
876            HeapType::ConcreteFunc(_)
877                | HeapType::ConcreteArray(_)
878                | HeapType::ConcreteStruct(_)
879                | HeapType::ConcreteCont(_)
880        )
881    }
882
883    /// Is this a concrete, user-defined function type?
884    pub fn is_concrete_func(&self) -> bool {
885        matches!(self, HeapType::ConcreteFunc(_))
886    }
887
888    /// Get the underlying concrete, user-defined function type, if any.
889    ///
890    /// Returns `None` if this is not a concrete function type.
891    pub fn as_concrete_func(&self) -> Option<&FuncType> {
892        match self {
893            HeapType::ConcreteFunc(f) => Some(f),
894            _ => None,
895        }
896    }
897
898    /// Get the underlying concrete, user-defined type, panicking if this is not
899    /// a concrete function type.
900    pub fn unwrap_concrete_func(&self) -> &FuncType {
901        self.as_concrete_func().unwrap()
902    }
903
904    /// Is this a concrete, user-defined array type?
905    pub fn is_concrete_array(&self) -> bool {
906        matches!(self, HeapType::ConcreteArray(_))
907    }
908
909    /// Get the underlying concrete, user-defined array type, if any.
910    ///
911    /// Returns `None` for if this is not a concrete array type.
912    pub fn as_concrete_array(&self) -> Option<&ArrayType> {
913        match self {
914            HeapType::ConcreteArray(f) => Some(f),
915            _ => None,
916        }
917    }
918
919    /// Get the underlying concrete, user-defined type, panicking if this is not
920    /// a concrete array type.
921    pub fn unwrap_concrete_array(&self) -> &ArrayType {
922        self.as_concrete_array().unwrap()
923    }
924
925    /// Is this a concrete, user-defined continuation type?
926    pub fn is_concrete_cont(&self) -> bool {
927        matches!(self, HeapType::ConcreteCont(_))
928    }
929
930    /// Get the underlying concrete, user-defined continuation type, if any.
931    ///
932    /// Returns `None` if this is not a concrete continuation type.
933    pub fn as_concrete_cont(&self) -> Option<&ContType> {
934        match self {
935            HeapType::ConcreteCont(f) => Some(f),
936            _ => None,
937        }
938    }
939
940    /// Is this a concrete, user-defined struct type?
941    pub fn is_concrete_struct(&self) -> bool {
942        matches!(self, HeapType::ConcreteStruct(_))
943    }
944
945    /// Get the underlying concrete, user-defined struct type, if any.
946    ///
947    /// Returns `None` for if this is not a concrete struct type.
948    pub fn as_concrete_struct(&self) -> Option<&StructType> {
949        match self {
950            HeapType::ConcreteStruct(f) => Some(f),
951            _ => None,
952        }
953    }
954
955    /// Get the underlying concrete, user-defined type, panicking if this is not
956    /// a concrete continuation type.
957    pub fn unwrap_concrete_cont(&self) -> &ContType {
958        self.as_concrete_cont().unwrap()
959    }
960
961    /// Get the underlying concrete, user-defined type, panicking if this is not
962    /// a concrete struct type.
963    pub fn unwrap_concrete_struct(&self) -> &StructType {
964        self.as_concrete_struct().unwrap()
965    }
966
967    /// Get the top type of this heap type's type hierarchy.
968    ///
969    /// The returned heap type is a supertype of all types in this heap type's
970    /// type hierarchy.
971    #[inline]
972    pub fn top(&self) -> HeapType {
973        match self {
974            HeapType::Func | HeapType::ConcreteFunc(_) | HeapType::NoFunc => HeapType::Func,
975
976            HeapType::Extern | HeapType::NoExtern => HeapType::Extern,
977
978            HeapType::Any
979            | HeapType::Eq
980            | HeapType::I31
981            | HeapType::Array
982            | HeapType::ConcreteArray(_)
983            | HeapType::Struct
984            | HeapType::ConcreteStruct(_)
985            | HeapType::None => HeapType::Any,
986
987            HeapType::Cont | HeapType::ConcreteCont(_) | HeapType::NoCont => HeapType::Cont,
988        }
989    }
990
991    /// Is this the top type within its type hierarchy?
992    #[inline]
993    pub fn is_top(&self) -> bool {
994        match self {
995            HeapType::Any | HeapType::Extern | HeapType::Func | HeapType::Cont => true,
996            _ => false,
997        }
998    }
999
1000    /// Get the bottom type of this heap type's type hierarchy.
1001    ///
1002    /// The returned heap type is a subtype of all types in this heap type's
1003    /// type hierarchy.
1004    #[inline]
1005    pub fn bottom(&self) -> HeapType {
1006        match self {
1007            HeapType::Extern | HeapType::NoExtern => HeapType::NoExtern,
1008
1009            HeapType::Func | HeapType::ConcreteFunc(_) | HeapType::NoFunc => HeapType::NoFunc,
1010
1011            HeapType::Any
1012            | HeapType::Eq
1013            | HeapType::I31
1014            | HeapType::Array
1015            | HeapType::ConcreteArray(_)
1016            | HeapType::Struct
1017            | HeapType::ConcreteStruct(_)
1018            | HeapType::None => HeapType::None,
1019
1020            HeapType::Cont | HeapType::ConcreteCont(_) | HeapType::NoCont => HeapType::NoCont,
1021        }
1022    }
1023
1024    /// Is this the bottom type within its type hierarchy?
1025    #[inline]
1026    pub fn is_bottom(&self) -> bool {
1027        match self {
1028            HeapType::None | HeapType::NoExtern | HeapType::NoFunc | HeapType::NoCont => true,
1029            _ => false,
1030        }
1031    }
1032
1033    /// Does this heap type match the other heap type?
1034    ///
1035    /// That is, is this heap type a subtype of the other?
1036    ///
1037    /// # Panics
1038    ///
1039    /// Panics if either type is associated with a different engine from the
1040    /// other.
1041    pub fn matches(&self, other: &HeapType) -> bool {
1042        match (self, other) {
1043            (HeapType::Extern, HeapType::Extern) => true,
1044            (HeapType::Extern, _) => false,
1045
1046            (HeapType::NoExtern, HeapType::NoExtern | HeapType::Extern) => true,
1047            (HeapType::NoExtern, _) => false,
1048
1049            (HeapType::NoFunc, HeapType::NoFunc | HeapType::ConcreteFunc(_) | HeapType::Func) => {
1050                true
1051            }
1052            (HeapType::NoFunc, _) => false,
1053
1054            (HeapType::ConcreteFunc(_), HeapType::Func) => true,
1055            (HeapType::ConcreteFunc(a), HeapType::ConcreteFunc(b)) => {
1056                assert!(a.comes_from_same_engine(b.engine()));
1057                a.engine()
1058                    .signatures()
1059                    .is_subtype(a.type_index(), b.type_index())
1060            }
1061            (HeapType::ConcreteFunc(_), _) => false,
1062
1063            (HeapType::Func, HeapType::Func) => true,
1064            (HeapType::Func, _) => false,
1065
1066            (HeapType::Cont, HeapType::Cont) => true,
1067            (HeapType::Cont, _) => false,
1068
1069            (HeapType::NoCont, HeapType::NoCont | HeapType::ConcreteCont(_) | HeapType::Cont) => {
1070                true
1071            }
1072            (HeapType::NoCont, _) => false,
1073
1074            (HeapType::ConcreteCont(_), HeapType::Cont) => true,
1075            (HeapType::ConcreteCont(a), HeapType::ConcreteCont(b)) => a.matches(b),
1076            (HeapType::ConcreteCont(_), _) => false,
1077
1078            (
1079                HeapType::None,
1080                HeapType::None
1081                | HeapType::ConcreteArray(_)
1082                | HeapType::Array
1083                | HeapType::ConcreteStruct(_)
1084                | HeapType::Struct
1085                | HeapType::I31
1086                | HeapType::Eq
1087                | HeapType::Any,
1088            ) => true,
1089            (HeapType::None, _) => false,
1090
1091            (HeapType::ConcreteArray(_), HeapType::Array | HeapType::Eq | HeapType::Any) => true,
1092            (HeapType::ConcreteArray(a), HeapType::ConcreteArray(b)) => {
1093                assert!(a.comes_from_same_engine(b.engine()));
1094                a.engine()
1095                    .signatures()
1096                    .is_subtype(a.type_index(), b.type_index())
1097            }
1098            (HeapType::ConcreteArray(_), _) => false,
1099
1100            (HeapType::Array, HeapType::Array | HeapType::Eq | HeapType::Any) => true,
1101            (HeapType::Array, _) => false,
1102
1103            (HeapType::ConcreteStruct(_), HeapType::Struct | HeapType::Eq | HeapType::Any) => true,
1104            (HeapType::ConcreteStruct(a), HeapType::ConcreteStruct(b)) => {
1105                assert!(a.comes_from_same_engine(b.engine()));
1106                a.engine()
1107                    .signatures()
1108                    .is_subtype(a.type_index(), b.type_index())
1109            }
1110            (HeapType::ConcreteStruct(_), _) => false,
1111
1112            (HeapType::Struct, HeapType::Struct | HeapType::Eq | HeapType::Any) => true,
1113            (HeapType::Struct, _) => false,
1114
1115            (HeapType::I31, HeapType::I31 | HeapType::Eq | HeapType::Any) => true,
1116            (HeapType::I31, _) => false,
1117
1118            (HeapType::Eq, HeapType::Eq | HeapType::Any) => true,
1119            (HeapType::Eq, _) => false,
1120
1121            (HeapType::Any, HeapType::Any) => true,
1122            (HeapType::Any, _) => false,
1123        }
1124    }
1125
1126    /// Is heap type `a` precisely equal to heap type `b`?
1127    ///
1128    /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
1129    /// are not exactly the same heap type.
1130    ///
1131    /// # Panics
1132    ///
1133    /// Panics if either type is associated with a different engine from the
1134    /// other.
1135    pub fn eq(a: &HeapType, b: &HeapType) -> bool {
1136        a.matches(b) && b.matches(a)
1137    }
1138
1139    pub(crate) fn ensure_matches(&self, engine: &Engine, other: &HeapType) -> Result<()> {
1140        if !self.comes_from_same_engine(engine) || !other.comes_from_same_engine(engine) {
1141            bail!("type used with wrong engine");
1142        }
1143        if self.matches(other) {
1144            Ok(())
1145        } else {
1146            bail!("type mismatch: expected {other}, found {self}");
1147        }
1148    }
1149
1150    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
1151        match self {
1152            HeapType::Extern
1153            | HeapType::NoExtern
1154            | HeapType::Func
1155            | HeapType::NoFunc
1156            | HeapType::Any
1157            | HeapType::Eq
1158            | HeapType::I31
1159            | HeapType::Array
1160            | HeapType::Struct
1161            | HeapType::Cont
1162            | HeapType::NoCont
1163            | HeapType::None => true,
1164            HeapType::ConcreteFunc(ty) => ty.comes_from_same_engine(engine),
1165            HeapType::ConcreteArray(ty) => ty.comes_from_same_engine(engine),
1166            HeapType::ConcreteStruct(ty) => ty.comes_from_same_engine(engine),
1167            HeapType::ConcreteCont(ty) => ty.comes_from_same_engine(engine),
1168        }
1169    }
1170
1171    pub(crate) fn to_wasm_type(&self) -> WasmHeapType {
1172        match self {
1173            HeapType::Extern => WasmHeapType::Extern,
1174            HeapType::NoExtern => WasmHeapType::NoExtern,
1175            HeapType::Func => WasmHeapType::Func,
1176            HeapType::NoFunc => WasmHeapType::NoFunc,
1177            HeapType::Any => WasmHeapType::Any,
1178            HeapType::Eq => WasmHeapType::Eq,
1179            HeapType::I31 => WasmHeapType::I31,
1180            HeapType::Array => WasmHeapType::Array,
1181            HeapType::Struct => WasmHeapType::Struct,
1182            HeapType::None => WasmHeapType::None,
1183            HeapType::ConcreteFunc(f) => {
1184                WasmHeapType::ConcreteFunc(EngineOrModuleTypeIndex::Engine(f.type_index()))
1185            }
1186            HeapType::ConcreteArray(a) => {
1187                WasmHeapType::ConcreteArray(EngineOrModuleTypeIndex::Engine(a.type_index()))
1188            }
1189            HeapType::ConcreteStruct(a) => {
1190                WasmHeapType::ConcreteStruct(EngineOrModuleTypeIndex::Engine(a.type_index()))
1191            }
1192            HeapType::Cont => WasmHeapType::Cont,
1193            HeapType::NoCont => WasmHeapType::NoCont,
1194            HeapType::ConcreteCont(c) => {
1195                WasmHeapType::ConcreteCont(EngineOrModuleTypeIndex::Engine(c.type_index()))
1196            }
1197        }
1198    }
1199
1200    pub(crate) fn from_wasm_type(engine: &Engine, ty: &WasmHeapType) -> HeapType {
1201        match ty {
1202            WasmHeapType::Extern => HeapType::Extern,
1203            WasmHeapType::NoExtern => HeapType::NoExtern,
1204            WasmHeapType::Func => HeapType::Func,
1205            WasmHeapType::NoFunc => HeapType::NoFunc,
1206            WasmHeapType::Any => HeapType::Any,
1207            WasmHeapType::Eq => HeapType::Eq,
1208            WasmHeapType::I31 => HeapType::I31,
1209            WasmHeapType::Array => HeapType::Array,
1210            WasmHeapType::Struct => HeapType::Struct,
1211            WasmHeapType::None => HeapType::None,
1212            WasmHeapType::ConcreteFunc(EngineOrModuleTypeIndex::Engine(idx)) => {
1213                HeapType::ConcreteFunc(FuncType::from_shared_type_index(engine, *idx))
1214            }
1215            WasmHeapType::ConcreteArray(EngineOrModuleTypeIndex::Engine(idx)) => {
1216                HeapType::ConcreteArray(ArrayType::from_shared_type_index(engine, *idx))
1217            }
1218            WasmHeapType::ConcreteStruct(EngineOrModuleTypeIndex::Engine(idx)) => {
1219                HeapType::ConcreteStruct(StructType::from_shared_type_index(engine, *idx))
1220            }
1221
1222            WasmHeapType::ConcreteFunc(EngineOrModuleTypeIndex::Module(_))
1223            | WasmHeapType::ConcreteFunc(EngineOrModuleTypeIndex::RecGroup(_))
1224            | WasmHeapType::ConcreteArray(EngineOrModuleTypeIndex::Module(_))
1225            | WasmHeapType::ConcreteArray(EngineOrModuleTypeIndex::RecGroup(_))
1226            | WasmHeapType::ConcreteStruct(EngineOrModuleTypeIndex::Module(_))
1227            | WasmHeapType::ConcreteStruct(EngineOrModuleTypeIndex::RecGroup(_))
1228            | WasmHeapType::ConcreteCont(EngineOrModuleTypeIndex::Module(_))
1229            | WasmHeapType::ConcreteCont(EngineOrModuleTypeIndex::RecGroup(_)) => {
1230                panic!("HeapType::from_wasm_type on non-canonicalized-for-runtime-usage heap type")
1231            }
1232            WasmHeapType::Cont => HeapType::Cont,
1233            WasmHeapType::NoCont => HeapType::NoCont,
1234            WasmHeapType::ConcreteCont(EngineOrModuleTypeIndex::Engine(idx)) => {
1235                HeapType::ConcreteCont(ContType::from_shared_type_index(engine, *idx))
1236            }
1237        }
1238    }
1239
1240    pub(crate) fn as_registered_type(&self) -> Option<&RegisteredType> {
1241        match self {
1242            HeapType::ConcreteCont(c) => Some(&c.registered_type),
1243            HeapType::ConcreteFunc(f) => Some(&f.registered_type),
1244            HeapType::ConcreteArray(a) => Some(&a.registered_type),
1245            HeapType::ConcreteStruct(a) => Some(&a.registered_type),
1246
1247            HeapType::Extern
1248            | HeapType::NoExtern
1249            | HeapType::Func
1250            | HeapType::NoFunc
1251            | HeapType::Any
1252            | HeapType::Eq
1253            | HeapType::I31
1254            | HeapType::Array
1255            | HeapType::Struct
1256            | HeapType::Cont
1257            | HeapType::NoCont
1258            | HeapType::None => None,
1259        }
1260    }
1261
1262    #[inline]
1263    pub(crate) fn is_vmgcref_type(&self) -> bool {
1264        match self.top() {
1265            Self::Any | Self::Extern => true,
1266            Self::Func => false,
1267            Self::Cont => false,
1268            ty => unreachable!("not a top type: {ty:?}"),
1269        }
1270    }
1271
1272    /// Is this a `VMGcRef` type that is not i31 and is not an uninhabited
1273    /// bottom type?
1274    #[inline]
1275    pub(crate) fn is_vmgcref_type_and_points_to_object(&self) -> bool {
1276        self.is_vmgcref_type()
1277            && !matches!(
1278                self,
1279                HeapType::I31 | HeapType::NoExtern | HeapType::NoFunc | HeapType::None
1280            )
1281    }
1282}
1283
1284// External Types
1285
1286/// A list of all possible types which can be externally referenced from a
1287/// WebAssembly module.
1288///
1289/// This list can be found in [`ImportType`] or [`ExportType`], so these types
1290/// can either be imported or exported.
1291#[derive(Debug, Clone)]
1292pub enum ExternType {
1293    /// This external type is the type of a WebAssembly function.
1294    Func(FuncType),
1295    /// This external type is the type of a WebAssembly global.
1296    Global(GlobalType),
1297    /// This external type is the type of a WebAssembly table.
1298    Table(TableType),
1299    /// This external type is the type of a WebAssembly memory.
1300    Memory(MemoryType),
1301    /// This external type is the type of a WebAssembly tag.
1302    Tag(TagType),
1303}
1304
1305macro_rules! extern_type_accessors {
1306    ($(($variant:ident($ty:ty) $get:ident $unwrap:ident))*) => ($(
1307        /// Attempt to return the underlying type of this external type,
1308        /// returning `None` if it is a different type.
1309        pub fn $get(&self) -> Option<&$ty> {
1310            if let ExternType::$variant(e) = self {
1311                Some(e)
1312            } else {
1313                None
1314            }
1315        }
1316
1317        /// Returns the underlying descriptor of this [`ExternType`], panicking
1318        /// if it is a different type.
1319        ///
1320        /// # Panics
1321        ///
1322        /// Panics if `self` is not of the right type.
1323        pub fn $unwrap(&self) -> &$ty {
1324            self.$get().expect(concat!("expected ", stringify!($ty)))
1325        }
1326    )*)
1327}
1328
1329impl ExternType {
1330    extern_type_accessors! {
1331        (Func(FuncType) func unwrap_func)
1332        (Global(GlobalType) global unwrap_global)
1333        (Table(TableType) table unwrap_table)
1334        (Memory(MemoryType) memory unwrap_memory)
1335        (Tag(TagType) tag unwrap_tag)
1336    }
1337
1338    pub(crate) fn from_wasmtime(
1339        engine: &Engine,
1340        types: &ModuleTypes,
1341        ty: &EntityType,
1342    ) -> ExternType {
1343        match ty {
1344            EntityType::Function(idx) => match idx {
1345                EngineOrModuleTypeIndex::Engine(e) => {
1346                    FuncType::from_shared_type_index(engine, *e).into()
1347                }
1348                EngineOrModuleTypeIndex::Module(m) => {
1349                    let subty = &types[*m];
1350                    debug_assert!(subty.is_canonicalized_for_runtime_usage());
1351                    // subty.canonicalize_for_runtime_usage(&mut |idx| {
1352                    //     signatures.shared_type(idx).unwrap()
1353                    // });
1354                    FuncType::from_wasm_func_type(
1355                        engine,
1356                        subty.is_final,
1357                        subty.supertype,
1358                        subty.unwrap_func().clone(),
1359                    )
1360                    .into()
1361                }
1362                EngineOrModuleTypeIndex::RecGroup(_) => unreachable!(),
1363            },
1364            EntityType::Global(ty) => GlobalType::from_wasmtime_global(engine, ty).into(),
1365            EntityType::Memory(ty) => MemoryType::from_wasmtime_memory(ty).into(),
1366            EntityType::Table(ty) => TableType::from_wasmtime_table(engine, ty).into(),
1367            EntityType::Tag(ty) => TagType::from_wasmtime_tag(engine, ty).into(),
1368        }
1369    }
1370    /// Construct a default value, if possible for the underlying type. Tags do not have a default value.
1371    pub fn default_value(&self, store: impl AsContextMut) -> Result<Extern> {
1372        match self {
1373            ExternType::Func(func_ty) => func_ty.default_value(store).map(Extern::Func),
1374            ExternType::Global(global_ty) => global_ty.default_value(store).map(Extern::Global),
1375            ExternType::Table(table_ty) => table_ty.default_value(store).map(Extern::Table),
1376            ExternType::Memory(mem_ty) => mem_ty.default_value(store).map(Extern::Memory),
1377            ExternType::Tag(_) => bail!("default tags not supported yet"), // FIXME: #10252
1378        }
1379    }
1380}
1381
1382impl From<FuncType> for ExternType {
1383    fn from(ty: FuncType) -> ExternType {
1384        ExternType::Func(ty)
1385    }
1386}
1387
1388impl From<GlobalType> for ExternType {
1389    fn from(ty: GlobalType) -> ExternType {
1390        ExternType::Global(ty)
1391    }
1392}
1393
1394impl From<MemoryType> for ExternType {
1395    fn from(ty: MemoryType) -> ExternType {
1396        ExternType::Memory(ty)
1397    }
1398}
1399
1400impl From<TableType> for ExternType {
1401    fn from(ty: TableType) -> ExternType {
1402        ExternType::Table(ty)
1403    }
1404}
1405
1406impl From<TagType> for ExternType {
1407    fn from(ty: TagType) -> ExternType {
1408        ExternType::Tag(ty)
1409    }
1410}
1411
1412/// The storage type of a `struct` field or `array` element.
1413///
1414/// This is either a packed 8- or -16 bit integer, or else it is some unpacked
1415/// Wasm value type.
1416#[derive(Clone, Hash)]
1417pub enum StorageType {
1418    /// `i8`, an 8-bit integer.
1419    I8,
1420    /// `i16`, a 16-bit integer.
1421    I16,
1422    /// A value type.
1423    ValType(ValType),
1424}
1425
1426impl fmt::Display for StorageType {
1427    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1428        match self {
1429            StorageType::I8 => write!(f, "i8"),
1430            StorageType::I16 => write!(f, "i16"),
1431            StorageType::ValType(ty) => fmt::Display::fmt(ty, f),
1432        }
1433    }
1434}
1435
1436impl From<ValType> for StorageType {
1437    #[inline]
1438    fn from(v: ValType) -> Self {
1439        StorageType::ValType(v)
1440    }
1441}
1442
1443impl From<RefType> for StorageType {
1444    #[inline]
1445    fn from(r: RefType) -> Self {
1446        StorageType::ValType(r.into())
1447    }
1448}
1449
1450impl StorageType {
1451    /// Is this an `i8`?
1452    #[inline]
1453    pub fn is_i8(&self) -> bool {
1454        matches!(self, Self::I8)
1455    }
1456
1457    /// Is this an `i16`?
1458    #[inline]
1459    pub fn is_i16(&self) -> bool {
1460        matches!(self, Self::I16)
1461    }
1462
1463    /// Is this a Wasm value type?
1464    #[inline]
1465    pub fn is_val_type(&self) -> bool {
1466        matches!(self, Self::I16)
1467    }
1468
1469    /// Get this storage type's underlying value type, if any.
1470    ///
1471    /// Returns `None` if this storage type is not a value type.
1472    #[inline]
1473    pub fn as_val_type(&self) -> Option<&ValType> {
1474        match self {
1475            Self::ValType(v) => Some(v),
1476            _ => None,
1477        }
1478    }
1479
1480    /// Get this storage type's underlying value type, panicking if it is not a
1481    /// value type.
1482    pub fn unwrap_val_type(&self) -> &ValType {
1483        self.as_val_type().unwrap()
1484    }
1485
1486    /// Unpack this (possibly packed) storage type into a full `ValType`.
1487    ///
1488    /// If this is a `StorageType::ValType`, then the inner `ValType` is
1489    /// returned as-is.
1490    ///
1491    /// If this is a packed `StorageType::I8` or `StorageType::I16, then a
1492    /// `ValType::I32` is returned.
1493    pub fn unpack(&self) -> &ValType {
1494        match self {
1495            StorageType::I8 | StorageType::I16 => &ValType::I32,
1496            StorageType::ValType(ty) => ty,
1497        }
1498    }
1499
1500    /// Does this field type match the other field type?
1501    ///
1502    /// That is, is this field type a subtype of the other field type?
1503    ///
1504    /// # Panics
1505    ///
1506    /// Panics if either type is associated with a different engine from the
1507    /// other.
1508    pub fn matches(&self, other: &Self) -> bool {
1509        match (self, other) {
1510            (StorageType::I8, StorageType::I8) => true,
1511            (StorageType::I8, _) => false,
1512            (StorageType::I16, StorageType::I16) => true,
1513            (StorageType::I16, _) => false,
1514            (StorageType::ValType(a), StorageType::ValType(b)) => a.matches(b),
1515            (StorageType::ValType(_), _) => false,
1516        }
1517    }
1518
1519    /// Is field type `a` precisely equal to field type `b`?
1520    ///
1521    /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
1522    /// are not exactly the same field type.
1523    ///
1524    /// # Panics
1525    ///
1526    /// Panics if either type is associated with a different engine from the
1527    /// other.
1528    pub fn eq(a: &Self, b: &Self) -> bool {
1529        match (a, b) {
1530            (StorageType::I8, StorageType::I8) => true,
1531            (StorageType::I8, _) => false,
1532            (StorageType::I16, StorageType::I16) => true,
1533            (StorageType::I16, _) => false,
1534            (StorageType::ValType(a), StorageType::ValType(b)) => ValType::eq(a, b),
1535            (StorageType::ValType(_), _) => false,
1536        }
1537    }
1538
1539    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
1540        match self {
1541            StorageType::I8 | StorageType::I16 => true,
1542            StorageType::ValType(v) => v.comes_from_same_engine(engine),
1543        }
1544    }
1545
1546    pub(crate) fn from_wasm_storage_type(engine: &Engine, ty: &WasmStorageType) -> Self {
1547        match ty {
1548            WasmStorageType::I8 => Self::I8,
1549            WasmStorageType::I16 => Self::I16,
1550            WasmStorageType::Val(v) => ValType::from_wasm_type(engine, &v).into(),
1551        }
1552    }
1553
1554    pub(crate) fn to_wasm_storage_type(&self) -> WasmStorageType {
1555        match self {
1556            Self::I8 => WasmStorageType::I8,
1557            Self::I16 => WasmStorageType::I16,
1558            Self::ValType(v) => WasmStorageType::Val(v.to_wasm_type()),
1559        }
1560    }
1561
1562    /// The byte size of this type, if it has a defined size in the spec.
1563    ///
1564    /// See
1565    /// https://webassembly.github.io/gc/core/syntax/types.html#bitwidth-fieldtype
1566    /// and
1567    /// https://webassembly.github.io/gc/core/syntax/types.html#bitwidth-valtype
1568    #[cfg(feature = "gc")]
1569    pub(crate) fn data_byte_size(&self) -> Option<u32> {
1570        match self {
1571            StorageType::I8 => Some(1),
1572            StorageType::I16 => Some(2),
1573            StorageType::ValType(ValType::I32 | ValType::F32) => Some(4),
1574            StorageType::ValType(ValType::I64 | ValType::F64) => Some(8),
1575            StorageType::ValType(ValType::V128) => Some(16),
1576            StorageType::ValType(ValType::Ref(_)) => None,
1577        }
1578    }
1579}
1580
1581/// The type of a `struct` field or an `array`'s elements.
1582///
1583/// This is a pair of both the field's storage type and its mutability
1584/// (i.e. whether the field can be updated or not).
1585#[derive(Clone, Hash)]
1586pub struct FieldType {
1587    mutability: Mutability,
1588    element_type: StorageType,
1589}
1590
1591impl fmt::Display for FieldType {
1592    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1593        if self.mutability.is_var() {
1594            write!(f, "(mut {})", self.element_type)
1595        } else {
1596            fmt::Display::fmt(&self.element_type, f)
1597        }
1598    }
1599}
1600
1601impl FieldType {
1602    /// Construct a new field type from the given parts.
1603    #[inline]
1604    pub fn new(mutability: Mutability, element_type: StorageType) -> Self {
1605        Self {
1606            mutability,
1607            element_type,
1608        }
1609    }
1610
1611    /// Get whether or not this field type is mutable.
1612    #[inline]
1613    pub fn mutability(&self) -> Mutability {
1614        self.mutability
1615    }
1616
1617    /// Get this field type's storage type.
1618    #[inline]
1619    pub fn element_type(&self) -> &StorageType {
1620        &self.element_type
1621    }
1622
1623    /// Does this field type match the other field type?
1624    ///
1625    /// That is, is this field type a subtype of the other field type?
1626    ///
1627    /// # Panics
1628    ///
1629    /// Panics if either type is associated with a different engine from the
1630    /// other.
1631    pub fn matches(&self, other: &Self) -> bool {
1632        // Our storage type must match `other`'s storage type and either
1633        //
1634        // 1. Both field types are immutable, or
1635        //
1636        // 2. Both field types are mutable and `other`'s storage type must match
1637        //    ours, i.e. the storage types are exactly the same.
1638        use Mutability as M;
1639        match (self.mutability, other.mutability) {
1640            // Case 1
1641            (M::Const, M::Const) => self.element_type.matches(&other.element_type),
1642            // Case 2
1643            (M::Var, M::Var) => StorageType::eq(&self.element_type, &other.element_type),
1644            // Does not match.
1645            _ => false,
1646        }
1647    }
1648
1649    /// Is field type `a` precisely equal to field type `b`?
1650    ///
1651    /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
1652    /// are not exactly the same field type.
1653    ///
1654    /// # Panics
1655    ///
1656    /// Panics if either type is associated with a different engine from the
1657    /// other.
1658    pub fn eq(a: &Self, b: &Self) -> bool {
1659        a.matches(b) && b.matches(a)
1660    }
1661
1662    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
1663        self.element_type.comes_from_same_engine(engine)
1664    }
1665
1666    pub(crate) fn from_wasm_field_type(engine: &Engine, ty: &WasmFieldType) -> Self {
1667        Self {
1668            mutability: if ty.mutable {
1669                Mutability::Var
1670            } else {
1671                Mutability::Const
1672            },
1673            element_type: StorageType::from_wasm_storage_type(engine, &ty.element_type),
1674        }
1675    }
1676
1677    pub(crate) fn to_wasm_field_type(&self) -> WasmFieldType {
1678        WasmFieldType {
1679            element_type: self.element_type.to_wasm_storage_type(),
1680            mutable: matches!(self.mutability, Mutability::Var),
1681        }
1682    }
1683}
1684
1685/// The type of a WebAssembly struct.
1686///
1687/// WebAssembly structs are a static, fixed-length, ordered sequence of
1688/// fields. Fields are named by index, not an identifier. Each field is mutable
1689/// or constant and stores unpacked [`Val`][crate::Val]s or packed 8-/16-bit
1690/// integers.
1691///
1692/// # Subtyping and Equality
1693///
1694/// `StructType` does not implement `Eq`, because reference types have a
1695/// subtyping relationship, and so 99.99% of the time you actually want to check
1696/// whether one type matches (i.e. is a subtype of) another type. You can use
1697/// the [`StructType::matches`] method to perform these types of checks. If,
1698/// however, you are in that 0.01% scenario where you need to check precise
1699/// equality between types, you can use the [`StructType::eq`] method.
1700//
1701// TODO: Once we have struct values, update above docs with a reference to the
1702// future `Struct::matches_ty` method
1703#[derive(Debug, Clone, Hash)]
1704pub struct StructType {
1705    registered_type: RegisteredType,
1706}
1707
1708impl fmt::Display for StructType {
1709    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1710        write!(f, "(struct")?;
1711        for field in self.fields() {
1712            write!(f, " (field {field})")?;
1713        }
1714        write!(f, ")")?;
1715        Ok(())
1716    }
1717}
1718
1719impl StructType {
1720    /// Construct a new `StructType` with the given field types.
1721    ///
1722    /// This `StructType` will be final and without a supertype.
1723    ///
1724    /// The result will be associated with the given engine, and attempts to use
1725    /// it with other engines will panic (for example, checking whether it is a
1726    /// subtype of another struct type that is associated with a different
1727    /// engine).
1728    ///
1729    /// Returns an error if the number of fields exceeds the implementation
1730    /// limit.
1731    ///
1732    /// # Panics
1733    ///
1734    /// Panics if any given field type is not associated with the given engine.
1735    pub fn new(engine: &Engine, fields: impl IntoIterator<Item = FieldType>) -> Result<Self> {
1736        Self::with_finality_and_supertype(engine, Finality::Final, None, fields)
1737    }
1738
1739    /// Construct a new `StructType` with the given finality, supertype, and
1740    /// fields.
1741    ///
1742    /// The result will be associated with the given engine, and attempts to use
1743    /// it with other engines will panic (for example, checking whether it is a
1744    /// subtype of another struct type that is associated with a different
1745    /// engine).
1746    ///
1747    /// Returns an error if the number of fields exceeds the implementation
1748    /// limit, if the supertype is final, or if this type does not match the
1749    /// supertype.
1750    ///
1751    /// # Panics
1752    ///
1753    /// Panics if any given field type is not associated with the given engine.
1754    pub fn with_finality_and_supertype(
1755        engine: &Engine,
1756        finality: Finality,
1757        supertype: Option<&Self>,
1758        fields: impl IntoIterator<Item = FieldType>,
1759    ) -> Result<Self> {
1760        let fields = fields.into_iter();
1761
1762        let mut wasmtime_fields = Vec::with_capacity({
1763            let size_hint = fields.size_hint();
1764            let cap = size_hint.1.unwrap_or(size_hint.0);
1765            // Only reserve space if we have a supertype, as that is the only time
1766            // that this vec is used.
1767            supertype.is_some() as usize * cap
1768        });
1769
1770        // Same as in `FuncType::new`: we must prevent any `RegisteredType`s
1771        // from being reclaimed while constructing this struct type.
1772        let mut registrations = smallvec::SmallVec::<[_; 4]>::new();
1773
1774        let fields = fields
1775            .map(|ty: FieldType| {
1776                assert!(ty.comes_from_same_engine(engine));
1777
1778                if supertype.is_some() {
1779                    wasmtime_fields.push(ty.clone());
1780                }
1781
1782                if let Some(r) = ty.element_type.as_val_type().and_then(|v| v.as_ref()) {
1783                    if let Some(r) = r.heap_type().as_registered_type() {
1784                        registrations.push(r.clone());
1785                    }
1786                }
1787
1788                ty.to_wasm_field_type()
1789            })
1790            .collect();
1791
1792        if let Some(supertype) = supertype {
1793            ensure!(
1794                supertype.finality().is_non_final(),
1795                "cannot create a subtype of a final supertype"
1796            );
1797            ensure!(
1798                Self::fields_match(wasmtime_fields.into_iter(), supertype.fields()),
1799                "struct fields must match their supertype's fields"
1800            );
1801        }
1802
1803        Self::from_wasm_struct_type(
1804            engine,
1805            finality.is_final(),
1806            false,
1807            supertype.map(|ty| ty.type_index().into()),
1808            WasmStructType { fields },
1809        )
1810    }
1811
1812    /// Get the engine that this struct type is associated with.
1813    pub fn engine(&self) -> &Engine {
1814        self.registered_type.engine()
1815    }
1816
1817    /// Get the finality of this struct type.
1818    pub fn finality(&self) -> Finality {
1819        match self.registered_type.is_final {
1820            true => Finality::Final,
1821            false => Finality::NonFinal,
1822        }
1823    }
1824
1825    /// Get the supertype of this struct type, if any.
1826    pub fn supertype(&self) -> Option<Self> {
1827        self.registered_type
1828            .supertype
1829            .map(|ty| Self::from_shared_type_index(self.engine(), ty.unwrap_engine_type_index()))
1830    }
1831
1832    /// Get the `i`th field type.
1833    ///
1834    /// Returns `None` if `i` is out of bounds.
1835    pub fn field(&self, i: usize) -> Option<FieldType> {
1836        let engine = self.engine();
1837        self.as_wasm_struct_type()
1838            .fields
1839            .get(i)
1840            .map(|ty| FieldType::from_wasm_field_type(engine, ty))
1841    }
1842
1843    /// Returns the list of field types for this function.
1844    #[inline]
1845    pub fn fields(&self) -> impl ExactSizeIterator<Item = FieldType> + '_ {
1846        let engine = self.engine();
1847        self.as_wasm_struct_type()
1848            .fields
1849            .iter()
1850            .map(|ty| FieldType::from_wasm_field_type(engine, ty))
1851    }
1852
1853    /// Does this struct type match the other struct type?
1854    ///
1855    /// That is, is this function type a subtype of the other struct type?
1856    ///
1857    /// # Panics
1858    ///
1859    /// Panics if either type is associated with a different engine from the
1860    /// other.
1861    pub fn matches(&self, other: &StructType) -> bool {
1862        assert!(self.comes_from_same_engine(other.engine()));
1863
1864        self.engine()
1865            .signatures()
1866            .is_subtype(self.type_index(), other.type_index())
1867    }
1868
1869    fn fields_match(
1870        a: impl ExactSizeIterator<Item = FieldType>,
1871        b: impl ExactSizeIterator<Item = FieldType>,
1872    ) -> bool {
1873        a.len() >= b.len() && a.zip(b).all(|(a, b)| a.matches(&b))
1874    }
1875
1876    /// Is struct type `a` precisely equal to struct type `b`?
1877    ///
1878    /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
1879    /// are not exactly the same struct type.
1880    ///
1881    /// # Panics
1882    ///
1883    /// Panics if either type is associated with a different engine from the
1884    /// other.
1885    pub fn eq(a: &StructType, b: &StructType) -> bool {
1886        assert!(a.comes_from_same_engine(b.engine()));
1887        a.type_index() == b.type_index()
1888    }
1889
1890    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
1891        Engine::same(self.registered_type().engine(), engine)
1892    }
1893
1894    pub(crate) fn type_index(&self) -> VMSharedTypeIndex {
1895        self.registered_type().index()
1896    }
1897
1898    pub(crate) fn as_wasm_struct_type(&self) -> &WasmStructType {
1899        self.registered_type().unwrap_struct()
1900    }
1901
1902    pub(crate) fn registered_type(&self) -> &RegisteredType {
1903        &self.registered_type
1904    }
1905
1906    /// Construct a `StructType` from a `WasmStructType`.
1907    ///
1908    /// This method should only be used when something has already registered --
1909    /// and is *keeping registered* -- any other concrete Wasm types referenced
1910    /// by the given `WasmStructType`.
1911    ///
1912    /// For example, this method may be called to convert an struct type from
1913    /// within a Wasm module's `ModuleTypes` since the Wasm module itself is
1914    /// holding a strong reference to all of its types, including any `(ref null
1915    /// <index>)` types used as the element type for this struct type.
1916    pub(crate) fn from_wasm_struct_type(
1917        engine: &Engine,
1918        is_final: bool,
1919        is_shared: bool,
1920        supertype: Option<EngineOrModuleTypeIndex>,
1921        ty: WasmStructType,
1922    ) -> Result<StructType> {
1923        const MAX_FIELDS: usize = 10_000;
1924        let fields_len = ty.fields.len();
1925        ensure!(
1926            fields_len <= MAX_FIELDS,
1927            "attempted to define a struct type with {fields_len} fields, but \
1928             that is more than the maximum supported number of fields \
1929             ({MAX_FIELDS})",
1930        );
1931
1932        let ty = RegisteredType::new(
1933            engine,
1934            WasmSubType {
1935                is_final,
1936                supertype,
1937                composite_type: WasmCompositeType {
1938                    shared: is_shared,
1939                    inner: WasmCompositeInnerType::Struct(ty),
1940                },
1941            },
1942        );
1943        Ok(Self {
1944            registered_type: ty,
1945        })
1946    }
1947
1948    pub(crate) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> StructType {
1949        let ty = RegisteredType::root(engine, index);
1950        Self::from_registered_type(ty)
1951    }
1952
1953    pub(crate) fn from_registered_type(registered_type: RegisteredType) -> Self {
1954        debug_assert!(registered_type.is_struct());
1955        Self { registered_type }
1956    }
1957}
1958
1959/// The type of a WebAssembly array.
1960///
1961/// WebAssembly arrays are dynamically-sized, but not resizable. They contain
1962/// either unpacked [`Val`][crate::Val]s or packed 8-/16-bit integers.
1963///
1964/// # Subtyping and Equality
1965///
1966/// `ArrayType` does not implement `Eq`, because reference types have a
1967/// subtyping relationship, and so 99.99% of the time you actually want to check
1968/// whether one type matches (i.e. is a subtype of) another type. You can use
1969/// the [`ArrayType::matches`] method to perform these types of checks. If,
1970/// however, you are in that 0.01% scenario where you need to check precise
1971/// equality between types, you can use the [`ArrayType::eq`] method.
1972//
1973// TODO: Once we have array values, update above docs with a reference to the
1974// future `Array::matches_ty` method
1975#[derive(Debug, Clone, Hash)]
1976pub struct ArrayType {
1977    registered_type: RegisteredType,
1978}
1979
1980impl fmt::Display for ArrayType {
1981    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1982        let field_ty = self.field_type();
1983        write!(f, "(array (field {field_ty}))")?;
1984        Ok(())
1985    }
1986}
1987
1988impl ArrayType {
1989    /// Construct a new `ArrayType` with the given field type's mutability and
1990    /// storage type.
1991    ///
1992    /// The new `ArrayType` will be final and without a supertype.
1993    ///
1994    /// The result will be associated with the given engine, and attempts to use
1995    /// it with other engines will panic (for example, checking whether it is a
1996    /// subtype of another array type that is associated with a different
1997    /// engine).
1998    ///
1999    /// # Panics
2000    ///
2001    /// Panics if the given field type is not associated with the given engine.
2002    pub fn new(engine: &Engine, field_type: FieldType) -> Self {
2003        Self::with_finality_and_supertype(engine, Finality::Final, None, field_type)
2004            .expect("cannot fail without a supertype")
2005    }
2006
2007    /// Construct a new `StructType` with the given finality, supertype, and
2008    /// fields.
2009    ///
2010    /// The result will be associated with the given engine, and attempts to use
2011    /// it with other engines will panic (for example, checking whether it is a
2012    /// subtype of another struct type that is associated with a different
2013    /// engine).
2014    ///
2015    /// Returns an error if the supertype is final, or if this type does not
2016    /// match the supertype.
2017    ///
2018    /// # Panics
2019    ///
2020    /// Panics if the given field type is not associated with the given engine.
2021    pub fn with_finality_and_supertype(
2022        engine: &Engine,
2023        finality: Finality,
2024        supertype: Option<&Self>,
2025        field_type: FieldType,
2026    ) -> Result<Self> {
2027        if let Some(supertype) = supertype {
2028            assert!(supertype.comes_from_same_engine(engine));
2029            ensure!(
2030                supertype.finality().is_non_final(),
2031                "cannot create a subtype of a final supertype"
2032            );
2033            ensure!(
2034                field_type.matches(&supertype.field_type()),
2035                "array field type must match its supertype's field type"
2036            );
2037        }
2038
2039        // Same as in `FuncType::new`: we must prevent any `RegisteredType` in
2040        // `field_type` from being reclaimed while constructing this array type.
2041        let _registration = field_type
2042            .element_type
2043            .as_val_type()
2044            .and_then(|v| v.as_ref())
2045            .and_then(|r| r.heap_type().as_registered_type());
2046
2047        assert!(field_type.comes_from_same_engine(engine));
2048        let wasm_ty = WasmArrayType(field_type.to_wasm_field_type());
2049
2050        Ok(Self::from_wasm_array_type(
2051            engine,
2052            finality.is_final(),
2053            supertype.map(|ty| ty.type_index().into()),
2054            wasm_ty,
2055        ))
2056    }
2057
2058    /// Get the engine that this array type is associated with.
2059    pub fn engine(&self) -> &Engine {
2060        self.registered_type.engine()
2061    }
2062
2063    /// Get the finality of this array type.
2064    pub fn finality(&self) -> Finality {
2065        match self.registered_type.is_final {
2066            true => Finality::Final,
2067            false => Finality::NonFinal,
2068        }
2069    }
2070
2071    /// Get the supertype of this array type, if any.
2072    pub fn supertype(&self) -> Option<Self> {
2073        self.registered_type
2074            .supertype
2075            .map(|ty| Self::from_shared_type_index(self.engine(), ty.unwrap_engine_type_index()))
2076    }
2077
2078    /// Get this array's underlying field type.
2079    ///
2080    /// The field type contains information about both this array type's
2081    /// mutability and the storage type used for its elements.
2082    pub fn field_type(&self) -> FieldType {
2083        FieldType::from_wasm_field_type(self.engine(), &self.as_wasm_array_type().0)
2084    }
2085
2086    /// Get this array type's mutability and whether its instances' elements can
2087    /// be updated or not.
2088    ///
2089    /// This is a convenience method providing a short-hand for
2090    /// `my_array_type.field_type().mutability()`.
2091    pub fn mutability(&self) -> Mutability {
2092        if self.as_wasm_array_type().0.mutable {
2093            Mutability::Var
2094        } else {
2095            Mutability::Const
2096        }
2097    }
2098
2099    /// Get the storage type used for this array type's elements.
2100    ///
2101    /// This is a convenience method providing a short-hand for
2102    /// `my_array_type.field_type().element_type()`.
2103    pub fn element_type(&self) -> StorageType {
2104        StorageType::from_wasm_storage_type(
2105            self.engine(),
2106            &self.registered_type.unwrap_array().0.element_type,
2107        )
2108    }
2109
2110    /// Does this array type match the other array type?
2111    ///
2112    /// That is, is this function type a subtype of the other array type?
2113    ///
2114    /// # Panics
2115    ///
2116    /// Panics if either type is associated with a different engine from the
2117    /// other.
2118    pub fn matches(&self, other: &ArrayType) -> bool {
2119        assert!(self.comes_from_same_engine(other.engine()));
2120
2121        self.engine()
2122            .signatures()
2123            .is_subtype(self.type_index(), other.type_index())
2124    }
2125
2126    /// Is array type `a` precisely equal to array type `b`?
2127    ///
2128    /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
2129    /// are not exactly the same array type.
2130    ///
2131    /// # Panics
2132    ///
2133    /// Panics if either type is associated with a different engine from the
2134    /// other.
2135    pub fn eq(a: &ArrayType, b: &ArrayType) -> bool {
2136        assert!(a.comes_from_same_engine(b.engine()));
2137        a.type_index() == b.type_index()
2138    }
2139
2140    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
2141        Engine::same(self.registered_type.engine(), engine)
2142    }
2143
2144    #[cfg(feature = "gc")]
2145    pub(crate) fn registered_type(&self) -> &RegisteredType {
2146        &self.registered_type
2147    }
2148
2149    pub(crate) fn type_index(&self) -> VMSharedTypeIndex {
2150        self.registered_type.index()
2151    }
2152
2153    pub(crate) fn as_wasm_array_type(&self) -> &WasmArrayType {
2154        self.registered_type.unwrap_array()
2155    }
2156
2157    /// Construct a `ArrayType` from a `WasmArrayType`.
2158    ///
2159    /// This method should only be used when something has already registered --
2160    /// and is *keeping registered* -- any other concrete Wasm types referenced
2161    /// by the given `WasmArrayType`.
2162    ///
2163    /// For example, this method may be called to convert an array type from
2164    /// within a Wasm module's `ModuleTypes` since the Wasm module itself is
2165    /// holding a strong reference to all of its types, including any `(ref null
2166    /// <index>)` types used as the element type for this array type.
2167    pub(crate) fn from_wasm_array_type(
2168        engine: &Engine,
2169        is_final: bool,
2170        supertype: Option<EngineOrModuleTypeIndex>,
2171        ty: WasmArrayType,
2172    ) -> ArrayType {
2173        let ty = RegisteredType::new(
2174            engine,
2175            WasmSubType {
2176                is_final,
2177                supertype,
2178                composite_type: WasmCompositeType {
2179                    shared: false,
2180                    inner: WasmCompositeInnerType::Array(ty),
2181                },
2182            },
2183        );
2184        Self {
2185            registered_type: ty,
2186        }
2187    }
2188
2189    pub(crate) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> ArrayType {
2190        let ty = RegisteredType::root(engine, index);
2191        Self::from_registered_type(ty)
2192    }
2193
2194    pub(crate) fn from_registered_type(registered_type: RegisteredType) -> Self {
2195        debug_assert!(registered_type.is_array());
2196        Self { registered_type }
2197    }
2198}
2199
2200/// The type of a WebAssembly function.
2201///
2202/// WebAssembly functions can have 0 or more parameters and results.
2203///
2204/// # Subtyping and Equality
2205///
2206/// `FuncType` does not implement `Eq`, because reference types have a subtyping
2207/// relationship, and so 99.99% of the time you actually want to check whether
2208/// one type matches (i.e. is a subtype of) another type. You can use the
2209/// [`FuncType::matches`] and [`Func::matches_ty`][crate::Func::matches_ty]
2210/// methods to perform these types of checks. If, however, you are in that 0.01%
2211/// scenario where you need to check precise equality between types, you can use
2212/// the [`FuncType::eq`] method.
2213#[derive(Debug, Clone, Hash)]
2214pub struct FuncType {
2215    registered_type: RegisteredType,
2216}
2217
2218impl Display for FuncType {
2219    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2220        write!(f, "(type (func")?;
2221        if self.params().len() > 0 {
2222            write!(f, " (param")?;
2223            for p in self.params() {
2224                write!(f, " {p}")?;
2225            }
2226            write!(f, ")")?;
2227        }
2228        if self.results().len() > 0 {
2229            write!(f, " (result")?;
2230            for r in self.results() {
2231                write!(f, " {r}")?;
2232            }
2233            write!(f, ")")?;
2234        }
2235        write!(f, "))")
2236    }
2237}
2238
2239impl FuncType {
2240    /// Creates a new function type from the given parameters and results.
2241    ///
2242    /// The function type returned will represent a function which takes
2243    /// `params` as arguments and returns `results` when it is finished.
2244    ///
2245    /// The resulting function type will be final and without a supertype.
2246    ///
2247    /// # Panics
2248    ///
2249    /// Panics if any parameter or value type is not associated with the given
2250    /// engine.
2251    pub fn new(
2252        engine: &Engine,
2253        params: impl IntoIterator<Item = ValType>,
2254        results: impl IntoIterator<Item = ValType>,
2255    ) -> FuncType {
2256        Self::with_finality_and_supertype(engine, Finality::Final, None, params, results)
2257            .expect("cannot fail without a supertype")
2258    }
2259
2260    /// Create a new function type with the given finality, supertype, parameter
2261    /// types, and result types.
2262    ///
2263    /// Returns an error if the supertype is final, or if this function type
2264    /// does not match the supertype.
2265    ///
2266    /// # Panics
2267    ///
2268    /// Panics if any parameter or value type is not associated with the given
2269    /// engine.
2270    pub fn with_finality_and_supertype(
2271        engine: &Engine,
2272        finality: Finality,
2273        supertype: Option<&Self>,
2274        params: impl IntoIterator<Item = ValType>,
2275        results: impl IntoIterator<Item = ValType>,
2276    ) -> Result<Self> {
2277        let params = params.into_iter();
2278        let results = results.into_iter();
2279
2280        let mut wasmtime_params = Vec::with_capacity({
2281            let size_hint = params.size_hint();
2282            let cap = size_hint.1.unwrap_or(size_hint.0);
2283            // Only reserve space if we have a supertype, as that is the only time
2284            // that this vec is used.
2285            supertype.is_some() as usize * cap
2286        });
2287
2288        let mut wasmtime_results = Vec::with_capacity({
2289            let size_hint = results.size_hint();
2290            let cap = size_hint.1.unwrap_or(size_hint.0);
2291            // Same as above.
2292            supertype.is_some() as usize * cap
2293        });
2294
2295        // Keep any of our parameters' and results' `RegisteredType`s alive
2296        // across `Self::from_wasm_func_type`. If one of our given `ValType`s is
2297        // the only thing keeping a type in the registry, we don't want to
2298        // unregister it when we convert the `ValType` into a `WasmValType` just
2299        // before we register our new `WasmFuncType` that will reference it.
2300        let mut registrations = smallvec::SmallVec::<[_; 4]>::new();
2301
2302        let mut to_wasm_type = |ty: ValType, vec: &mut Vec<_>| {
2303            assert!(ty.comes_from_same_engine(engine));
2304
2305            if supertype.is_some() {
2306                vec.push(ty.clone());
2307            }
2308
2309            if let Some(r) = ty.as_ref() {
2310                if let Some(r) = r.heap_type().as_registered_type() {
2311                    registrations.push(r.clone());
2312                }
2313            }
2314
2315            ty.to_wasm_type()
2316        };
2317
2318        let wasm_func_ty = WasmFuncType::new(
2319            params
2320                .map(|p| to_wasm_type(p, &mut wasmtime_params))
2321                .collect(),
2322            results
2323                .map(|r| to_wasm_type(r, &mut wasmtime_results))
2324                .collect(),
2325        );
2326
2327        if let Some(supertype) = supertype {
2328            assert!(supertype.comes_from_same_engine(engine));
2329            ensure!(
2330                supertype.finality().is_non_final(),
2331                "cannot create a subtype of a final supertype"
2332            );
2333            ensure!(
2334                Self::matches_impl(
2335                    wasmtime_params.iter().cloned(),
2336                    supertype.params(),
2337                    wasmtime_results.iter().cloned(),
2338                    supertype.results()
2339                ),
2340                "function type must match its supertype: found (func{params}{results}), expected \
2341                 {supertype}",
2342                params = if wasmtime_params.is_empty() {
2343                    String::new()
2344                } else {
2345                    let mut s = format!(" (params");
2346                    for p in &wasmtime_params {
2347                        write!(&mut s, " {p}").unwrap();
2348                    }
2349                    s.push(')');
2350                    s
2351                },
2352                results = if wasmtime_results.is_empty() {
2353                    String::new()
2354                } else {
2355                    let mut s = format!(" (results");
2356                    for r in &wasmtime_results {
2357                        write!(&mut s, " {r}").unwrap();
2358                    }
2359                    s.push(')');
2360                    s
2361                },
2362            );
2363        }
2364
2365        Ok(Self::from_wasm_func_type(
2366            engine,
2367            finality.is_final(),
2368            supertype.map(|ty| ty.type_index().into()),
2369            wasm_func_ty,
2370        ))
2371    }
2372
2373    /// Get the engine that this function type is associated with.
2374    pub fn engine(&self) -> &Engine {
2375        self.registered_type.engine()
2376    }
2377
2378    /// Get the finality of this function type.
2379    pub fn finality(&self) -> Finality {
2380        match self.registered_type.is_final {
2381            true => Finality::Final,
2382            false => Finality::NonFinal,
2383        }
2384    }
2385
2386    /// Get the supertype of this function type, if any.
2387    pub fn supertype(&self) -> Option<Self> {
2388        self.registered_type
2389            .supertype
2390            .map(|ty| Self::from_shared_type_index(self.engine(), ty.unwrap_engine_type_index()))
2391    }
2392
2393    /// Get the `i`th parameter type.
2394    ///
2395    /// Returns `None` if `i` is out of bounds.
2396    pub fn param(&self, i: usize) -> Option<ValType> {
2397        let engine = self.engine();
2398        self.registered_type
2399            .unwrap_func()
2400            .params()
2401            .get(i)
2402            .map(|ty| ValType::from_wasm_type(engine, ty))
2403    }
2404
2405    /// Returns the list of parameter types for this function.
2406    #[inline]
2407    pub fn params(&self) -> impl ExactSizeIterator<Item = ValType> + '_ {
2408        let engine = self.engine();
2409        self.registered_type
2410            .unwrap_func()
2411            .params()
2412            .iter()
2413            .map(|ty| ValType::from_wasm_type(engine, ty))
2414    }
2415
2416    /// Get the `i`th result type.
2417    ///
2418    /// Returns `None` if `i` is out of bounds.
2419    pub fn result(&self, i: usize) -> Option<ValType> {
2420        let engine = self.engine();
2421        self.registered_type
2422            .unwrap_func()
2423            .returns()
2424            .get(i)
2425            .map(|ty| ValType::from_wasm_type(engine, ty))
2426    }
2427
2428    /// Returns the list of result types for this function.
2429    #[inline]
2430    pub fn results(&self) -> impl ExactSizeIterator<Item = ValType> + '_ {
2431        let engine = self.engine();
2432        self.registered_type
2433            .unwrap_func()
2434            .returns()
2435            .iter()
2436            .map(|ty| ValType::from_wasm_type(engine, ty))
2437    }
2438
2439    /// Does this function type match the other function type?
2440    ///
2441    /// That is, is this function type a subtype of the other function type?
2442    ///
2443    /// # Panics
2444    ///
2445    /// Panics if either type is associated with a different engine from the
2446    /// other.
2447    pub fn matches(&self, other: &FuncType) -> bool {
2448        assert!(self.comes_from_same_engine(other.engine()));
2449
2450        // Avoid matching on structure for subtyping checks when we have
2451        // precisely the same type.
2452        if self.type_index() == other.type_index() {
2453            return true;
2454        }
2455
2456        Self::matches_impl(
2457            self.params(),
2458            other.params(),
2459            self.results(),
2460            other.results(),
2461        )
2462    }
2463
2464    fn matches_impl(
2465        a_params: impl ExactSizeIterator<Item = ValType>,
2466        b_params: impl ExactSizeIterator<Item = ValType>,
2467        a_results: impl ExactSizeIterator<Item = ValType>,
2468        b_results: impl ExactSizeIterator<Item = ValType>,
2469    ) -> bool {
2470        a_params.len() == b_params.len()
2471            && a_results.len() == b_results.len()
2472            // Params are contravariant and results are covariant. For more
2473            // details and a refresher on variance, read
2474            // https://github.com/bytecodealliance/wasm-tools/blob/f1d89a4/crates/wasmparser/src/readers/core/types/matches.rs#L137-L174
2475            && a_params
2476                .zip(b_params)
2477                .all(|(a, b)| b.matches(&a))
2478            && a_results
2479                .zip(b_results)
2480                .all(|(a, b)| a.matches(&b))
2481    }
2482
2483    /// Is function type `a` precisely equal to function type `b`?
2484    ///
2485    /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
2486    /// are not exactly the same function type.
2487    ///
2488    /// # Panics
2489    ///
2490    /// Panics if either type is associated with a different engine from the
2491    /// other.
2492    pub fn eq(a: &FuncType, b: &FuncType) -> bool {
2493        assert!(a.comes_from_same_engine(b.engine()));
2494        a.type_index() == b.type_index()
2495    }
2496
2497    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
2498        Engine::same(self.registered_type.engine(), engine)
2499    }
2500
2501    pub(crate) fn type_index(&self) -> VMSharedTypeIndex {
2502        self.registered_type.index()
2503    }
2504
2505    #[cfg(feature = "gc")]
2506    #[inline]
2507    pub(crate) fn as_wasm_func_type(&self) -> &WasmFuncType {
2508        self.registered_type.unwrap_func()
2509    }
2510
2511    pub(crate) fn into_registered_type(self) -> RegisteredType {
2512        self.registered_type
2513    }
2514
2515    /// Construct a `FuncType` from a `WasmFuncType`.
2516    ///
2517    /// This method should only be used when something has already registered --
2518    /// and is *keeping registered* -- any other concrete Wasm types referenced
2519    /// by the given `WasmFuncType`.
2520    ///
2521    /// For example, this method may be called to convert a function type from
2522    /// within a Wasm module's `ModuleTypes` since the Wasm module itself is
2523    /// holding a strong reference to all of its types, including any `(ref null
2524    /// <index>)` types used in the function's parameters and results.
2525    pub(crate) fn from_wasm_func_type(
2526        engine: &Engine,
2527        is_final: bool,
2528        supertype: Option<EngineOrModuleTypeIndex>,
2529        ty: WasmFuncType,
2530    ) -> FuncType {
2531        let ty = RegisteredType::new(
2532            engine,
2533            WasmSubType {
2534                is_final,
2535                supertype,
2536                composite_type: WasmCompositeType {
2537                    shared: false,
2538                    inner: WasmCompositeInnerType::Func(ty),
2539                },
2540            },
2541        );
2542        Self {
2543            registered_type: ty,
2544        }
2545    }
2546
2547    pub(crate) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> FuncType {
2548        let ty = RegisteredType::root(engine, index);
2549        Self::from_registered_type(ty)
2550    }
2551
2552    pub(crate) fn from_registered_type(registered_type: RegisteredType) -> Self {
2553        debug_assert!(registered_type.is_func());
2554        Self { registered_type }
2555    }
2556    /// Construct a func which returns results of default value, if each result type has a default value.
2557    pub fn default_value(&self, mut store: impl AsContextMut) -> Result<Func> {
2558        let dummy_results = self
2559            .results()
2560            .map(|ty| ty.default_value())
2561            .collect::<Option<Vec<_>>>()
2562            .ok_or_else(|| anyhow!("function results do not have a default value"))?;
2563        Ok(Func::new(&mut store, self.clone(), move |_, _, results| {
2564            for (slot, dummy) in results.iter_mut().zip(dummy_results.iter()) {
2565                *slot = *dummy;
2566            }
2567            Ok(())
2568        }))
2569    }
2570}
2571
2572// Continuation types
2573/// A WebAssembly continuation descriptor.
2574#[derive(Debug, Clone, Hash)]
2575pub struct ContType {
2576    registered_type: RegisteredType,
2577}
2578
2579impl ContType {
2580    /// Get the engine that this function type is associated with.
2581    pub fn engine(&self) -> &Engine {
2582        self.registered_type.engine()
2583    }
2584
2585    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
2586        Engine::same(self.registered_type.engine(), engine)
2587    }
2588
2589    pub(crate) fn type_index(&self) -> VMSharedTypeIndex {
2590        self.registered_type.index()
2591    }
2592
2593    /// Does this continuation type match the other continuation type?
2594    ///
2595    /// That is, is this continuation type a subtype of the other continuation type?
2596    ///
2597    /// # Panics
2598    ///
2599    /// Panics if either type is associated with a different engine from the
2600    /// other.
2601    pub fn matches(&self, other: &ContType) -> bool {
2602        assert!(self.comes_from_same_engine(other.engine()));
2603
2604        // Avoid matching on structure for subtyping checks when we have
2605        // precisely the same type.
2606        // TODO(dhil): Implement subtype check later.
2607        self.type_index() == other.type_index()
2608    }
2609
2610    pub(crate) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> ContType {
2611        let ty = RegisteredType::root(engine, index);
2612        assert!(ty.is_cont());
2613        Self {
2614            registered_type: ty,
2615        }
2616    }
2617}
2618
2619// Global Types
2620
2621/// A WebAssembly global descriptor.
2622///
2623/// This type describes an instance of a global in a WebAssembly module. Globals
2624/// are local to an [`Instance`](crate::Instance) and are either immutable or
2625/// mutable.
2626#[derive(Debug, Clone, Hash)]
2627pub struct GlobalType {
2628    content: ValType,
2629    mutability: Mutability,
2630}
2631
2632impl GlobalType {
2633    /// Creates a new global descriptor of the specified `content` type and
2634    /// whether or not it's mutable.
2635    pub fn new(content: ValType, mutability: Mutability) -> GlobalType {
2636        GlobalType {
2637            content,
2638            mutability,
2639        }
2640    }
2641
2642    /// Returns the value type of this global descriptor.
2643    pub fn content(&self) -> &ValType {
2644        &self.content
2645    }
2646
2647    /// Returns whether or not this global is mutable.
2648    pub fn mutability(&self) -> Mutability {
2649        self.mutability
2650    }
2651
2652    /// Returns `None` if the wasmtime global has a type that we can't
2653    /// represent, but that should only very rarely happen and indicate a bug.
2654    pub(crate) fn from_wasmtime_global(engine: &Engine, global: &Global) -> GlobalType {
2655        let ty = ValType::from_wasm_type(engine, &global.wasm_ty);
2656        let mutability = if global.mutability {
2657            Mutability::Var
2658        } else {
2659            Mutability::Const
2660        };
2661        GlobalType::new(ty, mutability)
2662    }
2663    ///
2664    pub fn default_value(&self, store: impl AsContextMut) -> Result<RuntimeGlobal> {
2665        let val = self
2666            .content()
2667            .default_value()
2668            .ok_or_else(|| anyhow!("global type has no default value"))?;
2669        RuntimeGlobal::new(store, self.clone(), val)
2670    }
2671}
2672
2673// Tag Types
2674
2675/// A descriptor for a tag in a WebAssembly module.
2676///
2677/// This type describes an instance of a tag in a WebAssembly
2678/// module. Tags are local to an [`Instance`](crate::Instance).
2679#[derive(Debug, Clone, Hash)]
2680pub struct TagType {
2681    ty: FuncType,
2682}
2683
2684impl TagType {
2685    /// Creates a new global descriptor of the specified type.
2686    pub fn new(ty: FuncType) -> TagType {
2687        TagType { ty }
2688    }
2689
2690    /// Returns the underlying function type of this tag descriptor.
2691    pub fn ty(&self) -> &FuncType {
2692        &self.ty
2693    }
2694
2695    pub(crate) fn from_wasmtime_tag(engine: &Engine, tag: &Tag) -> TagType {
2696        let ty = FuncType::from_shared_type_index(engine, tag.signature.unwrap_engine_type_index());
2697        TagType { ty }
2698    }
2699}
2700
2701// Table Types
2702
2703/// A descriptor for a table in a WebAssembly module.
2704///
2705/// Tables are contiguous chunks of a specific element, typically a `funcref` or
2706/// an `externref`. The most common use for tables is a function table through
2707/// which `call_indirect` can invoke other functions.
2708#[derive(Debug, Clone, Hash)]
2709pub struct TableType {
2710    // Keep a `wasmtime::RefType` so that `TableType::element` doesn't need to
2711    // take an `&Engine`.
2712    element: RefType,
2713    ty: Table,
2714}
2715
2716impl TableType {
2717    /// Creates a new table descriptor which will contain the specified
2718    /// `element` and have the `limits` applied to its length.
2719    pub fn new(element: RefType, min: u32, max: Option<u32>) -> TableType {
2720        let ref_type = element.to_wasm_type();
2721
2722        debug_assert!(
2723            ref_type.is_canonicalized_for_runtime_usage(),
2724            "should be canonicalized for runtime usage: {ref_type:?}"
2725        );
2726
2727        let limits = Limits {
2728            min: u64::from(min),
2729            max: max.map(|x| u64::from(x)),
2730        };
2731
2732        TableType {
2733            element,
2734            ty: Table {
2735                idx_type: IndexType::I32,
2736                limits,
2737                ref_type,
2738            },
2739        }
2740    }
2741
2742    /// Crates a new descriptor for a 64-bit table.
2743    ///
2744    /// Note that 64-bit tables are part of the memory64 proposal for
2745    /// WebAssembly which is not standardized yet.
2746    pub fn new64(element: RefType, min: u64, max: Option<u64>) -> TableType {
2747        let ref_type = element.to_wasm_type();
2748
2749        debug_assert!(
2750            ref_type.is_canonicalized_for_runtime_usage(),
2751            "should be canonicalized for runtime usage: {ref_type:?}"
2752        );
2753
2754        TableType {
2755            element,
2756            ty: Table {
2757                ref_type,
2758                idx_type: IndexType::I64,
2759                limits: Limits { min, max },
2760            },
2761        }
2762    }
2763
2764    /// Returns whether or not this table is a 64-bit table.
2765    ///
2766    /// Note that 64-bit tables are part of the memory64 proposal for
2767    /// WebAssembly which is not standardized yet.
2768    pub fn is_64(&self) -> bool {
2769        matches!(self.ty.idx_type, IndexType::I64)
2770    }
2771
2772    /// Returns the element value type of this table.
2773    pub fn element(&self) -> &RefType {
2774        &self.element
2775    }
2776
2777    /// Returns minimum number of elements this table must have
2778    pub fn minimum(&self) -> u64 {
2779        self.ty.limits.min
2780    }
2781
2782    /// Returns the optionally-specified maximum number of elements this table
2783    /// can have.
2784    ///
2785    /// If this returns `None` then the table is not limited in size.
2786    pub fn maximum(&self) -> Option<u64> {
2787        self.ty.limits.max
2788    }
2789
2790    pub(crate) fn from_wasmtime_table(engine: &Engine, table: &Table) -> TableType {
2791        let element = RefType::from_wasm_type(engine, &table.ref_type);
2792        TableType {
2793            element,
2794            ty: *table,
2795        }
2796    }
2797
2798    pub(crate) fn wasmtime_table(&self) -> &Table {
2799        &self.ty
2800    }
2801    ///
2802    pub fn default_value(&self, store: impl AsContextMut) -> Result<RuntimeTable> {
2803        let val: ValType = self.element().clone().into();
2804        let init_val = val
2805            .default_value()
2806            .context("table element type does not have a default value")?
2807            .ref_()
2808            .unwrap();
2809        RuntimeTable::new(store, self.clone(), init_val)
2810    }
2811}
2812
2813// Memory Types
2814
2815/// A builder for [`MemoryType`][crate::MemoryType]s.
2816///
2817/// A new builder can be constructed via its `Default` implementation.
2818///
2819/// When you're done configuring, get the underlying
2820/// [`MemoryType`][crate::MemoryType] by calling the
2821/// [`build`][crate::MemoryTypeBuilder::build] method.
2822///
2823/// # Example
2824///
2825/// ```
2826/// # fn foo() -> wasmtime::Result<()> {
2827/// use wasmtime::MemoryTypeBuilder;
2828///
2829/// let memory_type = MemoryTypeBuilder::new()
2830///     // Set the minimum size, in pages.
2831///     .min(4096)
2832///     // Set the maximum size, in pages.
2833///     .max(Some(4096))
2834///     // Set the page size to 1 byte (aka 2**0).
2835///     .page_size_log2(0)
2836///     // Get the underlying memory type.
2837///     .build()?;
2838/// #   Ok(())
2839/// # }
2840/// ```
2841pub struct MemoryTypeBuilder {
2842    ty: Memory,
2843}
2844
2845impl Default for MemoryTypeBuilder {
2846    fn default() -> Self {
2847        MemoryTypeBuilder {
2848            ty: Memory {
2849                idx_type: IndexType::I32,
2850                limits: Limits { min: 0, max: None },
2851                shared: false,
2852                page_size_log2: Memory::DEFAULT_PAGE_SIZE_LOG2,
2853            },
2854        }
2855    }
2856}
2857
2858impl MemoryTypeBuilder {
2859    /// Create a new builder for a [`MemoryType`] with the default settings.
2860    ///
2861    /// By default memory types have the following properties:
2862    ///
2863    /// * The minimum memory size is 0 pages.
2864    /// * The maximum memory size is unspecified.
2865    /// * Memories use 32-bit indexes.
2866    /// * The page size is 64KiB.
2867    ///
2868    /// Each option can be configured through the methods on the returned
2869    /// builder.
2870    pub fn new() -> MemoryTypeBuilder {
2871        MemoryTypeBuilder::default()
2872    }
2873
2874    fn validate(&self) -> Result<()> {
2875        if self
2876            .ty
2877            .limits
2878            .max
2879            .map_or(false, |max| max < self.ty.limits.min)
2880        {
2881            bail!("maximum page size cannot be smaller than the minimum page size");
2882        }
2883
2884        match self.ty.page_size_log2 {
2885            0 | Memory::DEFAULT_PAGE_SIZE_LOG2 => {}
2886            x => bail!(
2887                "page size must be 2**16 or 2**0, but was given 2**{x}; note \
2888                 that future Wasm extensions might allow any power of two page \
2889                 size, but only 2**16 and 2**0 are currently valid",
2890            ),
2891        }
2892
2893        if self.ty.shared && self.ty.limits.max.is_none() {
2894            bail!("shared memories must have a maximum size");
2895        }
2896
2897        let absolute_max = self.ty.max_size_based_on_index_type();
2898        let min = self
2899            .ty
2900            .minimum_byte_size()
2901            .context("memory's minimum byte size must fit in a u64")?;
2902        if min > absolute_max {
2903            bail!("minimum size is too large for this memory type's index type");
2904        }
2905        if self
2906            .ty
2907            .maximum_byte_size()
2908            .map_or(false, |max| max > absolute_max)
2909        {
2910            bail!("maximum size is too large for this memory type's index type");
2911        }
2912
2913        Ok(())
2914    }
2915
2916    /// Set the minimum size, in units of pages, for the memory type being
2917    /// built.
2918    ///
2919    /// The default minimum is `0`.
2920    pub fn min(&mut self, minimum: u64) -> &mut Self {
2921        self.ty.limits.min = minimum;
2922        self
2923    }
2924
2925    /// Set the maximum size, in units of pages, for the memory type being
2926    /// built.
2927    ///
2928    /// The default maximum is `None`.
2929    pub fn max(&mut self, maximum: Option<u64>) -> &mut Self {
2930        self.ty.limits.max = maximum;
2931        self
2932    }
2933
2934    /// Set whether this is a 64-bit memory or not.
2935    ///
2936    /// If a memory is not a 64-bit memory, then it is a 32-bit memory.
2937    ///
2938    /// The default is `false`, aka 32-bit memories.
2939    ///
2940    /// Note that 64-bit memories are part of [the memory64
2941    /// proposal](https://github.com/WebAssembly/memory64) for WebAssembly which
2942    /// is not fully standardized yet.
2943    pub fn memory64(&mut self, memory64: bool) -> &mut Self {
2944        self.ty.idx_type = match memory64 {
2945            true => IndexType::I64,
2946            false => IndexType::I32,
2947        };
2948        self
2949    }
2950
2951    /// Set the sharedness for the memory type being built.
2952    ///
2953    /// The default is `false`, aka unshared.
2954    ///
2955    /// Note that shared memories are part of [the threads
2956    /// proposal](https://github.com/WebAssembly/threads) for WebAssembly which
2957    /// is not fully standardized yet.
2958    pub fn shared(&mut self, shared: bool) -> &mut Self {
2959        self.ty.shared = shared;
2960        self
2961    }
2962
2963    /// Set the log base 2 of the page size, in bytes, for the memory type being
2964    /// built.
2965    ///
2966    /// The default value is `16`, which results in the default Wasm page size
2967    /// of 64KiB (aka 2<sup>16</sup> or 65536).
2968    ///
2969    /// Other than `16`, the only valid value is `0`, which results in a page
2970    /// size of one byte (aka 2<sup>0</sup>). Single-byte page sizes can be used
2971    /// to get fine-grained control over a Wasm memory's resource consumption
2972    /// and run Wasm in embedded environments with less than 64KiB of RAM, for
2973    /// example.
2974    ///
2975    /// Future extensions to the core WebAssembly language might relax these
2976    /// constraints and introduce more valid page sizes, such as any power of
2977    /// two between 1 and 65536 inclusive.
2978    ///
2979    /// Note that non-default page sizes are part of [the custom-page-sizes
2980    /// proposal](https://github.com/WebAssembly/custom-page-sizes) for
2981    /// WebAssembly which is not fully standardized yet.
2982    pub fn page_size_log2(&mut self, page_size_log2: u8) -> &mut Self {
2983        self.ty.page_size_log2 = page_size_log2;
2984        self
2985    }
2986
2987    /// Get the underlying memory type that this builder has been building.
2988    ///
2989    /// # Errors
2990    ///
2991    /// Returns an error if the configured memory type is invalid, for example
2992    /// if the maximum size is smaller than the minimum size.
2993    pub fn build(&self) -> Result<MemoryType> {
2994        self.validate()?;
2995        Ok(MemoryType { ty: self.ty })
2996    }
2997}
2998
2999/// A descriptor for a WebAssembly memory type.
3000///
3001/// Memories are described in units of pages (64KB) and represent contiguous
3002/// chunks of addressable memory.
3003#[derive(Debug, Clone, Hash, Eq, PartialEq)]
3004pub struct MemoryType {
3005    ty: Memory,
3006}
3007
3008impl MemoryType {
3009    /// Creates a new descriptor for a 32-bit WebAssembly memory given the
3010    /// specified limits of the memory.
3011    ///
3012    /// The `minimum` and `maximum` values here are specified in units of
3013    /// WebAssembly pages, which are 64KiB by default. Use
3014    /// [`MemoryTypeBuilder`][crate::MemoryTypeBuilder] if you want a
3015    /// non-default page size.
3016    ///
3017    /// # Panics
3018    ///
3019    /// Panics if the minimum is greater than the maximum or if the minimum or
3020    /// maximum number of pages can result in a byte size that is not
3021    /// addressable with a 32-bit integer.
3022    pub fn new(minimum: u32, maximum: Option<u32>) -> MemoryType {
3023        MemoryTypeBuilder::default()
3024            .min(minimum.into())
3025            .max(maximum.map(Into::into))
3026            .build()
3027            .unwrap()
3028    }
3029
3030    /// Creates a new descriptor for a 64-bit WebAssembly memory given the
3031    /// specified limits of the memory.
3032    ///
3033    /// The `minimum` and `maximum` values here are specified in units of
3034    /// WebAssembly pages, which are 64KiB by default. Use
3035    /// [`MemoryTypeBuilder`][crate::MemoryTypeBuilder] if you want a
3036    /// non-default page size.
3037    ///
3038    /// Note that 64-bit memories are part of [the memory64
3039    /// proposal](https://github.com/WebAssembly/memory64) for WebAssembly which
3040    /// is not fully standardized yet.
3041    ///
3042    /// # Panics
3043    ///
3044    /// Panics if the minimum is greater than the maximum or if the minimum or
3045    /// maximum number of pages can result in a byte size that is not
3046    /// addressable with a 64-bit integer.
3047    pub fn new64(minimum: u64, maximum: Option<u64>) -> MemoryType {
3048        MemoryTypeBuilder::default()
3049            .memory64(true)
3050            .min(minimum)
3051            .max(maximum)
3052            .build()
3053            .unwrap()
3054    }
3055
3056    /// Creates a new descriptor for shared WebAssembly memory given the
3057    /// specified limits of the memory.
3058    ///
3059    /// The `minimum` and `maximum` values here are specified in units of
3060    /// WebAssembly pages, which are 64KiB by default. Use
3061    /// [`MemoryTypeBuilder`][crate::MemoryTypeBuilder] if you want a
3062    /// non-default page size.
3063    ///
3064    /// Note that shared memories are part of [the threads
3065    /// proposal](https://github.com/WebAssembly/threads) for WebAssembly which
3066    /// is not fully standardized yet.
3067    ///
3068    /// # Panics
3069    ///
3070    /// Panics if the minimum is greater than the maximum or if the minimum or
3071    /// maximum number of pages can result in a byte size that is not
3072    /// addressable with a 32-bit integer.
3073    pub fn shared(minimum: u32, maximum: u32) -> MemoryType {
3074        MemoryTypeBuilder::default()
3075            .shared(true)
3076            .min(minimum.into())
3077            .max(Some(maximum.into()))
3078            .build()
3079            .unwrap()
3080    }
3081
3082    /// Creates a new [`MemoryTypeBuilder`] to configure all the various knobs
3083    /// of the final memory type being created.
3084    ///
3085    /// This is a convenience function for [`MemoryTypeBuilder::new`].
3086    pub fn builder() -> MemoryTypeBuilder {
3087        MemoryTypeBuilder::new()
3088    }
3089
3090    /// Returns whether this is a 64-bit memory or not.
3091    ///
3092    /// Note that 64-bit memories are part of the memory64 proposal for
3093    /// WebAssembly which is not standardized yet.
3094    pub fn is_64(&self) -> bool {
3095        matches!(self.ty.idx_type, IndexType::I64)
3096    }
3097
3098    /// Returns whether this is a shared memory or not.
3099    ///
3100    /// Note that shared memories are part of the threads proposal for
3101    /// WebAssembly which is not standardized yet.
3102    pub fn is_shared(&self) -> bool {
3103        self.ty.shared
3104    }
3105
3106    /// Returns minimum number of WebAssembly pages this memory must have.
3107    ///
3108    /// Note that the return value, while a `u64`, will always fit into a `u32`
3109    /// for 32-bit memories.
3110    pub fn minimum(&self) -> u64 {
3111        self.ty.limits.min
3112    }
3113
3114    /// Returns the optionally-specified maximum number of pages this memory
3115    /// can have.
3116    ///
3117    /// If this returns `None` then the memory is not limited in size.
3118    ///
3119    /// Note that the return value, while a `u64`, will always fit into a `u32`
3120    /// for 32-bit memories.
3121    pub fn maximum(&self) -> Option<u64> {
3122        self.ty.limits.max
3123    }
3124
3125    /// This memory's page size, in bytes.
3126    pub fn page_size(&self) -> u64 {
3127        self.ty.page_size()
3128    }
3129
3130    /// The log2 of this memory's page size, in bytes.
3131    pub fn page_size_log2(&self) -> u8 {
3132        self.ty.page_size_log2
3133    }
3134
3135    pub(crate) fn from_wasmtime_memory(memory: &Memory) -> MemoryType {
3136        MemoryType { ty: *memory }
3137    }
3138
3139    pub(crate) fn wasmtime_memory(&self) -> &Memory {
3140        &self.ty
3141    }
3142    ///
3143    pub fn default_value(&self, store: impl AsContextMut) -> Result<RuntimeMemory> {
3144        RuntimeMemory::new(store, self.clone())
3145    }
3146}
3147
3148// Import Types
3149
3150/// A descriptor for an imported value into a wasm module.
3151///
3152/// This type is primarily accessed from the
3153/// [`Module::imports`](crate::Module::imports) API. Each [`ImportType`]
3154/// describes an import into the wasm module with the module/name that it's
3155/// imported from as well as the type of item that's being imported.
3156#[derive(Clone)]
3157pub struct ImportType<'module> {
3158    /// The module of the import.
3159    module: &'module str,
3160
3161    /// The field of the import.
3162    name: &'module str,
3163
3164    /// The type of the import.
3165    ty: EntityType,
3166    types: &'module ModuleTypes,
3167    engine: &'module Engine,
3168}
3169
3170impl<'module> ImportType<'module> {
3171    /// Creates a new import descriptor which comes from `module` and `name` and
3172    /// is of type `ty`.
3173    pub(crate) fn new(
3174        module: &'module str,
3175        name: &'module str,
3176        ty: EntityType,
3177        types: &'module ModuleTypes,
3178        engine: &'module Engine,
3179    ) -> ImportType<'module> {
3180        assert!(ty.is_canonicalized_for_runtime_usage());
3181        ImportType {
3182            module,
3183            name,
3184            ty,
3185            types,
3186            engine,
3187        }
3188    }
3189
3190    /// Returns the module name that this import is expected to come from.
3191    pub fn module(&self) -> &'module str {
3192        self.module
3193    }
3194
3195    /// Returns the field name of the module that this import is expected to
3196    /// come from.
3197    pub fn name(&self) -> &'module str {
3198        self.name
3199    }
3200
3201    /// Returns the expected type of this import.
3202    pub fn ty(&self) -> ExternType {
3203        ExternType::from_wasmtime(self.engine, self.types, &self.ty)
3204    }
3205}
3206
3207impl<'module> fmt::Debug for ImportType<'module> {
3208    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3209        f.debug_struct("ImportType")
3210            .field("module", &self.module())
3211            .field("name", &self.name())
3212            .field("ty", &self.ty())
3213            .finish()
3214    }
3215}
3216
3217// Export Types
3218
3219/// A descriptor for an exported WebAssembly value.
3220///
3221/// This type is primarily accessed from the
3222/// [`Module::exports`](crate::Module::exports) accessor and describes what
3223/// names are exported from a wasm module and the type of the item that is
3224/// exported.
3225#[derive(Clone)]
3226pub struct ExportType<'module> {
3227    /// The name of the export.
3228    name: &'module str,
3229
3230    /// The type of the export.
3231    ty: EntityType,
3232    types: &'module ModuleTypes,
3233    engine: &'module Engine,
3234}
3235
3236impl<'module> ExportType<'module> {
3237    /// Creates a new export which is exported with the given `name` and has the
3238    /// given `ty`.
3239    pub(crate) fn new(
3240        name: &'module str,
3241        ty: EntityType,
3242        types: &'module ModuleTypes,
3243        engine: &'module Engine,
3244    ) -> ExportType<'module> {
3245        ExportType {
3246            name,
3247            ty,
3248            types,
3249            engine,
3250        }
3251    }
3252
3253    /// Returns the name by which this export is known.
3254    pub fn name(&self) -> &'module str {
3255        self.name
3256    }
3257
3258    /// Returns the type of this export.
3259    pub fn ty(&self) -> ExternType {
3260        ExternType::from_wasmtime(self.engine, self.types, &self.ty)
3261    }
3262}
3263
3264impl<'module> fmt::Debug for ExportType<'module> {
3265    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3266        f.debug_struct("ExportType")
3267            .field("name", &self.name().to_owned())
3268            .field("ty", &self.ty())
3269            .finish()
3270    }
3271}