1 //! This module defines the `Type` type, representing the dynamic form of a component interface type.
2
3 #[cfg(feature = "component-model-async")]
4 use crate::component::ComponentType;
5 use crate::component::matching::InstanceType;
6 use crate::{Engine, ExternType, FuncType, prelude::*};
7 use alloc::sync::Arc;
8 use core::fmt;
9 use core::ops::Deref;
10 use 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 };
17 use wasmtime_environ::{PanicOnOom as _, PrimaryMap};
18
19 pub 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)]
40 struct Handle<T> {
41 index: T,
42 types: Arc<ComponentTypes>,
43 resources: Arc<PrimaryMap<ResourceIndex, ResourceType>>,
44 }
45
46 impl<T> Handle<T> {
new(index: T, ty: &InstanceType<'_>) -> 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
instance(&self) -> InstanceType<'_>55 fn instance(&self) -> InstanceType<'_> {
56 InstanceType {
57 types: &self.types,
58 resources: &self.resources,
59 }
60 }
61
equivalent<'a>( &'a self, other: &'a Self, type_check: fn(&TypeChecker<'a>, T, T) -> bool, ) -> bool where T: PartialEq + Copy,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
86 impl<T: fmt::Debug> fmt::Debug for Handle<T> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result87 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
95 struct 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
102 impl TypeChecker<'_> {
interface_types_equal(&self, a: InterfaceType, b: InterfaceType) -> bool103 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
lists_equal(&self, l1: TypeListIndex, l2: TypeListIndex) -> bool167 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
maps_equal(&self, m1: TypeMapIndex, m2: TypeMapIndex) -> bool173 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
resources_equal(&self, o1: TypeResourceTableIndex, o2: TypeResourceTableIndex) -> bool179 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
records_equal(&self, r1: TypeRecordIndex, r2: TypeRecordIndex) -> bool199 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
variants_equal(&self, v1: TypeVariantIndex, v2: TypeVariantIndex) -> bool213 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
results_equal(&self, r1: TypeResultIndex, r2: TypeResultIndex) -> bool236 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
options_equal(&self, o1: TypeOptionIndex, o2: TypeOptionIndex) -> bool254 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
enums_equal(&self, e1: TypeEnumIndex, e2: TypeEnumIndex) -> bool260 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
tuples_equal(&self, t1: TypeTupleIndex, t2: TypeTupleIndex) -> bool266 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
flags_equal(&self, f1: TypeFlagsIndex, f2: TypeFlagsIndex) -> bool278 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
future_table_types_equal(&self, t1: TypeFutureTableIndex, t2: TypeFutureTableIndex) -> bool284 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
futures_equal(&self, t1: TypeFutureIndex, t2: TypeFutureIndex) -> bool288 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
stream_table_types_equal(&self, t1: TypeStreamTableIndex, t2: TypeStreamTableIndex) -> bool298 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
streams_equal(&self, t1: TypeStreamIndex, t2: TypeStreamIndex) -> bool302 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)]
315 pub struct List(Handle<TypeListIndex>);
316
317 impl PartialEq for List {
eq(&self, other: &Self) -> bool318 fn eq(&self, other: &Self) -> bool {
319 self.0.equivalent(&other.0, TypeChecker::lists_equal)
320 }
321 }
322
323 impl Eq for List {}
324
325 impl List {
from(index: TypeListIndex, ty: &InstanceType<'_>) -> Self326 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`.
ty(&self) -> Type331 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)]
338 pub struct Map(Handle<TypeMapIndex>);
339
340 impl PartialEq for Map {
eq(&self, other: &Self) -> bool341 fn eq(&self, other: &Self) -> bool {
342 self.0.equivalent(&other.0, TypeChecker::maps_equal)
343 }
344 }
345
346 impl Eq for Map {}
347
348 impl Map {
from(index: TypeMapIndex, ty: &InstanceType<'_>) -> Self349 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`.
key(&self) -> Type354 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`.
value(&self) -> Type359 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)]
366 pub 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)]
375 pub struct Record(Handle<TypeRecordIndex>);
376
377 impl Record {
from(index: TypeRecordIndex, ty: &InstanceType<'_>) -> Self378 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.
fields(&self) -> impl ExactSizeIterator<Item = Field<'_>>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
391 impl PartialEq for Record {
eq(&self, other: &Self) -> bool392 fn eq(&self, other: &Self) -> bool {
393 self.0.equivalent(&other.0, TypeChecker::records_equal)
394 }
395 }
396
397 impl Eq for Record {}
398
399 /// A `tuple` interface type
400 #[derive(Clone, Debug)]
401 pub struct Tuple(Handle<TypeTupleIndex>);
402
403 impl Tuple {
from(index: TypeTupleIndex, ty: &InstanceType<'_>) -> Self404 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.
types(&self) -> impl ExactSizeIterator<Item = Type> + '_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
417 impl PartialEq for Tuple {
eq(&self, other: &Self) -> bool418 fn eq(&self, other: &Self) -> bool {
419 self.0.equivalent(&other.0, TypeChecker::tuples_equal)
420 }
421 }
422
423 impl Eq for Tuple {}
424
425 /// A case declaration belonging to a `variant`
426 pub 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)]
435 pub struct Variant(Handle<TypeVariantIndex>);
436
437 impl Variant {
from(index: TypeVariantIndex, ty: &InstanceType<'_>) -> Self438 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.
cases(&self) -> impl ExactSizeIterator<Item = Case<'_>>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
454 impl PartialEq for Variant {
eq(&self, other: &Self) -> bool455 fn eq(&self, other: &Self) -> bool {
456 self.0.equivalent(&other.0, TypeChecker::variants_equal)
457 }
458 }
459
460 impl Eq for Variant {}
461
462 /// An `enum` interface type
463 #[derive(Clone, Debug)]
464 pub struct Enum(Handle<TypeEnumIndex>);
465
466 impl Enum {
from(index: TypeEnumIndex, ty: &InstanceType<'_>) -> Self467 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.
names(&self) -> impl ExactSizeIterator<Item = &str>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
480 impl PartialEq for Enum {
eq(&self, other: &Self) -> bool481 fn eq(&self, other: &Self) -> bool {
482 self.0.equivalent(&other.0, TypeChecker::enums_equal)
483 }
484 }
485
486 impl Eq for Enum {}
487
488 /// An `option` interface type
489 #[derive(Clone, Debug)]
490 pub struct OptionType(Handle<TypeOptionIndex>);
491
492 impl OptionType {
from(index: TypeOptionIndex, ty: &InstanceType<'_>) -> Self493 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`.
ty(&self) -> Type498 pub fn ty(&self) -> Type {
499 Type::from(&self.0.types[self.0.index].ty, &self.0.instance())
500 }
501 }
502
503 impl PartialEq for OptionType {
eq(&self, other: &Self) -> bool504 fn eq(&self, other: &Self) -> bool {
505 self.0.equivalent(&other.0, TypeChecker::options_equal)
506 }
507 }
508
509 impl Eq for OptionType {}
510
511 /// A `result` interface type
512 #[derive(Clone, Debug)]
513 pub struct ResultType(Handle<TypeResultIndex>);
514
515 impl ResultType {
from(index: TypeResultIndex, ty: &InstanceType<'_>) -> Self516 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`.
ok(&self) -> Option<Type>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`.
err(&self) -> Option<Type>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
537 impl PartialEq for ResultType {
eq(&self, other: &Self) -> bool538 fn eq(&self, other: &Self) -> bool {
539 self.0.equivalent(&other.0, TypeChecker::results_equal)
540 }
541 }
542
543 impl Eq for ResultType {}
544
545 /// A `flags` interface type
546 #[derive(Clone, Debug)]
547 pub struct Flags(Handle<TypeFlagsIndex>);
548
549 impl Flags {
from(index: TypeFlagsIndex, ty: &InstanceType<'_>) -> Self550 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.
names(&self) -> impl ExactSizeIterator<Item = &str>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
563 impl PartialEq for Flags {
eq(&self, other: &Self) -> bool564 fn eq(&self, other: &Self) -> bool {
565 self.0.equivalent(&other.0, TypeChecker::flags_equal)
566 }
567 }
568
569 impl Eq for Flags {}
570
571 #[cfg(feature = "component-model-async")]
typecheck_payload<T>( payload: Option<&InterfaceType>, types: &InstanceType<'_>, ) -> crate::Result<()> where T: ComponentType,572 pub(crate) fn typecheck_payload<T>(
573 payload: Option<&InterfaceType>,
574 types: &InstanceType<'_>,
575 ) -> crate::Result<()>
576 where
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)]
593 pub struct FutureType(Handle<TypeFutureIndex>);
594
595 impl FutureType {
from(index: TypeFutureIndex, ty: &InstanceType<'_>) -> Self596 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`.
ty(&self) -> Option<Type>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")]
equivalent_payload_guest( &self, ty: &InstanceType<'_>, payload: Option<&InterfaceType>, ) -> bool609 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")]
equivalent_payload_host<T>(&self) -> crate::Result<()> where T: ComponentType,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
640 impl PartialEq for FutureType {
eq(&self, other: &Self) -> bool641 fn eq(&self, other: &Self) -> bool {
642 self.0.equivalent(&other.0, TypeChecker::futures_equal)
643 }
644 }
645
646 impl Eq for FutureType {}
647
648 /// An `stream` interface type
649 #[derive(Clone, Debug)]
650 pub struct StreamType(Handle<TypeStreamIndex>);
651
652 impl StreamType {
from(index: TypeStreamIndex, ty: &InstanceType<'_>) -> Self653 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`.
ty(&self) -> Option<Type>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")]
equivalent_payload_guest( &self, ty: &InstanceType<'_>, payload: Option<&InterfaceType>, ) -> bool666 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")]
equivalent_payload_host<T>(&self) -> crate::Result<()> where T: ComponentType,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
697 impl PartialEq for StreamType {
eq(&self, other: &Self) -> bool698 fn eq(&self, other: &Self) -> bool {
699 self.0.equivalent(&other.0, TypeChecker::streams_equal)
700 }
701 }
702
703 impl 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")]
708 pub 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
738 impl 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`].
unwrap_list(&self) -> &List744 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`].
unwrap_record(&self) -> &Record757 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`].
unwrap_tuple(&self) -> &Tuple770 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`].
unwrap_variant(&self) -> &Variant783 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`].
unwrap_enum(&self) -> &Enum796 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`].
unwrap_option(&self) -> &OptionType809 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`].
unwrap_result(&self) -> &ResultType822 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`].
unwrap_flags(&self) -> &Flags835 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`].
unwrap_own(&self) -> &ResourceType848 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`].
unwrap_borrow(&self) -> &ResourceType860 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`.
from(ty: &InterfaceType, instance: &InstanceType<'_>) -> Self868 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
desc(&self) -> &'static str901 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)]
936 pub struct ComponentFunc(Handle<TypeFuncIndex>);
937
938 impl ComponentFunc {
from(index: TypeFuncIndex, ty: &InstanceType<'_>) -> Self939 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
async_(&self) -> bool944 pub fn async_(&self) -> bool {
945 self.0.types[self.0.index].async_
946 }
947
948 /// Iterates over types of function parameters and names.
params(&self) -> impl ExactSizeIterator<Item = (&str, Type)> + '_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
results(&self) -> impl ExactSizeIterator<Item = Type> + '_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)]
typecheck<Params, Return>(&self, cx: &InstanceType) -> crate::Result<()> where Params: crate::component::ComponentNamedList + crate::component::Lower, Return: crate::component::ComponentNamedList + crate::component::Lift,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)]
982 pub struct Module(Handle<TypeModuleIndex>);
983
984 impl Module {
from(index: TypeModuleIndex, ty: &InstanceType<'_>) -> Self985 pub(crate) fn from(index: TypeModuleIndex, ty: &InstanceType<'_>) -> Self {
986 Self(Handle::new(index, ty))
987 }
988
989 /// Iterates over imports of the module
imports<'a>( &'a self, engine: &'a Engine, ) -> impl ExactSizeIterator<Item = ((&'a str, &'a str), ExternType)> + 'a990 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
exports<'a>( &'a self, engine: &'a Engine, ) -> impl ExactSizeIterator<Item = (&'a str, ExternType)> + 'a1006 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)]
1021 pub struct Component(Handle<TypeComponentIndex>);
1022
1023 impl Component {
from(index: TypeComponentIndex, ty: &InstanceType<'_>) -> Self1024 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
get_import(&self, engine: &Engine, name: &str) -> Option<ComponentItem>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
imports<'a>( &'a self, engine: &'a Engine, ) -> impl ExactSizeIterator<Item = (&'a str, ComponentItem)> + 'a1037 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
get_export(&self, engine: &Engine, name: &str) -> Option<ComponentItem>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
exports<'a>( &'a self, engine: &'a Engine, ) -> impl ExactSizeIterator<Item = (&'a str, ComponentItem)> + 'a1058 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)]
instance_type(&self) -> InstanceType<'_>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)]
1081 pub struct ComponentInstance(Handle<TypeComponentInstanceIndex>);
1082
1083 impl ComponentInstance {
from(index: TypeComponentInstanceIndex, ty: &InstanceType<'_>) -> Self1084 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
get_export(&self, engine: &Engine, name: &str) -> Option<ComponentItem>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
exports<'a>( &'a self, engine: &'a Engine, ) -> impl ExactSizeIterator<Item = (&'a str, ComponentItem)>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)]
1112 pub 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
1129 impl ComponentItem {
from(engine: &Engine, def: &TypeDef, ty: &InstanceType<'_>) -> Self1130 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 }
from_export(engine: &Engine, export: &Export, ty: &InstanceType<'_>) -> Self1171 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 }
1186