1#[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::PanicOnOom as _;
11use wasmtime_environ::component::{
12 ComponentTypes, Export, InterfaceType, ResourceIndex, TypeComponentIndex,
13 TypeComponentInstanceIndex, TypeDef, TypeEnumIndex, TypeFixedLengthListIndex, TypeFlagsIndex,
14 TypeFuncIndex, TypeFutureIndex, TypeFutureTableIndex, TypeListIndex, TypeMapIndex,
15 TypeModuleIndex, TypeOptionIndex, TypeRecordIndex, TypeResourceTable, TypeResourceTableIndex,
16 TypeResultIndex, TypeStreamIndex, TypeStreamTableIndex, TypeTupleIndex, TypeVariantIndex,
17 alternate_lookup_key,
18};
19
20pub use crate::component::resources::ResourceType;
21
22#[derive(Clone)]
42struct Handle<T> {
43 index: T,
44 types: Arc<ComponentTypes>,
45 resources: Option<Arc<TryPrimaryMap<ResourceIndex, ResourceType>>>,
46}
47
48impl<T> Handle<T> {
49 fn new(index: T, ty: &InstanceType<'_>) -> Handle<T> {
50 Handle {
51 index,
52 types: ty.types.clone(),
53 resources: ty.resources.cloned(),
54 }
55 }
56
57 fn instance(&self) -> InstanceType<'_> {
58 InstanceType {
59 types: &self.types,
60 resources: self.resources.as_ref(),
61 }
62 }
63
64 fn equivalent<'a>(
65 &'a self,
66 other: &'a Self,
67 type_check: fn(&TypeChecker<'a>, T, T) -> bool,
68 ) -> bool
69 where
70 T: PartialEq + Copy,
71 {
72 (self.index == other.index
73 && Arc::ptr_eq(&self.types, &other.types)
74 && match (&self.resources, &other.resources) {
75 (Some(a), Some(b)) => Arc::ptr_eq(a, b),
76 (None, None) => true,
77 _ => false,
78 })
79 || type_check(
80 &TypeChecker {
81 a_types: &self.types,
82 b_types: &other.types,
83 a_resource: self.resources.as_deref(),
84 b_resource: other.resources.as_deref(),
85 },
86 self.index,
87 other.index,
88 )
89 }
90}
91
92impl<T: fmt::Debug> fmt::Debug for Handle<T> {
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 f.debug_struct("Handle")
95 .field("index", &self.index)
96 .finish()
97 }
98}
99
100struct TypeChecker<'a> {
102 a_types: &'a ComponentTypes,
103 a_resource: Option<&'a TryPrimaryMap<ResourceIndex, ResourceType>>,
104 b_types: &'a ComponentTypes,
105 b_resource: Option<&'a TryPrimaryMap<ResourceIndex, ResourceType>>,
106}
107
108impl TypeChecker<'_> {
109 fn interface_types_equal(&self, a: InterfaceType, b: InterfaceType) -> bool {
110 match (a, b) {
111 (InterfaceType::Own(o1), InterfaceType::Own(o2)) => self.resources_equal(o1, o2),
112 (InterfaceType::Own(_), _) => false,
113 (InterfaceType::Borrow(b1), InterfaceType::Borrow(b2)) => self.resources_equal(b1, b2),
114 (InterfaceType::Borrow(_), _) => false,
115 (InterfaceType::List(l1), InterfaceType::List(l2)) => self.lists_equal(l1, l2),
116 (InterfaceType::List(_), _) => false,
117 (InterfaceType::Map(m1), InterfaceType::Map(m2)) => self.maps_equal(m1, m2),
118 (InterfaceType::Map(_), _) => false,
119 (InterfaceType::Record(r1), InterfaceType::Record(r2)) => self.records_equal(r1, r2),
120 (InterfaceType::Record(_), _) => false,
121 (InterfaceType::Variant(v1), InterfaceType::Variant(v2)) => self.variants_equal(v1, v2),
122 (InterfaceType::Variant(_), _) => false,
123 (InterfaceType::Result(r1), InterfaceType::Result(r2)) => self.results_equal(r1, r2),
124 (InterfaceType::Result(_), _) => false,
125 (InterfaceType::Option(o1), InterfaceType::Option(o2)) => self.options_equal(o1, o2),
126 (InterfaceType::Option(_), _) => false,
127 (InterfaceType::Enum(e1), InterfaceType::Enum(e2)) => self.enums_equal(e1, e2),
128 (InterfaceType::Enum(_), _) => false,
129 (InterfaceType::Tuple(t1), InterfaceType::Tuple(t2)) => self.tuples_equal(t1, t2),
130 (InterfaceType::Tuple(_), _) => false,
131 (InterfaceType::Flags(f1), InterfaceType::Flags(f2)) => self.flags_equal(f1, f2),
132 (InterfaceType::Flags(_), _) => false,
133 (InterfaceType::Bool, InterfaceType::Bool) => true,
134 (InterfaceType::Bool, _) => false,
135 (InterfaceType::U8, InterfaceType::U8) => true,
136 (InterfaceType::U8, _) => false,
137 (InterfaceType::U16, InterfaceType::U16) => true,
138 (InterfaceType::U16, _) => false,
139 (InterfaceType::U32, InterfaceType::U32) => true,
140 (InterfaceType::U32, _) => false,
141 (InterfaceType::U64, InterfaceType::U64) => true,
142 (InterfaceType::U64, _) => false,
143 (InterfaceType::S8, InterfaceType::S8) => true,
144 (InterfaceType::S8, _) => false,
145 (InterfaceType::S16, InterfaceType::S16) => true,
146 (InterfaceType::S16, _) => false,
147 (InterfaceType::S32, InterfaceType::S32) => true,
148 (InterfaceType::S32, _) => false,
149 (InterfaceType::S64, InterfaceType::S64) => true,
150 (InterfaceType::S64, _) => false,
151 (InterfaceType::Float32, InterfaceType::Float32) => true,
152 (InterfaceType::Float32, _) => false,
153 (InterfaceType::Float64, InterfaceType::Float64) => true,
154 (InterfaceType::Float64, _) => false,
155 (InterfaceType::String, InterfaceType::String) => true,
156 (InterfaceType::String, _) => false,
157 (InterfaceType::Char, InterfaceType::Char) => true,
158 (InterfaceType::Char, _) => false,
159 (InterfaceType::Future(t1), InterfaceType::Future(t2)) => {
160 self.future_table_types_equal(t1, t2)
161 }
162 (InterfaceType::Future(_), _) => false,
163 (InterfaceType::Stream(t1), InterfaceType::Stream(t2)) => {
164 self.stream_table_types_equal(t1, t2)
165 }
166 (InterfaceType::Stream(_), _) => false,
167 (InterfaceType::ErrorContext(_), InterfaceType::ErrorContext(_)) => true,
168 (InterfaceType::ErrorContext(_), _) => false,
169 (InterfaceType::FixedLengthList(t1), InterfaceType::FixedLengthList(t2)) => {
170 self.fixed_length_lists_equal(t1, t2)
171 }
172 (InterfaceType::FixedLengthList(_), _) => false,
173 }
174 }
175
176 fn lists_equal(&self, l1: TypeListIndex, l2: TypeListIndex) -> bool {
177 let a = &self.a_types[l1];
178 let b = &self.b_types[l2];
179 self.interface_types_equal(a.element, b.element)
180 }
181
182 fn maps_equal(&self, m1: TypeMapIndex, m2: TypeMapIndex) -> bool {
183 let a = &self.a_types[m1];
184 let b = &self.b_types[m2];
185 self.interface_types_equal(a.key, b.key) && self.interface_types_equal(a.value, b.value)
186 }
187
188 fn fixed_length_lists_equal(
189 &self,
190 l1: wasmtime_environ::component::TypeFixedLengthListIndex,
191 l2: wasmtime_environ::component::TypeFixedLengthListIndex,
192 ) -> bool {
193 let a = &self.a_types[l1];
194 let b = &self.b_types[l2];
195 if a.size != b.size {
196 return false;
197 }
198 self.interface_types_equal(a.element, b.element)
199 }
200
201 fn resources_equal(&self, o1: TypeResourceTableIndex, o2: TypeResourceTableIndex) -> bool {
202 match (&self.a_types[o1], &self.b_types[o2]) {
203 (
207 TypeResourceTable::Concrete { ty: a, .. },
208 TypeResourceTable::Concrete { ty: b, .. },
209 ) => self.a_resource.unwrap()[*a] == self.b_resource.unwrap()[*b],
210 (TypeResourceTable::Concrete { .. }, _) => false,
211
212 (TypeResourceTable::Abstract(a), TypeResourceTable::Abstract(b)) => {
215 core::ptr::eq(self.a_types, self.b_types) && a == b
216 }
217 (TypeResourceTable::Abstract(_), _) => false,
218 }
219 }
220
221 fn records_equal(&self, r1: TypeRecordIndex, r2: TypeRecordIndex) -> bool {
222 let a = &self.a_types[r1];
223 let b = &self.b_types[r2];
224 if a.fields.len() != b.fields.len() {
225 return false;
226 }
227 a.fields
228 .iter()
229 .zip(b.fields.iter())
230 .all(|(a_field, b_field)| {
231 a_field.name == b_field.name && self.interface_types_equal(a_field.ty, b_field.ty)
232 })
233 }
234
235 fn variants_equal(&self, v1: TypeVariantIndex, v2: TypeVariantIndex) -> bool {
236 let a = &self.a_types[v1];
237 let b = &self.b_types[v2];
238 if a.cases.len() != b.cases.len() {
239 return false;
240 }
241 a.cases
242 .iter()
243 .zip(b.cases.iter())
244 .all(|((a_name, a_ty), (b_name, b_ty))| {
245 if a_name != b_name {
246 return false;
247 }
248 match (a_ty, b_ty) {
249 (Some(a_case_ty), Some(b_case_ty)) => {
250 self.interface_types_equal(*a_case_ty, *b_case_ty)
251 }
252 (None, None) => true,
253 _ => false,
254 }
255 })
256 }
257
258 fn results_equal(&self, r1: TypeResultIndex, r2: TypeResultIndex) -> bool {
259 let a = &self.a_types[r1];
260 let b = &self.b_types[r2];
261 let oks = match (a.ok, b.ok) {
262 (Some(ok1), Some(ok2)) => self.interface_types_equal(ok1, ok2),
263 (None, None) => true,
264 _ => false,
265 };
266 if !oks {
267 return false;
268 }
269 match (a.err, b.err) {
270 (Some(err1), Some(err2)) => self.interface_types_equal(err1, err2),
271 (None, None) => true,
272 _ => false,
273 }
274 }
275
276 fn options_equal(&self, o1: TypeOptionIndex, o2: TypeOptionIndex) -> bool {
277 let a = &self.a_types[o1];
278 let b = &self.b_types[o2];
279 self.interface_types_equal(a.ty, b.ty)
280 }
281
282 fn enums_equal(&self, e1: TypeEnumIndex, e2: TypeEnumIndex) -> bool {
283 let a = &self.a_types[e1];
284 let b = &self.b_types[e2];
285 a.names == b.names
286 }
287
288 fn tuples_equal(&self, t1: TypeTupleIndex, t2: TypeTupleIndex) -> bool {
289 let a = &self.a_types[t1];
290 let b = &self.b_types[t2];
291 if a.types.len() != b.types.len() {
292 return false;
293 }
294 a.types
295 .iter()
296 .zip(b.types.iter())
297 .all(|(&a, &b)| self.interface_types_equal(a, b))
298 }
299
300 fn flags_equal(&self, f1: TypeFlagsIndex, f2: TypeFlagsIndex) -> bool {
301 let a = &self.a_types[f1];
302 let b = &self.b_types[f2];
303 a.names == b.names
304 }
305
306 fn future_table_types_equal(&self, t1: TypeFutureTableIndex, t2: TypeFutureTableIndex) -> bool {
307 self.futures_equal(self.a_types[t1].ty, self.b_types[t2].ty)
308 }
309
310 fn futures_equal(&self, t1: TypeFutureIndex, t2: TypeFutureIndex) -> bool {
311 let a = &self.a_types[t1];
312 let b = &self.b_types[t2];
313 match (a.payload, b.payload) {
314 (Some(t1), Some(t2)) => self.interface_types_equal(t1, t2),
315 (None, None) => true,
316 _ => false,
317 }
318 }
319
320 fn stream_table_types_equal(&self, t1: TypeStreamTableIndex, t2: TypeStreamTableIndex) -> bool {
321 self.streams_equal(self.a_types[t1].ty, self.b_types[t2].ty)
322 }
323
324 fn streams_equal(&self, t1: TypeStreamIndex, t2: TypeStreamIndex) -> bool {
325 let a = &self.a_types[t1];
326 let b = &self.b_types[t2];
327 match (a.payload, b.payload) {
328 (Some(t1), Some(t2)) => self.interface_types_equal(t1, t2),
329 (None, None) => true,
330 _ => false,
331 }
332 }
333}
334
335#[derive(Clone, Debug)]
337pub struct List(Handle<TypeListIndex>);
338
339impl PartialEq for List {
340 fn eq(&self, other: &Self) -> bool {
341 self.0.equivalent(&other.0, TypeChecker::lists_equal)
342 }
343}
344
345impl Eq for List {}
346
347impl List {
348 pub(crate) fn from(index: TypeListIndex, ty: &InstanceType<'_>) -> Self {
349 List(Handle::new(index, ty))
350 }
351
352 pub fn ty(&self) -> Type {
354 Type::from(&self.0.types[self.0.index].element, &self.0.instance())
355 }
356}
357
358#[derive(Clone, Debug)]
360pub struct Map(Handle<TypeMapIndex>);
361
362impl PartialEq for Map {
363 fn eq(&self, other: &Self) -> bool {
364 self.0.equivalent(&other.0, TypeChecker::maps_equal)
365 }
366}
367
368impl Eq for Map {}
369
370impl Map {
371 pub(crate) fn from(index: TypeMapIndex, ty: &InstanceType<'_>) -> Self {
372 Map(Handle::new(index, ty))
373 }
374
375 pub fn key(&self) -> Type {
377 Type::from(&self.0.types[self.0.index].key, &self.0.instance())
378 }
379
380 pub fn value(&self) -> Type {
382 Type::from(&self.0.types[self.0.index].value, &self.0.instance())
383 }
384}
385#[derive(Clone, Debug)]
387pub struct FixedLengthList(Handle<TypeFixedLengthListIndex>);
388
389impl PartialEq for FixedLengthList {
390 fn eq(&self, other: &Self) -> bool {
391 self.0
392 .equivalent(&other.0, TypeChecker::fixed_length_lists_equal)
393 }
394}
395
396impl Eq for FixedLengthList {}
397
398impl FixedLengthList {
399 pub(crate) fn from(index: TypeFixedLengthListIndex, ty: &InstanceType<'_>) -> Self {
400 FixedLengthList(Handle::new(index, ty))
401 }
402
403 pub fn ty(&self) -> Type {
405 Type::from(&self.0.types[self.0.index].element, &self.0.instance())
406 }
407
408 pub fn len(&self) -> u32 {
410 self.0.types[self.0.index].size
411 }
412}
413
414#[derive(Debug)]
416pub struct Field<'a> {
417 pub name: &'a str,
419 pub ty: Type,
421}
422
423#[derive(Clone, Debug)]
425pub struct Record(Handle<TypeRecordIndex>);
426
427impl Record {
428 pub(crate) fn from(index: TypeRecordIndex, ty: &InstanceType<'_>) -> Self {
429 Record(Handle::new(index, ty))
430 }
431
432 pub fn fields(&self) -> impl ExactSizeIterator<Item = Field<'_>> {
434 self.0.types[self.0.index].fields.iter().map(|field| Field {
435 name: &field.name,
436 ty: Type::from(&field.ty, &self.0.instance()),
437 })
438 }
439}
440
441impl PartialEq for Record {
442 fn eq(&self, other: &Self) -> bool {
443 self.0.equivalent(&other.0, TypeChecker::records_equal)
444 }
445}
446
447impl Eq for Record {}
448
449#[derive(Clone, Debug)]
451pub struct Tuple(Handle<TypeTupleIndex>);
452
453impl Tuple {
454 pub(crate) fn from(index: TypeTupleIndex, ty: &InstanceType<'_>) -> Self {
455 Tuple(Handle::new(index, ty))
456 }
457
458 pub fn types(&self) -> impl ExactSizeIterator<Item = Type> + '_ {
460 self.0.types[self.0.index]
461 .types
462 .iter()
463 .map(|ty| Type::from(ty, &self.0.instance()))
464 }
465}
466
467impl PartialEq for Tuple {
468 fn eq(&self, other: &Self) -> bool {
469 self.0.equivalent(&other.0, TypeChecker::tuples_equal)
470 }
471}
472
473impl Eq for Tuple {}
474
475pub struct Case<'a> {
477 pub name: &'a str,
479 pub ty: Option<Type>,
481}
482
483#[derive(Clone, Debug)]
485pub struct Variant(Handle<TypeVariantIndex>);
486
487impl Variant {
488 pub(crate) fn from(index: TypeVariantIndex, ty: &InstanceType<'_>) -> Self {
489 Variant(Handle::new(index, ty))
490 }
491
492 pub fn cases(&self) -> impl ExactSizeIterator<Item = Case<'_>> {
494 self.0.types[self.0.index]
495 .cases
496 .iter()
497 .map(|(name, ty)| Case {
498 name,
499 ty: ty.as_ref().map(|ty| Type::from(ty, &self.0.instance())),
500 })
501 }
502}
503
504impl PartialEq for Variant {
505 fn eq(&self, other: &Self) -> bool {
506 self.0.equivalent(&other.0, TypeChecker::variants_equal)
507 }
508}
509
510impl Eq for Variant {}
511
512#[derive(Clone, Debug)]
514pub struct Enum(Handle<TypeEnumIndex>);
515
516impl Enum {
517 pub(crate) fn from(index: TypeEnumIndex, ty: &InstanceType<'_>) -> Self {
518 Enum(Handle::new(index, ty))
519 }
520
521 pub fn names(&self) -> impl ExactSizeIterator<Item = &str> {
523 self.0.types[self.0.index]
524 .names
525 .iter()
526 .map(|name| name.deref())
527 }
528}
529
530impl PartialEq for Enum {
531 fn eq(&self, other: &Self) -> bool {
532 self.0.equivalent(&other.0, TypeChecker::enums_equal)
533 }
534}
535
536impl Eq for Enum {}
537
538#[derive(Clone, Debug)]
540pub struct OptionType(Handle<TypeOptionIndex>);
541
542impl OptionType {
543 pub(crate) fn from(index: TypeOptionIndex, ty: &InstanceType<'_>) -> Self {
544 OptionType(Handle::new(index, ty))
545 }
546
547 pub fn ty(&self) -> Type {
549 Type::from(&self.0.types[self.0.index].ty, &self.0.instance())
550 }
551}
552
553impl PartialEq for OptionType {
554 fn eq(&self, other: &Self) -> bool {
555 self.0.equivalent(&other.0, TypeChecker::options_equal)
556 }
557}
558
559impl Eq for OptionType {}
560
561#[derive(Clone, Debug)]
563pub struct ResultType(Handle<TypeResultIndex>);
564
565impl ResultType {
566 pub(crate) fn from(index: TypeResultIndex, ty: &InstanceType<'_>) -> Self {
567 ResultType(Handle::new(index, ty))
568 }
569
570 pub fn ok(&self) -> Option<Type> {
572 Some(Type::from(
573 self.0.types[self.0.index].ok.as_ref()?,
574 &self.0.instance(),
575 ))
576 }
577
578 pub fn err(&self) -> Option<Type> {
580 Some(Type::from(
581 self.0.types[self.0.index].err.as_ref()?,
582 &self.0.instance(),
583 ))
584 }
585}
586
587impl PartialEq for ResultType {
588 fn eq(&self, other: &Self) -> bool {
589 self.0.equivalent(&other.0, TypeChecker::results_equal)
590 }
591}
592
593impl Eq for ResultType {}
594
595#[derive(Clone, Debug)]
597pub struct Flags(Handle<TypeFlagsIndex>);
598
599impl Flags {
600 pub(crate) fn from(index: TypeFlagsIndex, ty: &InstanceType<'_>) -> Self {
601 Flags(Handle::new(index, ty))
602 }
603
604 pub fn names(&self) -> impl ExactSizeIterator<Item = &str> {
606 self.0.types[self.0.index]
607 .names
608 .iter()
609 .map(|name| name.deref())
610 }
611}
612
613impl PartialEq for Flags {
614 fn eq(&self, other: &Self) -> bool {
615 self.0.equivalent(&other.0, TypeChecker::flags_equal)
616 }
617}
618
619impl Eq for Flags {}
620
621#[cfg(feature = "component-model-async")]
622pub(crate) fn typecheck_payload<T>(
623 payload: Option<&InterfaceType>,
624 types: &InstanceType<'_>,
625) -> crate::Result<()>
626where
627 T: ComponentType,
628{
629 match payload {
630 Some(a) => T::typecheck(a, types),
631 None => {
632 if T::IS_RUST_UNIT_TYPE {
633 Ok(())
634 } else {
635 crate::bail!("future payload types differ")
636 }
637 }
638 }
639}
640
641#[derive(Clone, Debug)]
643pub struct FutureType(Handle<TypeFutureIndex>);
644
645impl FutureType {
646 pub(crate) fn from(index: TypeFutureIndex, ty: &InstanceType<'_>) -> Self {
647 FutureType(Handle::new(index, ty))
648 }
649
650 pub fn ty(&self) -> Option<Type> {
652 Some(Type::from(
653 self.0.types[self.0.index].payload.as_ref()?,
654 &self.0.instance(),
655 ))
656 }
657
658 #[cfg(feature = "component-model-async")]
659 pub(crate) fn equivalent_payload_guest(
660 &self,
661 ty: &InstanceType<'_>,
662 payload: Option<&InterfaceType>,
663 ) -> bool {
664 let my_payload = self.0.types[self.0.index].payload.as_ref();
665 match (my_payload, payload) {
666 (Some(a), Some(b)) => TypeChecker {
667 a_types: &self.0.types,
668 a_resource: self.0.resources.as_deref(),
669 b_types: ty.types,
670 b_resource: ty.resources.map(|p| &**p),
671 }
672 .interface_types_equal(*a, *b),
673 (None, None) => true,
674 (Some(_), None) | (None, Some(_)) => false,
675 }
676 }
677
678 #[cfg(feature = "component-model-async")]
679 pub(crate) fn equivalent_payload_host<T>(&self) -> crate::Result<()>
680 where
681 T: ComponentType,
682 {
683 typecheck_payload::<T>(
684 self.0.types[self.0.index].payload.as_ref(),
685 &self.0.instance(),
686 )
687 }
688}
689
690impl PartialEq for FutureType {
691 fn eq(&self, other: &Self) -> bool {
692 self.0.equivalent(&other.0, TypeChecker::futures_equal)
693 }
694}
695
696impl Eq for FutureType {}
697
698#[derive(Clone, Debug)]
700pub struct StreamType(Handle<TypeStreamIndex>);
701
702impl StreamType {
703 pub(crate) fn from(index: TypeStreamIndex, ty: &InstanceType<'_>) -> Self {
704 StreamType(Handle::new(index, ty))
705 }
706
707 pub fn ty(&self) -> Option<Type> {
709 Some(Type::from(
710 self.0.types[self.0.index].payload.as_ref()?,
711 &self.0.instance(),
712 ))
713 }
714
715 #[cfg(feature = "component-model-async")]
716 pub(crate) fn equivalent_payload_guest(
717 &self,
718 ty: &InstanceType<'_>,
719 payload: Option<&InterfaceType>,
720 ) -> bool {
721 let my_payload = self.0.types[self.0.index].payload.as_ref();
722 match (my_payload, payload) {
723 (Some(a), Some(b)) => TypeChecker {
724 a_types: &self.0.types,
725 a_resource: self.0.resources.as_deref(),
726 b_types: ty.types,
727 b_resource: ty.resources.map(|p| &**p),
728 }
729 .interface_types_equal(*a, *b),
730 (None, None) => true,
731 (Some(_), None) | (None, Some(_)) => false,
732 }
733 }
734
735 #[cfg(feature = "component-model-async")]
736 pub(crate) fn equivalent_payload_host<T>(&self) -> crate::Result<()>
737 where
738 T: ComponentType,
739 {
740 typecheck_payload::<T>(
741 self.0.types[self.0.index].payload.as_ref(),
742 &self.0.instance(),
743 )
744 }
745}
746
747impl PartialEq for StreamType {
748 fn eq(&self, other: &Self) -> bool {
749 self.0.equivalent(&other.0, TypeChecker::streams_equal)
750 }
751}
752
753impl Eq for StreamType {}
754
755#[derive(Clone, PartialEq, Eq, Debug)]
757#[expect(missing_docs, reason = "self-describing variants")]
758pub enum Type {
759 Bool,
760 S8,
761 U8,
762 S16,
763 U16,
764 S32,
765 U32,
766 S64,
767 U64,
768 Float32,
769 Float64,
770 Char,
771 String,
772 List(List),
773 Map(Map),
774 Record(Record),
775 Tuple(Tuple),
776 Variant(Variant),
777 Enum(Enum),
778 Option(OptionType),
779 Result(ResultType),
780 Flags(Flags),
781 Own(ResourceType),
782 Borrow(ResourceType),
783 Future(FutureType),
784 Stream(StreamType),
785 ErrorContext,
786 FixedLengthList(FixedLengthList),
787}
788
789impl Type {
790 pub fn unwrap_list(&self) -> &List {
796 if let Type::List(handle) = self {
797 &handle
798 } else {
799 panic!("attempted to unwrap a {} as a list", self.desc())
800 }
801 }
802
803 pub fn unwrap_record(&self) -> &Record {
809 if let Type::Record(handle) = self {
810 &handle
811 } else {
812 panic!("attempted to unwrap a {} as a record", self.desc())
813 }
814 }
815
816 pub fn unwrap_tuple(&self) -> &Tuple {
822 if let Type::Tuple(handle) = self {
823 &handle
824 } else {
825 panic!("attempted to unwrap a {} as a tuple", self.desc())
826 }
827 }
828
829 pub fn unwrap_variant(&self) -> &Variant {
835 if let Type::Variant(handle) = self {
836 &handle
837 } else {
838 panic!("attempted to unwrap a {} as a variant", self.desc())
839 }
840 }
841
842 pub fn unwrap_enum(&self) -> &Enum {
848 if let Type::Enum(handle) = self {
849 &handle
850 } else {
851 panic!("attempted to unwrap a {} as a enum", self.desc())
852 }
853 }
854
855 pub fn unwrap_option(&self) -> &OptionType {
861 if let Type::Option(handle) = self {
862 &handle
863 } else {
864 panic!("attempted to unwrap a {} as a option", self.desc())
865 }
866 }
867
868 pub fn unwrap_result(&self) -> &ResultType {
874 if let Type::Result(handle) = self {
875 &handle
876 } else {
877 panic!("attempted to unwrap a {} as a result", self.desc())
878 }
879 }
880
881 pub fn unwrap_flags(&self) -> &Flags {
887 if let Type::Flags(handle) = self {
888 &handle
889 } else {
890 panic!("attempted to unwrap a {} as a flags", self.desc())
891 }
892 }
893
894 pub fn unwrap_own(&self) -> &ResourceType {
900 match self {
901 Type::Own(ty) => ty,
902 _ => panic!("attempted to unwrap a {} as a own", self.desc()),
903 }
904 }
905
906 pub fn unwrap_borrow(&self) -> &ResourceType {
912 match self {
913 Type::Borrow(ty) => ty,
914 _ => panic!("attempted to unwrap a {} as a own", self.desc()),
915 }
916 }
917
918 pub(crate) fn from(ty: &InterfaceType, instance: &InstanceType<'_>) -> Self {
920 match ty {
921 InterfaceType::Bool => Type::Bool,
922 InterfaceType::S8 => Type::S8,
923 InterfaceType::U8 => Type::U8,
924 InterfaceType::S16 => Type::S16,
925 InterfaceType::U16 => Type::U16,
926 InterfaceType::S32 => Type::S32,
927 InterfaceType::U32 => Type::U32,
928 InterfaceType::S64 => Type::S64,
929 InterfaceType::U64 => Type::U64,
930 InterfaceType::Float32 => Type::Float32,
931 InterfaceType::Float64 => Type::Float64,
932 InterfaceType::Char => Type::Char,
933 InterfaceType::String => Type::String,
934 InterfaceType::List(index) => Type::List(List::from(*index, instance)),
935 InterfaceType::Map(index) => Type::Map(Map::from(*index, instance)),
936 InterfaceType::Record(index) => Type::Record(Record::from(*index, instance)),
937 InterfaceType::Tuple(index) => Type::Tuple(Tuple::from(*index, instance)),
938 InterfaceType::Variant(index) => Type::Variant(Variant::from(*index, instance)),
939 InterfaceType::Enum(index) => Type::Enum(Enum::from(*index, instance)),
940 InterfaceType::Option(index) => Type::Option(OptionType::from(*index, instance)),
941 InterfaceType::Result(index) => Type::Result(ResultType::from(*index, instance)),
942 InterfaceType::Flags(index) => Type::Flags(Flags::from(*index, instance)),
943 InterfaceType::Own(index) => Type::Own(instance.resource_type(*index)),
944 InterfaceType::Borrow(index) => Type::Borrow(instance.resource_type(*index)),
945 InterfaceType::Future(index) => Type::Future(instance.future_type(*index)),
946 InterfaceType::Stream(index) => Type::Stream(instance.stream_type(*index)),
947 InterfaceType::ErrorContext(_) => Type::ErrorContext,
948 InterfaceType::FixedLengthList(index) => {
949 Type::FixedLengthList(FixedLengthList::from(*index, instance))
950 }
951 }
952 }
953
954 fn desc(&self) -> &'static str {
955 match self {
956 Type::Bool => "bool",
957 Type::S8 => "s8",
958 Type::U8 => "u8",
959 Type::S16 => "s16",
960 Type::U16 => "u16",
961 Type::S32 => "s32",
962 Type::U32 => "u32",
963 Type::S64 => "s64",
964 Type::U64 => "u64",
965 Type::Float32 => "float32",
966 Type::Float64 => "float64",
967 Type::Char => "char",
968 Type::String => "string",
969 Type::List(_) => "list",
970 Type::Map(_) => "map",
971 Type::Record(_) => "record",
972 Type::Tuple(_) => "tuple",
973 Type::Variant(_) => "variant",
974 Type::Enum(_) => "enum",
975 Type::Option(_) => "option",
976 Type::Result(_) => "result",
977 Type::Flags(_) => "flags",
978 Type::Own(_) => "own",
979 Type::Borrow(_) => "borrow",
980 Type::Future(_) => "future",
981 Type::Stream(_) => "stream",
982 Type::ErrorContext => "error-context",
983 Type::FixedLengthList(_) => "list<_, N>",
984 }
985 }
986}
987
988#[derive(Clone, Debug)]
990pub struct ComponentFunc(Handle<TypeFuncIndex>);
991
992impl ComponentFunc {
993 pub(crate) fn from(index: TypeFuncIndex, ty: &InstanceType<'_>) -> Self {
994 Self(Handle::new(index, ty))
995 }
996
997 pub fn async_(&self) -> bool {
999 self.0.types[self.0.index].async_
1000 }
1001
1002 pub fn params(&self) -> impl ExactSizeIterator<Item = (&str, Type)> + '_ {
1004 let ty = &self.0.types[self.0.index];
1005 self.0.types[ty.params]
1006 .types
1007 .iter()
1008 .zip(&ty.param_names)
1009 .map(|(ty, name)| (name.as_str(), Type::from(ty, &self.0.instance())))
1010 }
1011
1012 pub fn results(&self) -> impl ExactSizeIterator<Item = Type> + '_ {
1014 let results = self.0.types[self.0.index].results;
1015 self.0.types[results]
1016 .types
1017 .iter()
1018 .map(|ty| Type::from(ty, &self.0.instance()))
1019 }
1020
1021 #[doc(hidden)]
1022 pub fn typecheck<Params, Return>(&self, cx: &InstanceType) -> crate::Result<()>
1023 where
1024 Params: crate::component::ComponentNamedList + crate::component::Lower,
1025 Return: crate::component::ComponentNamedList + crate::component::Lift,
1026 {
1027 let ty = &self.0.types[self.0.index];
1028 Params::typecheck(&InterfaceType::Tuple(ty.params), cx)?;
1029 Return::typecheck(&InterfaceType::Tuple(ty.results), cx)?;
1030 Ok(())
1031 }
1032}
1033
1034#[derive(Clone, Debug)]
1036pub struct Module(Handle<TypeModuleIndex>);
1037
1038impl Module {
1039 pub(crate) fn from(index: TypeModuleIndex, ty: &InstanceType<'_>) -> Self {
1040 Self(Handle::new(index, ty))
1041 }
1042
1043 pub fn imports<'a>(
1045 &'a self,
1046 engine: &'a Engine,
1047 ) -> impl ExactSizeIterator<Item = ((&'a str, &'a str), ExternType)> + 'a {
1048 self.0.types[self.0.index]
1049 .imports
1050 .iter()
1051 .map(|((namespace, name), ty)| {
1052 (
1053 (namespace.as_str(), name.as_str()),
1054 ExternType::from_wasmtime(engine, self.0.types.module_types(), ty),
1055 )
1056 })
1057 }
1058
1059 pub fn exports<'a>(
1061 &'a self,
1062 engine: &'a Engine,
1063 ) -> impl ExactSizeIterator<Item = (&'a str, ExternType)> + 'a {
1064 self.0.types[self.0.index].exports.iter().map(|(name, ty)| {
1065 (
1066 name.as_str(),
1067 ExternType::from_wasmtime(engine, self.0.types.module_types(), ty),
1068 )
1069 })
1070 }
1071}
1072
1073#[derive(Clone, Debug)]
1075pub struct Component(Handle<TypeComponentIndex>);
1076
1077impl Component {
1078 pub(crate) fn from(index: TypeComponentIndex, ty: &InstanceType<'_>) -> Self {
1079 Self(Handle::new(index, ty))
1080 }
1081
1082 pub fn get_import<'a>(&'a self, engine: &'a Engine, name: &str) -> Option<ComponentExtern<'a>> {
1084 self.0.types[self.0.index]
1085 .imports
1086 .get(name)
1087 .map(|e| ComponentExtern::new(engine, &self.0.instance(), e))
1088 }
1089
1090 pub fn imports<'a>(
1092 &'a self,
1093 engine: &'a Engine,
1094 ) -> impl ExactSizeIterator<Item = (&'a str, ComponentExtern<'a>)> + 'a {
1095 self.0.types[self.0.index].imports.iter().map(|(name, e)| {
1096 (
1097 name.as_str(),
1098 ComponentExtern::new(engine, &self.0.instance(), e),
1099 )
1100 })
1101 }
1102
1103 pub fn get_export<'a>(&'a self, engine: &'a Engine, name: &str) -> Option<ComponentExtern<'a>> {
1105 self.0.types[self.0.index]
1106 .exports
1107 .get(name)
1108 .map(|e| ComponentExtern::new(engine, &self.0.instance(), e))
1109 }
1110
1111 pub fn exports<'a>(
1113 &'a self,
1114 engine: &'a Engine,
1115 ) -> impl ExactSizeIterator<Item = (&'a str, ComponentExtern<'a>)> + 'a {
1116 self.0.types[self.0.index].exports.iter().map(|(name, e)| {
1117 (
1118 name.as_str(),
1119 ComponentExtern::new(engine, &self.0.instance(), e),
1120 )
1121 })
1122 }
1123
1124 #[doc(hidden)]
1125 pub fn instance_type(&self) -> InstanceType<'_> {
1126 InstanceType {
1127 types: &self.0.types,
1128 resources: self.0.resources.as_ref(),
1129 }
1130 }
1131}
1132
1133#[derive(Clone, Debug)]
1135pub struct ComponentInstance(Handle<TypeComponentInstanceIndex>);
1136
1137impl ComponentInstance {
1138 pub(crate) fn from(index: TypeComponentInstanceIndex, ty: &InstanceType<'_>) -> Self {
1139 Self(Handle::new(index, ty))
1140 }
1141
1142 pub fn get_export<'a>(&'a self, engine: &'a Engine, name: &str) -> Option<ComponentExtern<'a>> {
1144 self.0.types[self.0.index]
1145 .exports
1146 .get(name)
1147 .map(|e| ComponentExtern::new(engine, &self.0.instance(), e))
1148 }
1149
1150 pub fn exports<'a>(
1152 &'a self,
1153 engine: &'a Engine,
1154 ) -> impl ExactSizeIterator<Item = (&'a str, ComponentExtern<'a>)> {
1155 self.0.types[self.0.index].exports.iter().map(|(name, e)| {
1156 (
1157 name.as_str(),
1158 ComponentExtern::new(engine, &self.0.instance(), e),
1159 )
1160 })
1161 }
1162}
1163
1164#[derive(Clone, Debug)]
1169pub struct ComponentExtern<'a> {
1170 pub ty: ComponentItem,
1172 pub implements: Option<&'a str>,
1174}
1175
1176impl<'a> ComponentExtern<'a> {
1177 fn new(
1178 engine: &'a Engine,
1179 instance_ty: &InstanceType<'_>,
1180 env: &'a wasmtime_environ::component::ComponentExtern,
1181 ) -> Self {
1182 Self {
1183 implements: env.data.implements.as_deref(),
1184 ty: ComponentItem::from(engine, &env.ty, instance_ty),
1185 }
1186 }
1187
1188 pub fn is_implements(&self, name: &str) -> bool {
1198 let implements = match self.implements {
1199 Some(s) => s,
1200 None => return false,
1201 };
1202 if name == implements {
1203 return true;
1204 }
1205
1206 match (alternate_lookup_key(implements), alternate_lookup_key(name)) {
1207 (Some((alt_implements, _)), Some((alt_name, _))) => alt_implements == alt_name,
1208 _ => false,
1209 }
1210 }
1211}
1212
1213#[derive(Clone, Debug)]
1215pub enum ComponentItem {
1216 ComponentFunc(ComponentFunc),
1218 CoreFunc(FuncType),
1220 Module(Module),
1222 Component(Component),
1224 ComponentInstance(ComponentInstance),
1226 Type(Type),
1228 Resource(ResourceType),
1230}
1231
1232impl ComponentItem {
1233 pub(crate) fn from(engine: &Engine, def: &TypeDef, ty: &InstanceType<'_>) -> Self {
1234 match def {
1235 TypeDef::Component(idx) => Self::Component(Component::from(*idx, ty)),
1236 TypeDef::ComponentInstance(idx) => {
1237 Self::ComponentInstance(ComponentInstance::from(*idx, ty))
1238 }
1239 TypeDef::ComponentFunc(idx) => Self::ComponentFunc(ComponentFunc::from(*idx, ty)),
1240 TypeDef::Interface(iface_ty) => Self::Type(Type::from(iface_ty, ty)),
1241 TypeDef::Module(idx) => Self::Module(Module::from(*idx, ty)),
1242 TypeDef::CoreFunc(idx) => {
1243 let subty = &ty.types[*idx];
1244 Self::CoreFunc(
1245 FuncType::from_wasm_func_type(
1246 engine,
1247 subty.is_final,
1248 subty.supertype,
1249 subty.unwrap_func().try_clone().panic_on_oom(),
1250 )
1251 .panic_on_oom(),
1252 )
1253 }
1254 TypeDef::Resource(idx) => match ty.types[*idx] {
1255 TypeResourceTable::Concrete {
1256 ty: resource_index, ..
1257 } => {
1258 let ty = match ty.resources.and_then(|t| t.get(resource_index)) {
1259 Some(ty) => *ty,
1262
1263 None => ResourceType::uninstantiated(&ty.types, resource_index),
1265 };
1266 Self::Resource(ty)
1267 }
1268 TypeResourceTable::Abstract(resource_index) => {
1269 Self::Resource(ResourceType::abstract_(&ty.types, resource_index))
1270 }
1271 },
1272 }
1273 }
1274 pub(crate) fn from_export(engine: &Engine, export: &Export, ty: &InstanceType<'_>) -> Self {
1275 match export {
1276 Export::Instance { ty: idx, .. } => {
1277 Self::ComponentInstance(ComponentInstance::from(*idx, ty))
1278 }
1279 Export::LiftedFunction { ty: idx, .. } => {
1280 Self::ComponentFunc(ComponentFunc::from(*idx, ty))
1281 }
1282 Export::ModuleStatic { ty: idx, .. } | Export::ModuleImport { ty: idx, .. } => {
1283 Self::Module(Module::from(*idx, ty))
1284 }
1285 Export::Type(idx) => Self::from(engine, idx, ty),
1286 }
1287 }
1288}