Skip to main content

wasmtime/runtime/component/
types.rs

1//! This module defines the `Type` type, representing the dynamic form of a component interface type.
2
3#[cfg(feature = "component-model-async")]
4use crate::component::ComponentType;
5use crate::component::matching::InstanceType;
6use crate::{Engine, ExternType, FuncType, prelude::*};
7use alloc::sync::Arc;
8use core::fmt;
9use core::ops::Deref;
10use wasmtime_environ::component::{
11    ComponentTypes, Export, InterfaceType, ResourceIndex, TypeComponentIndex,
12    TypeComponentInstanceIndex, TypeDef, TypeEnumIndex, TypeFlagsIndex, TypeFuncIndex,
13    TypeFutureIndex, TypeFutureTableIndex, TypeListIndex, TypeMapIndex, TypeModuleIndex,
14    TypeOptionIndex, TypeRecordIndex, TypeResourceTable, TypeResourceTableIndex, TypeResultIndex,
15    TypeStreamIndex, TypeStreamTableIndex, TypeTupleIndex, TypeVariantIndex,
16};
17use wasmtime_environ::{PanicOnOom as _, PrimaryMap};
18
19pub use crate::component::resources::ResourceType;
20
21/// An owned and `'static` handle for type information in a component.
22///
23/// The components here are:
24///
25/// * `index` - a `TypeFooIndex` defined in the `wasmtime_environ` crate. This
26///   then points into the next field of...
27///
28/// * `types` - this is an allocation originally created from compilation and is
29///   stored in a compiled `Component`. This contains all types necessary and
30///   information about recursive structures and all other type information
31///   within the component. The above `index` points into this structure.
32///
33/// * `resources` - this is used to "close the loop" and represent a concrete
34///   instance type rather than an abstract component type. Instantiating a
35///   component with different resources produces different instance types but
36///   the same underlying component type, so this field serves the purpose to
37///   distinguish instance types from one another. This is runtime state created
38///   during instantiation and threaded through here.
39#[derive(Clone)]
40struct Handle<T> {
41    index: T,
42    types: Arc<ComponentTypes>,
43    resources: Arc<PrimaryMap<ResourceIndex, ResourceType>>,
44}
45
46impl<T> Handle<T> {
47    fn new(index: T, ty: &InstanceType<'_>) -> Handle<T> {
48        Handle {
49            index,
50            types: ty.types.clone(),
51            resources: ty.resources.clone(),
52        }
53    }
54
55    fn instance(&self) -> InstanceType<'_> {
56        InstanceType {
57            types: &self.types,
58            resources: &self.resources,
59        }
60    }
61
62    fn equivalent<'a>(
63        &'a self,
64        other: &'a Self,
65        type_check: fn(&TypeChecker<'a>, T, T) -> bool,
66    ) -> bool
67    where
68        T: PartialEq + Copy,
69    {
70        (self.index == other.index
71            && Arc::ptr_eq(&self.types, &other.types)
72            && Arc::ptr_eq(&self.resources, &other.resources))
73            || type_check(
74                &TypeChecker {
75                    a_types: &self.types,
76                    b_types: &other.types,
77                    a_resource: &self.resources,
78                    b_resource: &other.resources,
79                },
80                self.index,
81                other.index,
82            )
83    }
84}
85
86impl<T: fmt::Debug> fmt::Debug for Handle<T> {
87    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88        f.debug_struct("Handle")
89            .field("index", &self.index)
90            .finish()
91    }
92}
93
94/// Type checker between two `Handle`s
95struct TypeChecker<'a> {
96    a_types: &'a ComponentTypes,
97    a_resource: &'a PrimaryMap<ResourceIndex, ResourceType>,
98    b_types: &'a ComponentTypes,
99    b_resource: &'a PrimaryMap<ResourceIndex, ResourceType>,
100}
101
102impl TypeChecker<'_> {
103    fn interface_types_equal(&self, a: InterfaceType, b: InterfaceType) -> bool {
104        match (a, b) {
105            (InterfaceType::Own(o1), InterfaceType::Own(o2)) => self.resources_equal(o1, o2),
106            (InterfaceType::Own(_), _) => false,
107            (InterfaceType::Borrow(b1), InterfaceType::Borrow(b2)) => self.resources_equal(b1, b2),
108            (InterfaceType::Borrow(_), _) => false,
109            (InterfaceType::List(l1), InterfaceType::List(l2)) => self.lists_equal(l1, l2),
110            (InterfaceType::List(_), _) => false,
111            (InterfaceType::Map(m1), InterfaceType::Map(m2)) => self.maps_equal(m1, m2),
112            (InterfaceType::Map(_), _) => false,
113            (InterfaceType::Record(r1), InterfaceType::Record(r2)) => self.records_equal(r1, r2),
114            (InterfaceType::Record(_), _) => false,
115            (InterfaceType::Variant(v1), InterfaceType::Variant(v2)) => self.variants_equal(v1, v2),
116            (InterfaceType::Variant(_), _) => false,
117            (InterfaceType::Result(r1), InterfaceType::Result(r2)) => self.results_equal(r1, r2),
118            (InterfaceType::Result(_), _) => false,
119            (InterfaceType::Option(o1), InterfaceType::Option(o2)) => self.options_equal(o1, o2),
120            (InterfaceType::Option(_), _) => false,
121            (InterfaceType::Enum(e1), InterfaceType::Enum(e2)) => self.enums_equal(e1, e2),
122            (InterfaceType::Enum(_), _) => false,
123            (InterfaceType::Tuple(t1), InterfaceType::Tuple(t2)) => self.tuples_equal(t1, t2),
124            (InterfaceType::Tuple(_), _) => false,
125            (InterfaceType::Flags(f1), InterfaceType::Flags(f2)) => self.flags_equal(f1, f2),
126            (InterfaceType::Flags(_), _) => false,
127            (InterfaceType::Bool, InterfaceType::Bool) => true,
128            (InterfaceType::Bool, _) => false,
129            (InterfaceType::U8, InterfaceType::U8) => true,
130            (InterfaceType::U8, _) => false,
131            (InterfaceType::U16, InterfaceType::U16) => true,
132            (InterfaceType::U16, _) => false,
133            (InterfaceType::U32, InterfaceType::U32) => true,
134            (InterfaceType::U32, _) => false,
135            (InterfaceType::U64, InterfaceType::U64) => true,
136            (InterfaceType::U64, _) => false,
137            (InterfaceType::S8, InterfaceType::S8) => true,
138            (InterfaceType::S8, _) => false,
139            (InterfaceType::S16, InterfaceType::S16) => true,
140            (InterfaceType::S16, _) => false,
141            (InterfaceType::S32, InterfaceType::S32) => true,
142            (InterfaceType::S32, _) => false,
143            (InterfaceType::S64, InterfaceType::S64) => true,
144            (InterfaceType::S64, _) => false,
145            (InterfaceType::Float32, InterfaceType::Float32) => true,
146            (InterfaceType::Float32, _) => false,
147            (InterfaceType::Float64, InterfaceType::Float64) => true,
148            (InterfaceType::Float64, _) => false,
149            (InterfaceType::String, InterfaceType::String) => true,
150            (InterfaceType::String, _) => false,
151            (InterfaceType::Char, InterfaceType::Char) => true,
152            (InterfaceType::Char, _) => false,
153            (InterfaceType::Future(t1), InterfaceType::Future(t2)) => {
154                self.future_table_types_equal(t1, t2)
155            }
156            (InterfaceType::Future(_), _) => false,
157            (InterfaceType::Stream(t1), InterfaceType::Stream(t2)) => {
158                self.stream_table_types_equal(t1, t2)
159            }
160            (InterfaceType::Stream(_), _) => false,
161            (InterfaceType::ErrorContext(_), InterfaceType::ErrorContext(_)) => true,
162            (InterfaceType::ErrorContext(_), _) => false,
163            (InterfaceType::FixedLengthList(_), _) => todo!(), // FIXME(#12279)
164        }
165    }
166
167    fn lists_equal(&self, l1: TypeListIndex, l2: TypeListIndex) -> bool {
168        let a = &self.a_types[l1];
169        let b = &self.b_types[l2];
170        self.interface_types_equal(a.element, b.element)
171    }
172
173    fn maps_equal(&self, m1: TypeMapIndex, m2: TypeMapIndex) -> bool {
174        let a = &self.a_types[m1];
175        let b = &self.b_types[m2];
176        self.interface_types_equal(a.key, b.key) && self.interface_types_equal(a.value, b.value)
177    }
178
179    fn resources_equal(&self, o1: TypeResourceTableIndex, o2: TypeResourceTableIndex) -> bool {
180        match (&self.a_types[o1], &self.b_types[o2]) {
181            // Concrete resource types are the same if they map back to the
182            // exact same `ResourceType` at runtime, so look them up in resource
183            // type tables and compare the types themselves.
184            (
185                TypeResourceTable::Concrete { ty: a, .. },
186                TypeResourceTable::Concrete { ty: b, .. },
187            ) => self.a_resource[*a] == self.b_resource[*b],
188            (TypeResourceTable::Concrete { .. }, _) => false,
189
190            // Abstract resource types are only the same if they have the same
191            // index and come from the exact same component.
192            (TypeResourceTable::Abstract(a), TypeResourceTable::Abstract(b)) => {
193                core::ptr::eq(self.a_types, self.b_types) && a == b
194            }
195            (TypeResourceTable::Abstract(_), _) => false,
196        }
197    }
198
199    fn records_equal(&self, r1: TypeRecordIndex, r2: TypeRecordIndex) -> bool {
200        let a = &self.a_types[r1];
201        let b = &self.b_types[r2];
202        if a.fields.len() != b.fields.len() {
203            return false;
204        }
205        a.fields
206            .iter()
207            .zip(b.fields.iter())
208            .all(|(a_field, b_field)| {
209                a_field.name == b_field.name && self.interface_types_equal(a_field.ty, b_field.ty)
210            })
211    }
212
213    fn variants_equal(&self, v1: TypeVariantIndex, v2: TypeVariantIndex) -> bool {
214        let a = &self.a_types[v1];
215        let b = &self.b_types[v2];
216        if a.cases.len() != b.cases.len() {
217            return false;
218        }
219        a.cases
220            .iter()
221            .zip(b.cases.iter())
222            .all(|((a_name, a_ty), (b_name, b_ty))| {
223                if a_name != b_name {
224                    return false;
225                }
226                match (a_ty, b_ty) {
227                    (Some(a_case_ty), Some(b_case_ty)) => {
228                        self.interface_types_equal(*a_case_ty, *b_case_ty)
229                    }
230                    (None, None) => true,
231                    _ => false,
232                }
233            })
234    }
235
236    fn results_equal(&self, r1: TypeResultIndex, r2: TypeResultIndex) -> bool {
237        let a = &self.a_types[r1];
238        let b = &self.b_types[r2];
239        let oks = match (a.ok, b.ok) {
240            (Some(ok1), Some(ok2)) => self.interface_types_equal(ok1, ok2),
241            (None, None) => true,
242            _ => false,
243        };
244        if !oks {
245            return false;
246        }
247        match (a.err, b.err) {
248            (Some(err1), Some(err2)) => self.interface_types_equal(err1, err2),
249            (None, None) => true,
250            _ => false,
251        }
252    }
253
254    fn options_equal(&self, o1: TypeOptionIndex, o2: TypeOptionIndex) -> bool {
255        let a = &self.a_types[o1];
256        let b = &self.b_types[o2];
257        self.interface_types_equal(a.ty, b.ty)
258    }
259
260    fn enums_equal(&self, e1: TypeEnumIndex, e2: TypeEnumIndex) -> bool {
261        let a = &self.a_types[e1];
262        let b = &self.b_types[e2];
263        a.names == b.names
264    }
265
266    fn tuples_equal(&self, t1: TypeTupleIndex, t2: TypeTupleIndex) -> bool {
267        let a = &self.a_types[t1];
268        let b = &self.b_types[t2];
269        if a.types.len() != b.types.len() {
270            return false;
271        }
272        a.types
273            .iter()
274            .zip(b.types.iter())
275            .all(|(&a, &b)| self.interface_types_equal(a, b))
276    }
277
278    fn flags_equal(&self, f1: TypeFlagsIndex, f2: TypeFlagsIndex) -> bool {
279        let a = &self.a_types[f1];
280        let b = &self.b_types[f2];
281        a.names == b.names
282    }
283
284    fn future_table_types_equal(&self, t1: TypeFutureTableIndex, t2: TypeFutureTableIndex) -> bool {
285        self.futures_equal(self.a_types[t1].ty, self.b_types[t2].ty)
286    }
287
288    fn futures_equal(&self, t1: TypeFutureIndex, t2: TypeFutureIndex) -> bool {
289        let a = &self.a_types[t1];
290        let b = &self.b_types[t2];
291        match (a.payload, b.payload) {
292            (Some(t1), Some(t2)) => self.interface_types_equal(t1, t2),
293            (None, None) => true,
294            _ => false,
295        }
296    }
297
298    fn stream_table_types_equal(&self, t1: TypeStreamTableIndex, t2: TypeStreamTableIndex) -> bool {
299        self.streams_equal(self.a_types[t1].ty, self.b_types[t2].ty)
300    }
301
302    fn streams_equal(&self, t1: TypeStreamIndex, t2: TypeStreamIndex) -> bool {
303        let a = &self.a_types[t1];
304        let b = &self.b_types[t2];
305        match (a.payload, b.payload) {
306            (Some(t1), Some(t2)) => self.interface_types_equal(t1, t2),
307            (None, None) => true,
308            _ => false,
309        }
310    }
311}
312
313/// A `list` interface type
314#[derive(Clone, Debug)]
315pub struct List(Handle<TypeListIndex>);
316
317impl PartialEq for List {
318    fn eq(&self, other: &Self) -> bool {
319        self.0.equivalent(&other.0, TypeChecker::lists_equal)
320    }
321}
322
323impl Eq for List {}
324
325impl List {
326    pub(crate) fn from(index: TypeListIndex, ty: &InstanceType<'_>) -> Self {
327        List(Handle::new(index, ty))
328    }
329
330    /// Retrieve the element type of this `list`.
331    pub fn ty(&self) -> Type {
332        Type::from(&self.0.types[self.0.index].element, &self.0.instance())
333    }
334}
335
336/// A `map` interface type
337#[derive(Clone, Debug)]
338pub struct Map(Handle<TypeMapIndex>);
339
340impl PartialEq for Map {
341    fn eq(&self, other: &Self) -> bool {
342        self.0.equivalent(&other.0, TypeChecker::maps_equal)
343    }
344}
345
346impl Eq for Map {}
347
348impl Map {
349    pub(crate) fn from(index: TypeMapIndex, ty: &InstanceType<'_>) -> Self {
350        Map(Handle::new(index, ty))
351    }
352
353    /// Retrieve the key type of this `map`.
354    pub fn key(&self) -> Type {
355        Type::from(&self.0.types[self.0.index].key, &self.0.instance())
356    }
357
358    /// Retrieve the value type of this `map`.
359    pub fn value(&self) -> Type {
360        Type::from(&self.0.types[self.0.index].value, &self.0.instance())
361    }
362}
363
364/// A field declaration belonging to a `record`
365#[derive(Debug)]
366pub struct Field<'a> {
367    /// The name of the field
368    pub name: &'a str,
369    /// The type of the field
370    pub ty: Type,
371}
372
373/// A `record` interface type
374#[derive(Clone, Debug)]
375pub struct Record(Handle<TypeRecordIndex>);
376
377impl Record {
378    pub(crate) fn from(index: TypeRecordIndex, ty: &InstanceType<'_>) -> Self {
379        Record(Handle::new(index, ty))
380    }
381
382    /// Retrieve the fields of this `record` in declaration order.
383    pub fn fields(&self) -> impl ExactSizeIterator<Item = Field<'_>> {
384        self.0.types[self.0.index].fields.iter().map(|field| Field {
385            name: &field.name,
386            ty: Type::from(&field.ty, &self.0.instance()),
387        })
388    }
389}
390
391impl PartialEq for Record {
392    fn eq(&self, other: &Self) -> bool {
393        self.0.equivalent(&other.0, TypeChecker::records_equal)
394    }
395}
396
397impl Eq for Record {}
398
399/// A `tuple` interface type
400#[derive(Clone, Debug)]
401pub struct Tuple(Handle<TypeTupleIndex>);
402
403impl Tuple {
404    pub(crate) fn from(index: TypeTupleIndex, ty: &InstanceType<'_>) -> Self {
405        Tuple(Handle::new(index, ty))
406    }
407
408    /// Retrieve the types of the fields of this `tuple` in declaration order.
409    pub fn types(&self) -> impl ExactSizeIterator<Item = Type> + '_ {
410        self.0.types[self.0.index]
411            .types
412            .iter()
413            .map(|ty| Type::from(ty, &self.0.instance()))
414    }
415}
416
417impl PartialEq for Tuple {
418    fn eq(&self, other: &Self) -> bool {
419        self.0.equivalent(&other.0, TypeChecker::tuples_equal)
420    }
421}
422
423impl Eq for Tuple {}
424
425/// A case declaration belonging to a `variant`
426pub struct Case<'a> {
427    /// The name of the case
428    pub name: &'a str,
429    /// The optional payload type of the case
430    pub ty: Option<Type>,
431}
432
433/// A `variant` interface type
434#[derive(Clone, Debug)]
435pub struct Variant(Handle<TypeVariantIndex>);
436
437impl Variant {
438    pub(crate) fn from(index: TypeVariantIndex, ty: &InstanceType<'_>) -> Self {
439        Variant(Handle::new(index, ty))
440    }
441
442    /// Retrieve the cases of this `variant` in declaration order.
443    pub fn cases(&self) -> impl ExactSizeIterator<Item = Case<'_>> {
444        self.0.types[self.0.index]
445            .cases
446            .iter()
447            .map(|(name, ty)| Case {
448                name,
449                ty: ty.as_ref().map(|ty| Type::from(ty, &self.0.instance())),
450            })
451    }
452}
453
454impl PartialEq for Variant {
455    fn eq(&self, other: &Self) -> bool {
456        self.0.equivalent(&other.0, TypeChecker::variants_equal)
457    }
458}
459
460impl Eq for Variant {}
461
462/// An `enum` interface type
463#[derive(Clone, Debug)]
464pub struct Enum(Handle<TypeEnumIndex>);
465
466impl Enum {
467    pub(crate) fn from(index: TypeEnumIndex, ty: &InstanceType<'_>) -> Self {
468        Enum(Handle::new(index, ty))
469    }
470
471    /// Retrieve the names of the cases of this `enum` in declaration order.
472    pub fn names(&self) -> impl ExactSizeIterator<Item = &str> {
473        self.0.types[self.0.index]
474            .names
475            .iter()
476            .map(|name| name.deref())
477    }
478}
479
480impl PartialEq for Enum {
481    fn eq(&self, other: &Self) -> bool {
482        self.0.equivalent(&other.0, TypeChecker::enums_equal)
483    }
484}
485
486impl Eq for Enum {}
487
488/// An `option` interface type
489#[derive(Clone, Debug)]
490pub struct OptionType(Handle<TypeOptionIndex>);
491
492impl OptionType {
493    pub(crate) fn from(index: TypeOptionIndex, ty: &InstanceType<'_>) -> Self {
494        OptionType(Handle::new(index, ty))
495    }
496
497    /// Retrieve the type parameter for this `option`.
498    pub fn ty(&self) -> Type {
499        Type::from(&self.0.types[self.0.index].ty, &self.0.instance())
500    }
501}
502
503impl PartialEq for OptionType {
504    fn eq(&self, other: &Self) -> bool {
505        self.0.equivalent(&other.0, TypeChecker::options_equal)
506    }
507}
508
509impl Eq for OptionType {}
510
511/// A `result` interface type
512#[derive(Clone, Debug)]
513pub struct ResultType(Handle<TypeResultIndex>);
514
515impl ResultType {
516    pub(crate) fn from(index: TypeResultIndex, ty: &InstanceType<'_>) -> Self {
517        ResultType(Handle::new(index, ty))
518    }
519
520    /// Retrieve the `ok` type parameter for this `result`.
521    pub fn ok(&self) -> Option<Type> {
522        Some(Type::from(
523            self.0.types[self.0.index].ok.as_ref()?,
524            &self.0.instance(),
525        ))
526    }
527
528    /// Retrieve the `err` type parameter for this `result`.
529    pub fn err(&self) -> Option<Type> {
530        Some(Type::from(
531            self.0.types[self.0.index].err.as_ref()?,
532            &self.0.instance(),
533        ))
534    }
535}
536
537impl PartialEq for ResultType {
538    fn eq(&self, other: &Self) -> bool {
539        self.0.equivalent(&other.0, TypeChecker::results_equal)
540    }
541}
542
543impl Eq for ResultType {}
544
545/// A `flags` interface type
546#[derive(Clone, Debug)]
547pub struct Flags(Handle<TypeFlagsIndex>);
548
549impl Flags {
550    pub(crate) fn from(index: TypeFlagsIndex, ty: &InstanceType<'_>) -> Self {
551        Flags(Handle::new(index, ty))
552    }
553
554    /// Retrieve the names of the flags of this `flags` type in declaration order.
555    pub fn names(&self) -> impl ExactSizeIterator<Item = &str> {
556        self.0.types[self.0.index]
557            .names
558            .iter()
559            .map(|name| name.deref())
560    }
561}
562
563impl PartialEq for Flags {
564    fn eq(&self, other: &Self) -> bool {
565        self.0.equivalent(&other.0, TypeChecker::flags_equal)
566    }
567}
568
569impl Eq for Flags {}
570
571#[cfg(feature = "component-model-async")]
572pub(crate) fn typecheck_payload<T>(
573    payload: Option<&InterfaceType>,
574    types: &InstanceType<'_>,
575) -> crate::Result<()>
576where
577    T: ComponentType,
578{
579    match payload {
580        Some(a) => T::typecheck(a, types),
581        None => {
582            if T::IS_RUST_UNIT_TYPE {
583                Ok(())
584            } else {
585                crate::bail!("future payload types differ")
586            }
587        }
588    }
589}
590
591/// An `future` interface type
592#[derive(Clone, Debug)]
593pub struct FutureType(Handle<TypeFutureIndex>);
594
595impl FutureType {
596    pub(crate) fn from(index: TypeFutureIndex, ty: &InstanceType<'_>) -> Self {
597        FutureType(Handle::new(index, ty))
598    }
599
600    /// Retrieve the type parameter for this `future`.
601    pub fn ty(&self) -> Option<Type> {
602        Some(Type::from(
603            self.0.types[self.0.index].payload.as_ref()?,
604            &self.0.instance(),
605        ))
606    }
607
608    #[cfg(feature = "component-model-async")]
609    pub(crate) fn equivalent_payload_guest(
610        &self,
611        ty: &InstanceType<'_>,
612        payload: Option<&InterfaceType>,
613    ) -> bool {
614        let my_payload = self.0.types[self.0.index].payload.as_ref();
615        match (my_payload, payload) {
616            (Some(a), Some(b)) => TypeChecker {
617                a_types: &self.0.types,
618                a_resource: &self.0.resources,
619                b_types: ty.types,
620                b_resource: ty.resources,
621            }
622            .interface_types_equal(*a, *b),
623            (None, None) => true,
624            (Some(_), None) | (None, Some(_)) => false,
625        }
626    }
627
628    #[cfg(feature = "component-model-async")]
629    pub(crate) fn equivalent_payload_host<T>(&self) -> crate::Result<()>
630    where
631        T: ComponentType,
632    {
633        typecheck_payload::<T>(
634            self.0.types[self.0.index].payload.as_ref(),
635            &self.0.instance(),
636        )
637    }
638}
639
640impl PartialEq for FutureType {
641    fn eq(&self, other: &Self) -> bool {
642        self.0.equivalent(&other.0, TypeChecker::futures_equal)
643    }
644}
645
646impl Eq for FutureType {}
647
648/// An `stream` interface type
649#[derive(Clone, Debug)]
650pub struct StreamType(Handle<TypeStreamIndex>);
651
652impl StreamType {
653    pub(crate) fn from(index: TypeStreamIndex, ty: &InstanceType<'_>) -> Self {
654        StreamType(Handle::new(index, ty))
655    }
656
657    /// Retrieve the type parameter for this `stream`.
658    pub fn ty(&self) -> Option<Type> {
659        Some(Type::from(
660            self.0.types[self.0.index].payload.as_ref()?,
661            &self.0.instance(),
662        ))
663    }
664
665    #[cfg(feature = "component-model-async")]
666    pub(crate) fn equivalent_payload_guest(
667        &self,
668        ty: &InstanceType<'_>,
669        payload: Option<&InterfaceType>,
670    ) -> bool {
671        let my_payload = self.0.types[self.0.index].payload.as_ref();
672        match (my_payload, payload) {
673            (Some(a), Some(b)) => TypeChecker {
674                a_types: &self.0.types,
675                a_resource: &self.0.resources,
676                b_types: ty.types,
677                b_resource: ty.resources,
678            }
679            .interface_types_equal(*a, *b),
680            (None, None) => true,
681            (Some(_), None) | (None, Some(_)) => false,
682        }
683    }
684
685    #[cfg(feature = "component-model-async")]
686    pub(crate) fn equivalent_payload_host<T>(&self) -> crate::Result<()>
687    where
688        T: ComponentType,
689    {
690        typecheck_payload::<T>(
691            self.0.types[self.0.index].payload.as_ref(),
692            &self.0.instance(),
693        )
694    }
695}
696
697impl PartialEq for StreamType {
698    fn eq(&self, other: &Self) -> bool {
699        self.0.equivalent(&other.0, TypeChecker::streams_equal)
700    }
701}
702
703impl Eq for StreamType {}
704
705/// Represents a component model interface type
706#[derive(Clone, PartialEq, Eq, Debug)]
707#[expect(missing_docs, reason = "self-describing variants")]
708pub enum Type {
709    Bool,
710    S8,
711    U8,
712    S16,
713    U16,
714    S32,
715    U32,
716    S64,
717    U64,
718    Float32,
719    Float64,
720    Char,
721    String,
722    List(List),
723    Map(Map),
724    Record(Record),
725    Tuple(Tuple),
726    Variant(Variant),
727    Enum(Enum),
728    Option(OptionType),
729    Result(ResultType),
730    Flags(Flags),
731    Own(ResourceType),
732    Borrow(ResourceType),
733    Future(FutureType),
734    Stream(StreamType),
735    ErrorContext,
736}
737
738impl Type {
739    /// Retrieve the inner [`List`] of a [`Type::List`].
740    ///
741    /// # Panics
742    ///
743    /// This will panic if `self` is not a [`Type::List`].
744    pub fn unwrap_list(&self) -> &List {
745        if let Type::List(handle) = self {
746            &handle
747        } else {
748            panic!("attempted to unwrap a {} as a list", self.desc())
749        }
750    }
751
752    /// Retrieve the inner [`Record`] of a [`Type::Record`].
753    ///
754    /// # Panics
755    ///
756    /// This will panic if `self` is not a [`Type::Record`].
757    pub fn unwrap_record(&self) -> &Record {
758        if let Type::Record(handle) = self {
759            &handle
760        } else {
761            panic!("attempted to unwrap a {} as a record", self.desc())
762        }
763    }
764
765    /// Retrieve the inner [`Tuple`] of a [`Type::Tuple`].
766    ///
767    /// # Panics
768    ///
769    /// This will panic if `self` is not a [`Type::Tuple`].
770    pub fn unwrap_tuple(&self) -> &Tuple {
771        if let Type::Tuple(handle) = self {
772            &handle
773        } else {
774            panic!("attempted to unwrap a {} as a tuple", self.desc())
775        }
776    }
777
778    /// Retrieve the inner [`Variant`] of a [`Type::Variant`].
779    ///
780    /// # Panics
781    ///
782    /// This will panic if `self` is not a [`Type::Variant`].
783    pub fn unwrap_variant(&self) -> &Variant {
784        if let Type::Variant(handle) = self {
785            &handle
786        } else {
787            panic!("attempted to unwrap a {} as a variant", self.desc())
788        }
789    }
790
791    /// Retrieve the inner [`Enum`] of a [`Type::Enum`].
792    ///
793    /// # Panics
794    ///
795    /// This will panic if `self` is not a [`Type::Enum`].
796    pub fn unwrap_enum(&self) -> &Enum {
797        if let Type::Enum(handle) = self {
798            &handle
799        } else {
800            panic!("attempted to unwrap a {} as a enum", self.desc())
801        }
802    }
803
804    /// Retrieve the inner [`OptionType`] of a [`Type::Option`].
805    ///
806    /// # Panics
807    ///
808    /// This will panic if `self` is not a [`Type::Option`].
809    pub fn unwrap_option(&self) -> &OptionType {
810        if let Type::Option(handle) = self {
811            &handle
812        } else {
813            panic!("attempted to unwrap a {} as a option", self.desc())
814        }
815    }
816
817    /// Retrieve the inner [`ResultType`] of a [`Type::Result`].
818    ///
819    /// # Panics
820    ///
821    /// This will panic if `self` is not a [`Type::Result`].
822    pub fn unwrap_result(&self) -> &ResultType {
823        if let Type::Result(handle) = self {
824            &handle
825        } else {
826            panic!("attempted to unwrap a {} as a result", self.desc())
827        }
828    }
829
830    /// Retrieve the inner [`Flags`] of a [`Type::Flags`].
831    ///
832    /// # Panics
833    ///
834    /// This will panic if `self` is not a [`Type::Flags`].
835    pub fn unwrap_flags(&self) -> &Flags {
836        if let Type::Flags(handle) = self {
837            &handle
838        } else {
839            panic!("attempted to unwrap a {} as a flags", self.desc())
840        }
841    }
842
843    /// Retrieve the inner [`ResourceType`] of a [`Type::Own`].
844    ///
845    /// # Panics
846    ///
847    /// This will panic if `self` is not a [`Type::Own`].
848    pub fn unwrap_own(&self) -> &ResourceType {
849        match self {
850            Type::Own(ty) => ty,
851            _ => panic!("attempted to unwrap a {} as a own", self.desc()),
852        }
853    }
854
855    /// Retrieve the inner [`ResourceType`] of a [`Type::Borrow`].
856    ///
857    /// # Panics
858    ///
859    /// This will panic if `self` is not a [`Type::Borrow`].
860    pub fn unwrap_borrow(&self) -> &ResourceType {
861        match self {
862            Type::Borrow(ty) => ty,
863            _ => panic!("attempted to unwrap a {} as a own", self.desc()),
864        }
865    }
866
867    /// Convert the specified `InterfaceType` to a `Type`.
868    pub(crate) fn from(ty: &InterfaceType, instance: &InstanceType<'_>) -> Self {
869        match ty {
870            InterfaceType::Bool => Type::Bool,
871            InterfaceType::S8 => Type::S8,
872            InterfaceType::U8 => Type::U8,
873            InterfaceType::S16 => Type::S16,
874            InterfaceType::U16 => Type::U16,
875            InterfaceType::S32 => Type::S32,
876            InterfaceType::U32 => Type::U32,
877            InterfaceType::S64 => Type::S64,
878            InterfaceType::U64 => Type::U64,
879            InterfaceType::Float32 => Type::Float32,
880            InterfaceType::Float64 => Type::Float64,
881            InterfaceType::Char => Type::Char,
882            InterfaceType::String => Type::String,
883            InterfaceType::List(index) => Type::List(List::from(*index, instance)),
884            InterfaceType::Map(index) => Type::Map(Map::from(*index, instance)),
885            InterfaceType::Record(index) => Type::Record(Record::from(*index, instance)),
886            InterfaceType::Tuple(index) => Type::Tuple(Tuple::from(*index, instance)),
887            InterfaceType::Variant(index) => Type::Variant(Variant::from(*index, instance)),
888            InterfaceType::Enum(index) => Type::Enum(Enum::from(*index, instance)),
889            InterfaceType::Option(index) => Type::Option(OptionType::from(*index, instance)),
890            InterfaceType::Result(index) => Type::Result(ResultType::from(*index, instance)),
891            InterfaceType::Flags(index) => Type::Flags(Flags::from(*index, instance)),
892            InterfaceType::Own(index) => Type::Own(instance.resource_type(*index)),
893            InterfaceType::Borrow(index) => Type::Borrow(instance.resource_type(*index)),
894            InterfaceType::Future(index) => Type::Future(instance.future_type(*index)),
895            InterfaceType::Stream(index) => Type::Stream(instance.stream_type(*index)),
896            InterfaceType::ErrorContext(_) => Type::ErrorContext,
897            InterfaceType::FixedLengthList(_) => todo!(), // FIXME(#12279)
898        }
899    }
900
901    fn desc(&self) -> &'static str {
902        match self {
903            Type::Bool => "bool",
904            Type::S8 => "s8",
905            Type::U8 => "u8",
906            Type::S16 => "s16",
907            Type::U16 => "u16",
908            Type::S32 => "s32",
909            Type::U32 => "u32",
910            Type::S64 => "s64",
911            Type::U64 => "u64",
912            Type::Float32 => "float32",
913            Type::Float64 => "float64",
914            Type::Char => "char",
915            Type::String => "string",
916            Type::List(_) => "list",
917            Type::Map(_) => "map",
918            Type::Record(_) => "record",
919            Type::Tuple(_) => "tuple",
920            Type::Variant(_) => "variant",
921            Type::Enum(_) => "enum",
922            Type::Option(_) => "option",
923            Type::Result(_) => "result",
924            Type::Flags(_) => "flags",
925            Type::Own(_) => "own",
926            Type::Borrow(_) => "borrow",
927            Type::Future(_) => "future",
928            Type::Stream(_) => "stream",
929            Type::ErrorContext => "error-context",
930        }
931    }
932}
933
934/// Component function type
935#[derive(Clone, Debug)]
936pub struct ComponentFunc(Handle<TypeFuncIndex>);
937
938impl ComponentFunc {
939    pub(crate) fn from(index: TypeFuncIndex, ty: &InstanceType<'_>) -> Self {
940        Self(Handle::new(index, ty))
941    }
942
943    /// Returns whether this is an async function
944    pub fn async_(&self) -> bool {
945        self.0.types[self.0.index].async_
946    }
947
948    /// Iterates over types of function parameters and names.
949    pub fn params(&self) -> impl ExactSizeIterator<Item = (&str, Type)> + '_ {
950        let ty = &self.0.types[self.0.index];
951        self.0.types[ty.params]
952            .types
953            .iter()
954            .zip(&ty.param_names)
955            .map(|(ty, name)| (name.as_str(), Type::from(ty, &self.0.instance())))
956    }
957
958    /// Iterates over types of function results
959    pub fn results(&self) -> impl ExactSizeIterator<Item = Type> + '_ {
960        let results = self.0.types[self.0.index].results;
961        self.0.types[results]
962            .types
963            .iter()
964            .map(|ty| Type::from(ty, &self.0.instance()))
965    }
966
967    #[doc(hidden)]
968    pub fn typecheck<Params, Return>(&self, cx: &InstanceType) -> crate::Result<()>
969    where
970        Params: crate::component::ComponentNamedList + crate::component::Lower,
971        Return: crate::component::ComponentNamedList + crate::component::Lift,
972    {
973        let ty = &self.0.types[self.0.index];
974        Params::typecheck(&InterfaceType::Tuple(ty.params), cx)?;
975        Return::typecheck(&InterfaceType::Tuple(ty.results), cx)?;
976        Ok(())
977    }
978}
979
980/// Core module type
981#[derive(Clone, Debug)]
982pub struct Module(Handle<TypeModuleIndex>);
983
984impl Module {
985    pub(crate) fn from(index: TypeModuleIndex, ty: &InstanceType<'_>) -> Self {
986        Self(Handle::new(index, ty))
987    }
988
989    /// Iterates over imports of the module
990    pub fn imports<'a>(
991        &'a self,
992        engine: &'a Engine,
993    ) -> impl ExactSizeIterator<Item = ((&'a str, &'a str), ExternType)> + 'a {
994        self.0.types[self.0.index]
995            .imports
996            .iter()
997            .map(|((namespace, name), ty)| {
998                (
999                    (namespace.as_str(), name.as_str()),
1000                    ExternType::from_wasmtime(engine, self.0.types.module_types(), ty),
1001                )
1002            })
1003    }
1004
1005    /// Iterates over exports of the module
1006    pub fn exports<'a>(
1007        &'a self,
1008        engine: &'a Engine,
1009    ) -> impl ExactSizeIterator<Item = (&'a str, ExternType)> + 'a {
1010        self.0.types[self.0.index].exports.iter().map(|(name, ty)| {
1011            (
1012                name.as_str(),
1013                ExternType::from_wasmtime(engine, self.0.types.module_types(), ty),
1014            )
1015        })
1016    }
1017}
1018
1019/// Component type
1020#[derive(Clone, Debug)]
1021pub struct Component(Handle<TypeComponentIndex>);
1022
1023impl Component {
1024    pub(crate) fn from(index: TypeComponentIndex, ty: &InstanceType<'_>) -> Self {
1025        Self(Handle::new(index, ty))
1026    }
1027
1028    /// Returns import associated with `name`, if such exists in the component
1029    pub fn get_import(&self, engine: &Engine, name: &str) -> Option<ComponentItem> {
1030        self.0.types[self.0.index]
1031            .imports
1032            .get(name)
1033            .map(|ty| ComponentItem::from(engine, ty, &self.0.instance()))
1034    }
1035
1036    /// Iterates over imports of the component
1037    pub fn imports<'a>(
1038        &'a self,
1039        engine: &'a Engine,
1040    ) -> impl ExactSizeIterator<Item = (&'a str, ComponentItem)> + 'a {
1041        self.0.types[self.0.index].imports.iter().map(|(name, ty)| {
1042            (
1043                name.as_str(),
1044                ComponentItem::from(engine, ty, &self.0.instance()),
1045            )
1046        })
1047    }
1048
1049    /// Returns export associated with `name`, if such exists in the component
1050    pub fn get_export(&self, engine: &Engine, name: &str) -> Option<ComponentItem> {
1051        self.0.types[self.0.index]
1052            .exports
1053            .get(name)
1054            .map(|ty| ComponentItem::from(engine, ty, &self.0.instance()))
1055    }
1056
1057    /// Iterates over exports of the component
1058    pub fn exports<'a>(
1059        &'a self,
1060        engine: &'a Engine,
1061    ) -> impl ExactSizeIterator<Item = (&'a str, ComponentItem)> + 'a {
1062        self.0.types[self.0.index].exports.iter().map(|(name, ty)| {
1063            (
1064                name.as_str(),
1065                ComponentItem::from(engine, ty, &self.0.instance()),
1066            )
1067        })
1068    }
1069
1070    #[doc(hidden)]
1071    pub fn instance_type(&self) -> InstanceType<'_> {
1072        InstanceType {
1073            types: &self.0.types,
1074            resources: &self.0.resources,
1075        }
1076    }
1077}
1078
1079/// Component instance type
1080#[derive(Clone, Debug)]
1081pub struct ComponentInstance(Handle<TypeComponentInstanceIndex>);
1082
1083impl ComponentInstance {
1084    pub(crate) fn from(index: TypeComponentInstanceIndex, ty: &InstanceType<'_>) -> Self {
1085        Self(Handle::new(index, ty))
1086    }
1087
1088    /// Returns export associated with `name`, if such exists in the component instance
1089    pub fn get_export(&self, engine: &Engine, name: &str) -> Option<ComponentItem> {
1090        self.0.types[self.0.index]
1091            .exports
1092            .get(name)
1093            .map(|ty| ComponentItem::from(engine, ty, &self.0.instance()))
1094    }
1095
1096    /// Iterates over exports of the component instance
1097    pub fn exports<'a>(
1098        &'a self,
1099        engine: &'a Engine,
1100    ) -> impl ExactSizeIterator<Item = (&'a str, ComponentItem)> {
1101        self.0.types[self.0.index].exports.iter().map(|(name, ty)| {
1102            (
1103                name.as_str(),
1104                ComponentItem::from(engine, ty, &self.0.instance()),
1105            )
1106        })
1107    }
1108}
1109
1110/// Type of an item contained within the component
1111#[derive(Clone, Debug)]
1112pub enum ComponentItem {
1113    /// Component function item
1114    ComponentFunc(ComponentFunc),
1115    /// Core function item
1116    CoreFunc(FuncType),
1117    /// Core module item
1118    Module(Module),
1119    /// Component item
1120    Component(Component),
1121    /// Component instance item
1122    ComponentInstance(ComponentInstance),
1123    /// Interface type item
1124    Type(Type),
1125    /// Resource item
1126    Resource(ResourceType),
1127}
1128
1129impl ComponentItem {
1130    pub(crate) fn from(engine: &Engine, def: &TypeDef, ty: &InstanceType<'_>) -> Self {
1131        match def {
1132            TypeDef::Component(idx) => Self::Component(Component::from(*idx, ty)),
1133            TypeDef::ComponentInstance(idx) => {
1134                Self::ComponentInstance(ComponentInstance::from(*idx, ty))
1135            }
1136            TypeDef::ComponentFunc(idx) => Self::ComponentFunc(ComponentFunc::from(*idx, ty)),
1137            TypeDef::Interface(iface_ty) => Self::Type(Type::from(iface_ty, ty)),
1138            TypeDef::Module(idx) => Self::Module(Module::from(*idx, ty)),
1139            TypeDef::CoreFunc(idx) => {
1140                let subty = &ty.types[*idx];
1141                Self::CoreFunc(
1142                    FuncType::from_wasm_func_type(
1143                        engine,
1144                        subty.is_final,
1145                        subty.supertype,
1146                        subty.unwrap_func().try_clone().panic_on_oom(),
1147                    )
1148                    .panic_on_oom(),
1149                )
1150            }
1151            TypeDef::Resource(idx) => match ty.types[*idx] {
1152                TypeResourceTable::Concrete {
1153                    ty: resource_index, ..
1154                } => {
1155                    let ty = match ty.resources.get(resource_index) {
1156                        // This resource type was substituted by a linker for
1157                        // example so it's replaced here.
1158                        Some(ty) => *ty,
1159
1160                        // This resource type was not substituted.
1161                        None => ResourceType::uninstantiated(&ty.types, resource_index),
1162                    };
1163                    Self::Resource(ty)
1164                }
1165                TypeResourceTable::Abstract(resource_index) => {
1166                    Self::Resource(ResourceType::abstract_(&ty.types, resource_index))
1167                }
1168            },
1169        }
1170    }
1171    pub(crate) fn from_export(engine: &Engine, export: &Export, ty: &InstanceType<'_>) -> Self {
1172        match export {
1173            Export::Instance { ty: idx, .. } => {
1174                Self::ComponentInstance(ComponentInstance::from(*idx, ty))
1175            }
1176            Export::LiftedFunction { ty: idx, .. } => {
1177                Self::ComponentFunc(ComponentFunc::from(*idx, ty))
1178            }
1179            Export::ModuleStatic { ty: idx, .. } | Export::ModuleImport { ty: idx, .. } => {
1180                Self::Module(Module::from(*idx, ty))
1181            }
1182            Export::Type(idx) => Self::from(engine, idx, ty),
1183        }
1184    }
1185}