1#[cfg(feature = "component-model-async")]
4use crate::component::ComponentType;
5use crate::component::matching::InstanceType;
6use crate::component::{ResourceAny, Val};
7use crate::{AsContextMut, Engine, ExternType, FuncType, StoreContextMut, prelude::*};
8use alloc::sync::Arc;
9use core::fmt;
10use core::ops::Deref;
11use wasmtime_environ::PanicOnOom as _;
12use wasmtime_environ::component::{
13 ComponentTypes, Export, InterfaceType, ResourceIndex, TypeComponentIndex,
14 TypeComponentInstanceIndex, TypeDef, TypeEnumIndex, TypeFixedLengthListIndex, TypeFlagsIndex,
15 TypeFuncIndex, TypeFutureIndex, TypeFutureTableIndex, TypeListIndex, TypeMapIndex,
16 TypeModuleIndex, TypeOptionIndex, TypeRecordIndex, TypeResourceTable, TypeResourceTableIndex,
17 TypeResultIndex, TypeStreamIndex, TypeStreamTableIndex, TypeTupleIndex, TypeVariantIndex,
18 alternate_lookup_key,
19};
20
21pub use crate::component::resources::ResourceType;
22
23#[derive(Clone)]
43struct Handle<T> {
44 index: T,
45 types: Arc<ComponentTypes>,
46 resources: Option<Arc<TryPrimaryMap<ResourceIndex, ResourceType>>>,
47}
48
49impl<T> Handle<T> {
50 fn new(index: T, ty: &InstanceType<'_>) -> Handle<T> {
51 Handle {
52 index,
53 types: ty.types.clone(),
54 resources: ty.resources.cloned(),
55 }
56 }
57
58 fn instance(&self) -> InstanceType<'_> {
59 InstanceType {
60 types: &self.types,
61 resources: self.resources.as_ref(),
62 }
63 }
64
65 fn equivalent<'a>(
66 &'a self,
67 other: &'a Self,
68 type_check: fn(&TypeChecker<'a>, T, T) -> bool,
69 ) -> bool
70 where
71 T: PartialEq + Copy,
72 {
73 (self.index == other.index
74 && Arc::ptr_eq(&self.types, &other.types)
75 && match (&self.resources, &other.resources) {
76 (Some(a), Some(b)) => Arc::ptr_eq(a, b),
77 (None, None) => true,
78 _ => false,
79 })
80 || type_check(
81 &TypeChecker {
82 a_types: &self.types,
83 b_types: &other.types,
84 a_resource: self.resources.as_deref(),
85 b_resource: other.resources.as_deref(),
86 },
87 self.index,
88 other.index,
89 )
90 }
91}
92
93impl<T: fmt::Debug> fmt::Debug for Handle<T> {
94 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95 f.debug_struct("Handle")
96 .field("index", &self.index)
97 .finish()
98 }
99}
100
101struct TypeChecker<'a> {
103 a_types: &'a ComponentTypes,
104 a_resource: Option<&'a TryPrimaryMap<ResourceIndex, ResourceType>>,
105 b_types: &'a ComponentTypes,
106 b_resource: Option<&'a TryPrimaryMap<ResourceIndex, ResourceType>>,
107}
108
109impl TypeChecker<'_> {
110 fn interface_types_equal(&self, a: InterfaceType, b: InterfaceType) -> bool {
111 match (a, b) {
112 (InterfaceType::Own(o1), InterfaceType::Own(o2)) => self.resources_equal(o1, o2),
113 (InterfaceType::Own(_), _) => false,
114 (InterfaceType::Borrow(b1), InterfaceType::Borrow(b2)) => self.resources_equal(b1, b2),
115 (InterfaceType::Borrow(_), _) => false,
116 (InterfaceType::List(l1), InterfaceType::List(l2)) => self.lists_equal(l1, l2),
117 (InterfaceType::List(_), _) => false,
118 (InterfaceType::Map(m1), InterfaceType::Map(m2)) => self.maps_equal(m1, m2),
119 (InterfaceType::Map(_), _) => false,
120 (InterfaceType::Record(r1), InterfaceType::Record(r2)) => self.records_equal(r1, r2),
121 (InterfaceType::Record(_), _) => false,
122 (InterfaceType::Variant(v1), InterfaceType::Variant(v2)) => self.variants_equal(v1, v2),
123 (InterfaceType::Variant(_), _) => false,
124 (InterfaceType::Result(r1), InterfaceType::Result(r2)) => self.results_equal(r1, r2),
125 (InterfaceType::Result(_), _) => false,
126 (InterfaceType::Option(o1), InterfaceType::Option(o2)) => self.options_equal(o1, o2),
127 (InterfaceType::Option(_), _) => false,
128 (InterfaceType::Enum(e1), InterfaceType::Enum(e2)) => self.enums_equal(e1, e2),
129 (InterfaceType::Enum(_), _) => false,
130 (InterfaceType::Tuple(t1), InterfaceType::Tuple(t2)) => self.tuples_equal(t1, t2),
131 (InterfaceType::Tuple(_), _) => false,
132 (InterfaceType::Flags(f1), InterfaceType::Flags(f2)) => self.flags_equal(f1, f2),
133 (InterfaceType::Flags(_), _) => false,
134 (InterfaceType::Bool, InterfaceType::Bool) => true,
135 (InterfaceType::Bool, _) => false,
136 (InterfaceType::U8, InterfaceType::U8) => true,
137 (InterfaceType::U8, _) => false,
138 (InterfaceType::U16, InterfaceType::U16) => true,
139 (InterfaceType::U16, _) => false,
140 (InterfaceType::U32, InterfaceType::U32) => true,
141 (InterfaceType::U32, _) => false,
142 (InterfaceType::U64, InterfaceType::U64) => true,
143 (InterfaceType::U64, _) => false,
144 (InterfaceType::S8, InterfaceType::S8) => true,
145 (InterfaceType::S8, _) => false,
146 (InterfaceType::S16, InterfaceType::S16) => true,
147 (InterfaceType::S16, _) => false,
148 (InterfaceType::S32, InterfaceType::S32) => true,
149 (InterfaceType::S32, _) => false,
150 (InterfaceType::S64, InterfaceType::S64) => true,
151 (InterfaceType::S64, _) => false,
152 (InterfaceType::Float32, InterfaceType::Float32) => true,
153 (InterfaceType::Float32, _) => false,
154 (InterfaceType::Float64, InterfaceType::Float64) => true,
155 (InterfaceType::Float64, _) => false,
156 (InterfaceType::String, InterfaceType::String) => true,
157 (InterfaceType::String, _) => false,
158 (InterfaceType::Char, InterfaceType::Char) => true,
159 (InterfaceType::Char, _) => false,
160 (InterfaceType::Future(t1), InterfaceType::Future(t2)) => {
161 self.future_table_types_equal(t1, t2)
162 }
163 (InterfaceType::Future(_), _) => false,
164 (InterfaceType::Stream(t1), InterfaceType::Stream(t2)) => {
165 self.stream_table_types_equal(t1, t2)
166 }
167 (InterfaceType::Stream(_), _) => false,
168 (InterfaceType::ErrorContext(_), InterfaceType::ErrorContext(_)) => true,
169 (InterfaceType::ErrorContext(_), _) => false,
170 (InterfaceType::FixedLengthList(t1), InterfaceType::FixedLengthList(t2)) => {
171 self.fixed_length_lists_equal(t1, t2)
172 }
173 (InterfaceType::FixedLengthList(_), _) => false,
174 }
175 }
176
177 fn lists_equal(&self, l1: TypeListIndex, l2: TypeListIndex) -> bool {
178 let a = &self.a_types[l1];
179 let b = &self.b_types[l2];
180 self.interface_types_equal(a.element, b.element)
181 }
182
183 fn maps_equal(&self, m1: TypeMapIndex, m2: TypeMapIndex) -> bool {
184 let a = &self.a_types[m1];
185 let b = &self.b_types[m2];
186 self.interface_types_equal(a.key, b.key) && self.interface_types_equal(a.value, b.value)
187 }
188
189 fn fixed_length_lists_equal(
190 &self,
191 l1: wasmtime_environ::component::TypeFixedLengthListIndex,
192 l2: wasmtime_environ::component::TypeFixedLengthListIndex,
193 ) -> bool {
194 let a = &self.a_types[l1];
195 let b = &self.b_types[l2];
196 if a.size != b.size {
197 return false;
198 }
199 self.interface_types_equal(a.element, b.element)
200 }
201
202 fn resources_equal(&self, o1: TypeResourceTableIndex, o2: TypeResourceTableIndex) -> bool {
203 match (&self.a_types[o1], &self.b_types[o2]) {
204 (
208 TypeResourceTable::Concrete { ty: a, .. },
209 TypeResourceTable::Concrete { ty: b, .. },
210 ) => self.a_resource.unwrap()[*a] == self.b_resource.unwrap()[*b],
211 (TypeResourceTable::Concrete { .. }, _) => false,
212
213 (TypeResourceTable::Abstract(a), TypeResourceTable::Abstract(b)) => {
216 core::ptr::eq(self.a_types, self.b_types) && a == b
217 }
218 (TypeResourceTable::Abstract(_), _) => false,
219 }
220 }
221
222 fn records_equal(&self, r1: TypeRecordIndex, r2: TypeRecordIndex) -> bool {
223 let a = &self.a_types[r1];
224 let b = &self.b_types[r2];
225 if a.fields.len() != b.fields.len() {
226 return false;
227 }
228 a.fields
229 .iter()
230 .zip(b.fields.iter())
231 .all(|(a_field, b_field)| {
232 a_field.name == b_field.name && self.interface_types_equal(a_field.ty, b_field.ty)
233 })
234 }
235
236 fn variants_equal(&self, v1: TypeVariantIndex, v2: TypeVariantIndex) -> bool {
237 let a = &self.a_types[v1];
238 let b = &self.b_types[v2];
239 if a.cases.len() != b.cases.len() {
240 return false;
241 }
242 a.cases
243 .iter()
244 .zip(b.cases.iter())
245 .all(|((a_name, a_ty), (b_name, b_ty))| {
246 if a_name != b_name {
247 return false;
248 }
249 match (a_ty, b_ty) {
250 (Some(a_case_ty), Some(b_case_ty)) => {
251 self.interface_types_equal(*a_case_ty, *b_case_ty)
252 }
253 (None, None) => true,
254 _ => false,
255 }
256 })
257 }
258
259 fn results_equal(&self, r1: TypeResultIndex, r2: TypeResultIndex) -> bool {
260 let a = &self.a_types[r1];
261 let b = &self.b_types[r2];
262 let oks = match (a.ok, b.ok) {
263 (Some(ok1), Some(ok2)) => self.interface_types_equal(ok1, ok2),
264 (None, None) => true,
265 _ => false,
266 };
267 if !oks {
268 return false;
269 }
270 match (a.err, b.err) {
271 (Some(err1), Some(err2)) => self.interface_types_equal(err1, err2),
272 (None, None) => true,
273 _ => false,
274 }
275 }
276
277 fn options_equal(&self, o1: TypeOptionIndex, o2: TypeOptionIndex) -> bool {
278 let a = &self.a_types[o1];
279 let b = &self.b_types[o2];
280 self.interface_types_equal(a.ty, b.ty)
281 }
282
283 fn enums_equal(&self, e1: TypeEnumIndex, e2: TypeEnumIndex) -> bool {
284 let a = &self.a_types[e1];
285 let b = &self.b_types[e2];
286 a.names == b.names
287 }
288
289 fn tuples_equal(&self, t1: TypeTupleIndex, t2: TypeTupleIndex) -> bool {
290 let a = &self.a_types[t1];
291 let b = &self.b_types[t2];
292 if a.types.len() != b.types.len() {
293 return false;
294 }
295 a.types
296 .iter()
297 .zip(b.types.iter())
298 .all(|(&a, &b)| self.interface_types_equal(a, b))
299 }
300
301 fn flags_equal(&self, f1: TypeFlagsIndex, f2: TypeFlagsIndex) -> bool {
302 let a = &self.a_types[f1];
303 let b = &self.b_types[f2];
304 a.names == b.names
305 }
306
307 fn future_table_types_equal(&self, t1: TypeFutureTableIndex, t2: TypeFutureTableIndex) -> bool {
308 self.futures_equal(self.a_types[t1].ty, self.b_types[t2].ty)
309 }
310
311 fn futures_equal(&self, t1: TypeFutureIndex, t2: TypeFutureIndex) -> bool {
312 let a = &self.a_types[t1];
313 let b = &self.b_types[t2];
314 match (a.payload, b.payload) {
315 (Some(t1), Some(t2)) => self.interface_types_equal(t1, t2),
316 (None, None) => true,
317 _ => false,
318 }
319 }
320
321 fn stream_table_types_equal(&self, t1: TypeStreamTableIndex, t2: TypeStreamTableIndex) -> bool {
322 self.streams_equal(self.a_types[t1].ty, self.b_types[t2].ty)
323 }
324
325 fn streams_equal(&self, t1: TypeStreamIndex, t2: TypeStreamIndex) -> bool {
326 let a = &self.a_types[t1];
327 let b = &self.b_types[t2];
328 match (a.payload, b.payload) {
329 (Some(t1), Some(t2)) => self.interface_types_equal(t1, t2),
330 (None, None) => true,
331 _ => false,
332 }
333 }
334}
335
336#[derive(Clone, Debug)]
338pub struct List(Handle<TypeListIndex>);
339
340impl PartialEq for List {
341 fn eq(&self, other: &Self) -> bool {
342 self.0.equivalent(&other.0, TypeChecker::lists_equal)
343 }
344}
345
346impl Eq for List {}
347
348impl List {
349 pub(crate) fn from(index: TypeListIndex, ty: &InstanceType<'_>) -> Self {
350 List(Handle::new(index, ty))
351 }
352
353 pub fn ty(&self) -> Type {
355 Type::from(&self.0.types[self.0.index].element, &self.0.instance())
356 }
357}
358
359#[derive(Clone, Debug)]
361pub struct Map(Handle<TypeMapIndex>);
362
363impl PartialEq for Map {
364 fn eq(&self, other: &Self) -> bool {
365 self.0.equivalent(&other.0, TypeChecker::maps_equal)
366 }
367}
368
369impl Eq for Map {}
370
371impl Map {
372 pub(crate) fn from(index: TypeMapIndex, ty: &InstanceType<'_>) -> Self {
373 Map(Handle::new(index, ty))
374 }
375
376 pub fn key(&self) -> Type {
378 Type::from(&self.0.types[self.0.index].key, &self.0.instance())
379 }
380
381 pub fn value(&self) -> Type {
383 Type::from(&self.0.types[self.0.index].value, &self.0.instance())
384 }
385}
386#[derive(Clone, Debug)]
388pub struct FixedLengthList(Handle<TypeFixedLengthListIndex>);
389
390impl PartialEq for FixedLengthList {
391 fn eq(&self, other: &Self) -> bool {
392 self.0
393 .equivalent(&other.0, TypeChecker::fixed_length_lists_equal)
394 }
395}
396
397impl Eq for FixedLengthList {}
398
399impl FixedLengthList {
400 pub(crate) fn from(index: TypeFixedLengthListIndex, ty: &InstanceType<'_>) -> Self {
401 FixedLengthList(Handle::new(index, ty))
402 }
403
404 pub fn ty(&self) -> Type {
406 Type::from(&self.0.types[self.0.index].element, &self.0.instance())
407 }
408
409 pub fn len(&self) -> u32 {
411 self.0.types[self.0.index].size
412 }
413}
414
415#[derive(Debug)]
417pub struct Field<'a> {
418 pub name: &'a str,
420 pub ty: Type,
422}
423
424#[derive(Clone, Debug)]
426pub struct Record(Handle<TypeRecordIndex>);
427
428impl Record {
429 pub(crate) fn from(index: TypeRecordIndex, ty: &InstanceType<'_>) -> Self {
430 Record(Handle::new(index, ty))
431 }
432
433 pub fn fields(&self) -> impl ExactSizeIterator<Item = Field<'_>> {
435 self.0.types[self.0.index].fields.iter().map(|field| Field {
436 name: &field.name,
437 ty: Type::from(&field.ty, &self.0.instance()),
438 })
439 }
440}
441
442impl PartialEq for Record {
443 fn eq(&self, other: &Self) -> bool {
444 self.0.equivalent(&other.0, TypeChecker::records_equal)
445 }
446}
447
448impl Eq for Record {}
449
450#[derive(Clone, Debug)]
452pub struct Tuple(Handle<TypeTupleIndex>);
453
454impl Tuple {
455 pub(crate) fn from(index: TypeTupleIndex, ty: &InstanceType<'_>) -> Self {
456 Tuple(Handle::new(index, ty))
457 }
458
459 pub fn types(&self) -> impl ExactSizeIterator<Item = Type> + '_ {
461 self.0.types[self.0.index]
462 .types
463 .iter()
464 .map(|ty| Type::from(ty, &self.0.instance()))
465 }
466}
467
468impl PartialEq for Tuple {
469 fn eq(&self, other: &Self) -> bool {
470 self.0.equivalent(&other.0, TypeChecker::tuples_equal)
471 }
472}
473
474impl Eq for Tuple {}
475
476pub struct Case<'a> {
478 pub name: &'a str,
480 pub ty: Option<Type>,
482}
483
484#[derive(Clone, Debug)]
486pub struct Variant(Handle<TypeVariantIndex>);
487
488impl Variant {
489 pub(crate) fn from(index: TypeVariantIndex, ty: &InstanceType<'_>) -> Self {
490 Variant(Handle::new(index, ty))
491 }
492
493 pub fn cases(&self) -> impl ExactSizeIterator<Item = Case<'_>> {
495 self.0.types[self.0.index]
496 .cases
497 .iter()
498 .map(|(name, ty)| Case {
499 name,
500 ty: ty.as_ref().map(|ty| Type::from(ty, &self.0.instance())),
501 })
502 }
503}
504
505impl PartialEq for Variant {
506 fn eq(&self, other: &Self) -> bool {
507 self.0.equivalent(&other.0, TypeChecker::variants_equal)
508 }
509}
510
511impl Eq for Variant {}
512
513#[derive(Clone, Debug)]
515pub struct Enum(Handle<TypeEnumIndex>);
516
517impl Enum {
518 pub(crate) fn from(index: TypeEnumIndex, ty: &InstanceType<'_>) -> Self {
519 Enum(Handle::new(index, ty))
520 }
521
522 pub fn names(&self) -> impl ExactSizeIterator<Item = &str> {
524 self.0.types[self.0.index]
525 .names
526 .iter()
527 .map(|name| name.deref())
528 }
529}
530
531impl PartialEq for Enum {
532 fn eq(&self, other: &Self) -> bool {
533 self.0.equivalent(&other.0, TypeChecker::enums_equal)
534 }
535}
536
537impl Eq for Enum {}
538
539#[derive(Clone, Debug)]
541pub struct OptionType(Handle<TypeOptionIndex>);
542
543impl OptionType {
544 pub(crate) fn from(index: TypeOptionIndex, ty: &InstanceType<'_>) -> Self {
545 OptionType(Handle::new(index, ty))
546 }
547
548 pub fn ty(&self) -> Type {
550 Type::from(&self.0.types[self.0.index].ty, &self.0.instance())
551 }
552}
553
554impl PartialEq for OptionType {
555 fn eq(&self, other: &Self) -> bool {
556 self.0.equivalent(&other.0, TypeChecker::options_equal)
557 }
558}
559
560impl Eq for OptionType {}
561
562#[derive(Clone, Debug)]
564pub struct ResultType(Handle<TypeResultIndex>);
565
566impl ResultType {
567 pub(crate) fn from(index: TypeResultIndex, ty: &InstanceType<'_>) -> Self {
568 ResultType(Handle::new(index, ty))
569 }
570
571 pub fn ok(&self) -> Option<Type> {
573 Some(Type::from(
574 self.0.types[self.0.index].ok.as_ref()?,
575 &self.0.instance(),
576 ))
577 }
578
579 pub fn err(&self) -> Option<Type> {
581 Some(Type::from(
582 self.0.types[self.0.index].err.as_ref()?,
583 &self.0.instance(),
584 ))
585 }
586}
587
588impl PartialEq for ResultType {
589 fn eq(&self, other: &Self) -> bool {
590 self.0.equivalent(&other.0, TypeChecker::results_equal)
591 }
592}
593
594impl Eq for ResultType {}
595
596#[derive(Clone, Debug)]
598pub struct Flags(Handle<TypeFlagsIndex>);
599
600impl Flags {
601 pub(crate) fn from(index: TypeFlagsIndex, ty: &InstanceType<'_>) -> Self {
602 Flags(Handle::new(index, ty))
603 }
604
605 pub fn names(&self) -> impl ExactSizeIterator<Item = &str> {
607 self.0.types[self.0.index]
608 .names
609 .iter()
610 .map(|name| name.deref())
611 }
612}
613
614impl PartialEq for Flags {
615 fn eq(&self, other: &Self) -> bool {
616 self.0.equivalent(&other.0, TypeChecker::flags_equal)
617 }
618}
619
620impl Eq for Flags {}
621
622#[cfg(feature = "component-model-async")]
623pub(crate) fn typecheck_payload<T>(
624 payload: Option<&InterfaceType>,
625 types: &InstanceType<'_>,
626) -> crate::Result<()>
627where
628 T: ComponentType,
629{
630 match payload {
631 Some(a) => T::typecheck(a, types),
632 None => {
633 if T::IS_RUST_UNIT_TYPE {
634 Ok(())
635 } else {
636 crate::bail!("future payload types differ")
637 }
638 }
639 }
640}
641
642#[derive(Clone, Debug)]
644pub struct FutureType(Handle<TypeFutureIndex>);
645
646impl FutureType {
647 pub(crate) fn from(index: TypeFutureIndex, ty: &InstanceType<'_>) -> Self {
648 FutureType(Handle::new(index, ty))
649 }
650
651 pub fn ty(&self) -> Option<Type> {
653 Some(Type::from(
654 self.0.types[self.0.index].payload.as_ref()?,
655 &self.0.instance(),
656 ))
657 }
658
659 #[cfg(feature = "component-model-async")]
660 pub(crate) fn equivalent_payload_guest(
661 &self,
662 ty: &InstanceType<'_>,
663 payload: Option<&InterfaceType>,
664 ) -> bool {
665 let my_payload = self.0.types[self.0.index].payload.as_ref();
666 match (my_payload, payload) {
667 (Some(a), Some(b)) => TypeChecker {
668 a_types: &self.0.types,
669 a_resource: self.0.resources.as_deref(),
670 b_types: ty.types,
671 b_resource: ty.resources.map(|p| &**p),
672 }
673 .interface_types_equal(*a, *b),
674 (None, None) => true,
675 (Some(_), None) | (None, Some(_)) => false,
676 }
677 }
678
679 #[cfg(feature = "component-model-async")]
680 pub(crate) fn equivalent_payload_host<T>(&self) -> crate::Result<()>
681 where
682 T: ComponentType,
683 {
684 typecheck_payload::<T>(
685 self.0.types[self.0.index].payload.as_ref(),
686 &self.0.instance(),
687 )
688 }
689}
690
691impl PartialEq for FutureType {
692 fn eq(&self, other: &Self) -> bool {
693 self.0.equivalent(&other.0, TypeChecker::futures_equal)
694 }
695}
696
697impl Eq for FutureType {}
698
699#[derive(Clone, Debug)]
701pub struct StreamType(Handle<TypeStreamIndex>);
702
703impl StreamType {
704 pub(crate) fn from(index: TypeStreamIndex, ty: &InstanceType<'_>) -> Self {
705 StreamType(Handle::new(index, ty))
706 }
707
708 pub fn ty(&self) -> Option<Type> {
710 Some(Type::from(
711 self.0.types[self.0.index].payload.as_ref()?,
712 &self.0.instance(),
713 ))
714 }
715
716 #[cfg(feature = "component-model-async")]
717 pub(crate) fn equivalent_payload_guest(
718 &self,
719 ty: &InstanceType<'_>,
720 payload: Option<&InterfaceType>,
721 ) -> bool {
722 let my_payload = self.0.types[self.0.index].payload.as_ref();
723 match (my_payload, payload) {
724 (Some(a), Some(b)) => TypeChecker {
725 a_types: &self.0.types,
726 a_resource: self.0.resources.as_deref(),
727 b_types: ty.types,
728 b_resource: ty.resources.map(|p| &**p),
729 }
730 .interface_types_equal(*a, *b),
731 (None, None) => true,
732 (Some(_), None) | (None, Some(_)) => false,
733 }
734 }
735
736 #[cfg(feature = "component-model-async")]
737 pub(crate) fn equivalent_payload_host<T>(&self) -> crate::Result<()>
738 where
739 T: ComponentType,
740 {
741 typecheck_payload::<T>(
742 self.0.types[self.0.index].payload.as_ref(),
743 &self.0.instance(),
744 )
745 }
746}
747
748impl PartialEq for StreamType {
749 fn eq(&self, other: &Self) -> bool {
750 self.0.equivalent(&other.0, TypeChecker::streams_equal)
751 }
752}
753
754impl Eq for StreamType {}
755
756#[derive(Clone, PartialEq, Eq, Debug)]
758#[expect(missing_docs, reason = "self-describing variants")]
759pub enum Type {
760 Bool,
761 S8,
762 U8,
763 S16,
764 U16,
765 S32,
766 U32,
767 S64,
768 U64,
769 Float32,
770 Float64,
771 Char,
772 String,
773 List(List),
774 Map(Map),
775 Record(Record),
776 Tuple(Tuple),
777 Variant(Variant),
778 Enum(Enum),
779 Option(OptionType),
780 Result(ResultType),
781 Flags(Flags),
782 Own(ResourceType),
783 Borrow(ResourceType),
784 Future(FutureType),
785 Stream(StreamType),
786 ErrorContext,
787 FixedLengthList(FixedLengthList),
788}
789
790impl Type {
791 pub fn unwrap_list(&self) -> &List {
797 if let Type::List(handle) = self {
798 &handle
799 } else {
800 panic!("attempted to unwrap a {} as a list", self.desc())
801 }
802 }
803
804 pub fn unwrap_map(&self) -> &Map {
810 if let Type::Map(handle) = self {
811 &handle
812 } else {
813 panic!("attempted to unwrap a {} as a map", self.desc())
814 }
815 }
816
817 pub fn unwrap_record(&self) -> &Record {
823 if let Type::Record(handle) = self {
824 &handle
825 } else {
826 panic!("attempted to unwrap a {} as a record", self.desc())
827 }
828 }
829
830 pub fn unwrap_tuple(&self) -> &Tuple {
836 if let Type::Tuple(handle) = self {
837 &handle
838 } else {
839 panic!("attempted to unwrap a {} as a tuple", self.desc())
840 }
841 }
842
843 pub fn unwrap_variant(&self) -> &Variant {
849 if let Type::Variant(handle) = self {
850 &handle
851 } else {
852 panic!("attempted to unwrap a {} as a variant", self.desc())
853 }
854 }
855
856 pub fn unwrap_enum(&self) -> &Enum {
862 if let Type::Enum(handle) = self {
863 &handle
864 } else {
865 panic!("attempted to unwrap a {} as a enum", self.desc())
866 }
867 }
868
869 pub fn unwrap_option(&self) -> &OptionType {
875 if let Type::Option(handle) = self {
876 &handle
877 } else {
878 panic!("attempted to unwrap a {} as a option", self.desc())
879 }
880 }
881
882 pub fn unwrap_result(&self) -> &ResultType {
888 if let Type::Result(handle) = self {
889 &handle
890 } else {
891 panic!("attempted to unwrap a {} as a result", self.desc())
892 }
893 }
894
895 pub fn unwrap_flags(&self) -> &Flags {
901 if let Type::Flags(handle) = self {
902 &handle
903 } else {
904 panic!("attempted to unwrap a {} as a flags", self.desc())
905 }
906 }
907
908 pub fn unwrap_own(&self) -> &ResourceType {
914 match self {
915 Type::Own(ty) => ty,
916 _ => panic!("attempted to unwrap a {} as a own", self.desc()),
917 }
918 }
919
920 pub fn unwrap_borrow(&self) -> &ResourceType {
926 match self {
927 Type::Borrow(ty) => ty,
928 _ => panic!("attempted to unwrap a {} as a own", self.desc()),
929 }
930 }
931
932 pub(crate) fn from(ty: &InterfaceType, instance: &InstanceType<'_>) -> Self {
934 match ty {
935 InterfaceType::Bool => Type::Bool,
936 InterfaceType::S8 => Type::S8,
937 InterfaceType::U8 => Type::U8,
938 InterfaceType::S16 => Type::S16,
939 InterfaceType::U16 => Type::U16,
940 InterfaceType::S32 => Type::S32,
941 InterfaceType::U32 => Type::U32,
942 InterfaceType::S64 => Type::S64,
943 InterfaceType::U64 => Type::U64,
944 InterfaceType::Float32 => Type::Float32,
945 InterfaceType::Float64 => Type::Float64,
946 InterfaceType::Char => Type::Char,
947 InterfaceType::String => Type::String,
948 InterfaceType::List(index) => Type::List(List::from(*index, instance)),
949 InterfaceType::Map(index) => Type::Map(Map::from(*index, instance)),
950 InterfaceType::Record(index) => Type::Record(Record::from(*index, instance)),
951 InterfaceType::Tuple(index) => Type::Tuple(Tuple::from(*index, instance)),
952 InterfaceType::Variant(index) => Type::Variant(Variant::from(*index, instance)),
953 InterfaceType::Enum(index) => Type::Enum(Enum::from(*index, instance)),
954 InterfaceType::Option(index) => Type::Option(OptionType::from(*index, instance)),
955 InterfaceType::Result(index) => Type::Result(ResultType::from(*index, instance)),
956 InterfaceType::Flags(index) => Type::Flags(Flags::from(*index, instance)),
957 InterfaceType::Own(index) => Type::Own(instance.resource_type(*index)),
958 InterfaceType::Borrow(index) => Type::Borrow(instance.resource_type(*index)),
959 InterfaceType::Future(index) => Type::Future(instance.future_type(*index)),
960 InterfaceType::Stream(index) => Type::Stream(instance.stream_type(*index)),
961 InterfaceType::ErrorContext(_) => Type::ErrorContext,
962 InterfaceType::FixedLengthList(index) => {
963 Type::FixedLengthList(FixedLengthList::from(*index, instance))
964 }
965 }
966 }
967
968 pub fn default_value(&self, mut store: impl AsContextMut) -> Result<Val> {
996 self.default_value_impl(store.as_context_mut())
997 }
998
999 fn default_value_impl<T>(&self, mut store: StoreContextMut<'_, T>) -> Result<Val> {
1001 Ok(match self {
1002 Type::Bool => Val::Bool(false),
1003 Type::S8 => Val::S8(0),
1004 Type::U8 => Val::U8(0),
1005 Type::S16 => Val::S16(0),
1006 Type::U16 => Val::U16(0),
1007 Type::S32 => Val::S32(0),
1008 Type::U32 => Val::U32(0),
1009 Type::S64 => Val::S64(0),
1010 Type::U64 => Val::U64(0),
1011 Type::Float32 => Val::Float32(0.0),
1012 Type::Float64 => Val::Float64(0.0),
1013 Type::Char => Val::Char('\0'),
1014 Type::String => Val::String(String::new()),
1015
1016 Type::List(_) => Val::List(Vec::new()),
1018 Type::Map(_) => Val::Map(Vec::new()),
1019 Type::Option(_) => Val::Option(None),
1020 Type::Flags(_) => Val::Flags(Vec::new()),
1021
1022 Type::Enum(e) => {
1023 let name = e.names().next().ok_or_else(|| {
1024 format_err!("no default value exists for an `enum` with no cases")
1025 })?;
1026 Val::Enum(name.to_string())
1027 }
1028
1029 Type::Record(record) => {
1030 let mut fields = TryVec::with_capacity(record.fields().len())?;
1031 for field in record.fields() {
1032 let val = field.ty.default_value_impl(store.as_context_mut())?;
1033 fields.push((field.name.to_string(), val))?;
1034 }
1035 Val::Record(fields.into())
1036 }
1037
1038 Type::Tuple(tuple) => {
1039 let mut vals = TryVec::with_capacity(tuple.types().len())?;
1040 for ty in tuple.types() {
1041 vals.push(ty.default_value_impl(store.as_context_mut())?)?;
1042 }
1043 Val::Tuple(vals.into())
1044 }
1045
1046 Type::Variant(variant) => {
1047 let case = variant.cases().next().ok_or_else(|| {
1048 format_err!("no default value exists for a `variant` with no cases")
1049 })?;
1050 let payload = match &case.ty {
1051 Some(ty) => Some(Box::new(ty.default_value_impl(store.as_context_mut())?)),
1052 None => None,
1053 };
1054 Val::Variant(case.name.to_string(), payload)
1055 }
1056
1057 Type::Result(result) => Val::Result(Ok(match result.ok() {
1058 Some(ty) => Some(Box::new(ty.default_value_impl(store.as_context_mut())?)),
1059 None => None,
1060 })),
1061
1062 Type::FixedLengthList(list) => {
1063 let element = list.ty().default_value_impl(store.as_context_mut())?;
1065 let len = usize::try_from(list.len())?;
1066 let mut vals = TryVec::with_capacity(len)?;
1067 for _ in 0..len {
1068 vals.push(element.clone())?;
1069 }
1070 Val::FixedLengthList(vals.into())
1071 }
1072
1073 Type::Own(ty) | Type::Borrow(ty) => {
1077 Val::Resource(ResourceAny::new_own_dynamic(*ty, 0, &mut store)?)
1078 }
1079
1080 Type::Future(_) | Type::Stream(_) | Type::ErrorContext => {
1081 bail!("no default value exists for type `{}`", self.desc())
1082 }
1083 })
1084 }
1085
1086 fn desc(&self) -> &'static str {
1087 match self {
1088 Type::Bool => "bool",
1089 Type::S8 => "s8",
1090 Type::U8 => "u8",
1091 Type::S16 => "s16",
1092 Type::U16 => "u16",
1093 Type::S32 => "s32",
1094 Type::U32 => "u32",
1095 Type::S64 => "s64",
1096 Type::U64 => "u64",
1097 Type::Float32 => "float32",
1098 Type::Float64 => "float64",
1099 Type::Char => "char",
1100 Type::String => "string",
1101 Type::List(_) => "list",
1102 Type::Map(_) => "map",
1103 Type::Record(_) => "record",
1104 Type::Tuple(_) => "tuple",
1105 Type::Variant(_) => "variant",
1106 Type::Enum(_) => "enum",
1107 Type::Option(_) => "option",
1108 Type::Result(_) => "result",
1109 Type::Flags(_) => "flags",
1110 Type::Own(_) => "own",
1111 Type::Borrow(_) => "borrow",
1112 Type::Future(_) => "future",
1113 Type::Stream(_) => "stream",
1114 Type::ErrorContext => "error-context",
1115 Type::FixedLengthList(_) => "list<_, N>",
1116 }
1117 }
1118}
1119
1120#[derive(Clone, Debug)]
1122pub struct ComponentFunc(Handle<TypeFuncIndex>);
1123
1124impl ComponentFunc {
1125 pub(crate) fn from(index: TypeFuncIndex, ty: &InstanceType<'_>) -> Self {
1126 Self(Handle::new(index, ty))
1127 }
1128
1129 pub fn async_(&self) -> bool {
1131 self.0.types[self.0.index].async_
1132 }
1133
1134 pub fn params(&self) -> impl ExactSizeIterator<Item = (&str, Type)> + '_ {
1136 let ty = &self.0.types[self.0.index];
1137 self.0.types[ty.params]
1138 .types
1139 .iter()
1140 .zip(&ty.param_names)
1141 .map(|(ty, name)| (name.as_str(), Type::from(ty, &self.0.instance())))
1142 }
1143
1144 pub fn results(&self) -> impl ExactSizeIterator<Item = Type> + '_ {
1146 let results = self.0.types[self.0.index].results;
1147 self.0.types[results]
1148 .types
1149 .iter()
1150 .map(|ty| Type::from(ty, &self.0.instance()))
1151 }
1152
1153 #[doc(hidden)]
1154 pub fn typecheck<Params, Return>(&self, cx: &InstanceType) -> crate::Result<()>
1155 where
1156 Params: crate::component::ComponentNamedList + crate::component::Lower,
1157 Return: crate::component::ComponentNamedList + crate::component::Lift,
1158 {
1159 let ty = &self.0.types[self.0.index];
1160 Params::typecheck(&InterfaceType::Tuple(ty.params), cx)?;
1161 Return::typecheck(&InterfaceType::Tuple(ty.results), cx)?;
1162 Ok(())
1163 }
1164}
1165
1166#[derive(Clone, Debug)]
1168pub struct Module(Handle<TypeModuleIndex>);
1169
1170impl Module {
1171 pub(crate) fn from(index: TypeModuleIndex, ty: &InstanceType<'_>) -> Self {
1172 Self(Handle::new(index, ty))
1173 }
1174
1175 pub fn imports<'a>(
1183 &'a self,
1184 engine: &'a Engine,
1185 ) -> impl ExactSizeIterator<Item = ((&'a str, &'a str), ExternType)> + 'a {
1186 self.0.types[self.0.index]
1187 .imports
1188 .iter()
1189 .map(|((namespace, name), ty)| {
1190 (
1191 (namespace.as_str(), name.as_str()),
1192 ExternType::from_wasmtime(engine, self.0.types.module_types(), ty),
1193 )
1194 })
1195 }
1196
1197 pub fn exports<'a>(
1205 &'a self,
1206 engine: &'a Engine,
1207 ) -> impl ExactSizeIterator<Item = (&'a str, ExternType)> + 'a {
1208 self.0.types[self.0.index].exports.iter().map(|(name, ty)| {
1209 (
1210 name.as_str(),
1211 ExternType::from_wasmtime(engine, self.0.types.module_types(), ty),
1212 )
1213 })
1214 }
1215}
1216
1217#[derive(Clone, Debug)]
1219pub struct Component(Handle<TypeComponentIndex>);
1220
1221impl Component {
1222 pub(crate) fn from(index: TypeComponentIndex, ty: &InstanceType<'_>) -> Self {
1223 Self(Handle::new(index, ty))
1224 }
1225
1226 pub fn get_import<'a>(&'a self, engine: &'a Engine, name: &str) -> Option<ComponentExtern<'a>> {
1234 self.0.types[self.0.index]
1235 .imports
1236 .get(name)
1237 .map(|e| ComponentExtern::new(engine, &self.0.instance(), e))
1238 }
1239
1240 pub fn imports<'a>(
1248 &'a self,
1249 engine: &'a Engine,
1250 ) -> impl ExactSizeIterator<Item = (&'a str, ComponentExtern<'a>)> + 'a {
1251 self.0.types[self.0.index].imports.iter().map(|(name, e)| {
1252 (
1253 name.as_str(),
1254 ComponentExtern::new(engine, &self.0.instance(), e),
1255 )
1256 })
1257 }
1258
1259 pub fn get_export<'a>(&'a self, engine: &'a Engine, name: &str) -> Option<ComponentExtern<'a>> {
1267 self.0.types[self.0.index]
1268 .exports
1269 .get(name)
1270 .map(|e| ComponentExtern::new(engine, &self.0.instance(), e))
1271 }
1272
1273 pub fn exports<'a>(
1281 &'a self,
1282 engine: &'a Engine,
1283 ) -> impl ExactSizeIterator<Item = (&'a str, ComponentExtern<'a>)> + 'a {
1284 self.0.types[self.0.index].exports.iter().map(|(name, e)| {
1285 (
1286 name.as_str(),
1287 ComponentExtern::new(engine, &self.0.instance(), e),
1288 )
1289 })
1290 }
1291
1292 #[doc(hidden)]
1293 pub fn instance_type(&self) -> InstanceType<'_> {
1294 InstanceType {
1295 types: &self.0.types,
1296 resources: self.0.resources.as_ref(),
1297 }
1298 }
1299}
1300
1301#[derive(Clone, Debug)]
1303pub struct ComponentInstance(Handle<TypeComponentInstanceIndex>);
1304
1305impl ComponentInstance {
1306 pub(crate) fn from(index: TypeComponentInstanceIndex, ty: &InstanceType<'_>) -> Self {
1307 Self(Handle::new(index, ty))
1308 }
1309
1310 pub fn get_export<'a>(&'a self, engine: &'a Engine, name: &str) -> Option<ComponentExtern<'a>> {
1318 self.0.types[self.0.index]
1319 .exports
1320 .get(name)
1321 .map(|e| ComponentExtern::new(engine, &self.0.instance(), e))
1322 }
1323
1324 pub fn exports<'a>(
1332 &'a self,
1333 engine: &'a Engine,
1334 ) -> impl ExactSizeIterator<Item = (&'a str, ComponentExtern<'a>)> {
1335 self.0.types[self.0.index].exports.iter().map(|(name, e)| {
1336 (
1337 name.as_str(),
1338 ComponentExtern::new(engine, &self.0.instance(), e),
1339 )
1340 })
1341 }
1342}
1343
1344#[derive(Clone, Debug)]
1349pub struct ComponentExtern<'a> {
1350 pub ty: ComponentItem,
1352 pub implements: Option<&'a str>,
1354 pub external_id: Option<&'a str>,
1359}
1360
1361impl<'a> ComponentExtern<'a> {
1362 fn new(
1363 engine: &'a Engine,
1364 instance_ty: &InstanceType<'_>,
1365 env: &'a wasmtime_environ::component::ComponentExtern,
1366 ) -> Self {
1367 Self {
1368 implements: env.data.implements.as_deref(),
1369 external_id: env.data.external_id.as_deref(),
1370 ty: ComponentItem::from(engine, &env.ty, instance_ty),
1371 }
1372 }
1373
1374 pub fn is_implements(&self, name: &str) -> bool {
1385 let implements = match self.implements {
1386 Some(s) => s,
1387 None => return false,
1388 };
1389 if name == implements {
1390 return true;
1391 }
1392
1393 let reduced = |name| alternate_lookup_key(name).map_or(name, |(name, _)| name);
1397 reduced(implements) == reduced(name)
1398 }
1399}
1400
1401#[derive(Clone, Debug)]
1403pub enum ComponentItem {
1404 ComponentFunc(ComponentFunc),
1406 CoreFunc(FuncType),
1408 Module(Module),
1410 Component(Component),
1412 ComponentInstance(ComponentInstance),
1414 Type(Type),
1416 Resource(ResourceType),
1418}
1419
1420impl ComponentItem {
1421 pub(crate) fn from(engine: &Engine, def: &TypeDef, ty: &InstanceType<'_>) -> Self {
1422 match def {
1423 TypeDef::Component(idx) => Self::Component(Component::from(*idx, ty)),
1424 TypeDef::ComponentInstance(idx) => {
1425 Self::ComponentInstance(ComponentInstance::from(*idx, ty))
1426 }
1427 TypeDef::ComponentFunc(idx) => Self::ComponentFunc(ComponentFunc::from(*idx, ty)),
1428 TypeDef::Interface(iface_ty) => Self::Type(Type::from(iface_ty, ty)),
1429 TypeDef::Module(idx) => Self::Module(Module::from(*idx, ty)),
1430 TypeDef::CoreFunc(idx) => {
1431 let subty = &ty.types[*idx];
1432 Self::CoreFunc(
1433 FuncType::from_wasm_func_type(
1434 engine,
1435 subty.is_final,
1436 subty.supertype,
1437 subty.unwrap_func().try_clone().panic_on_oom(),
1438 )
1439 .panic_on_oom(),
1440 )
1441 }
1442 TypeDef::Resource(idx) => match ty.types[*idx] {
1443 TypeResourceTable::Concrete {
1444 ty: resource_index, ..
1445 } => {
1446 let ty = match ty.resources.and_then(|t| t.get(resource_index)) {
1447 Some(ty) => *ty,
1450
1451 None => ResourceType::uninstantiated(&ty.types, resource_index),
1453 };
1454 Self::Resource(ty)
1455 }
1456 TypeResourceTable::Abstract(resource_index) => {
1457 Self::Resource(ResourceType::abstract_(&ty.types, resource_index))
1458 }
1459 },
1460 }
1461 }
1462 pub(crate) fn from_export(engine: &Engine, export: &Export, ty: &InstanceType<'_>) -> Self {
1463 match export {
1464 Export::Instance { ty: idx, .. } => {
1465 Self::ComponentInstance(ComponentInstance::from(*idx, ty))
1466 }
1467 Export::LiftedFunction { ty: idx, .. } => {
1468 Self::ComponentFunc(ComponentFunc::from(*idx, ty))
1469 }
1470 Export::ModuleStatic { ty: idx, .. } | Export::ModuleImport { ty: idx, .. } => {
1471 Self::Module(Module::from(*idx, ty))
1472 }
1473 Export::Type(idx) => Self::from(engine, idx, ty),
1474 }
1475 }
1476}