1use super::{
4 check_max,
5 component_types::{
6 Abi, AliasableResourceId, ComponentAnyTypeId, ComponentCoreInstanceTypeId,
7 ComponentCoreModuleTypeId, ComponentCoreTypeId, ComponentDefinedType,
8 ComponentDefinedTypeId, ComponentEntityType, ComponentFuncType, ComponentFuncTypeId,
9 ComponentInstanceType, ComponentInstanceTypeId, ComponentType, ComponentTypeId,
10 ComponentValType, Context, CoreInstanceTypeKind, InstanceType, ModuleType, RecordType,
11 Remap, Remapping, ResourceId, SubtypeCx, TupleType, VariantCase, VariantType,
12 },
13 core::{InternRecGroup, Module},
14 types::{CoreTypeId, EntityType, TypeAlloc, TypeInfo, TypeList},
15};
16use crate::collections::index_map::Entry;
17use crate::limits::*;
18use crate::prelude::*;
19use crate::validator::names::{ComponentName, ComponentNameKind, KebabStr, KebabString};
20use crate::{
21 BinaryReaderError, CanonicalFunction, CanonicalOption, ComponentExportName,
22 ComponentExternalKind, ComponentOuterAliasKind, ComponentTypeRef, CompositeInnerType,
23 ExternalKind, FuncType, GlobalType, InstantiationArgKind, MemoryType, PackedIndex, RefType,
24 Result, SubType, TableType, TypeBounds, ValType, WasmFeatures,
25};
26use core::mem;
27
28fn to_kebab_str<'a>(s: &'a str, desc: &str, offset: usize) -> Result<&'a KebabStr> {
29 match KebabStr::new(s) {
30 Some(s) => Ok(s),
31 None => {
32 if s.is_empty() {
33 bail!(offset, "{desc} name cannot be empty");
34 }
35
36 bail!(offset, "{desc} name `{s}` is not in kebab case");
37 }
38 }
39}
40
41pub(crate) struct ComponentState {
42 kind: ComponentKind,
45 features: WasmFeatures,
46
47 pub core_types: Vec<ComponentCoreTypeId>,
49 pub core_funcs: Vec<CoreTypeId>,
50 pub core_tags: Vec<CoreTypeId>,
51 pub core_modules: Vec<ComponentCoreModuleTypeId>,
52 pub core_instances: Vec<ComponentCoreInstanceTypeId>,
53 pub core_memories: Vec<MemoryType>,
54 pub core_tables: Vec<TableType>,
55 pub core_globals: Vec<GlobalType>,
56
57 pub types: Vec<ComponentAnyTypeId>,
59 pub funcs: Vec<ComponentFuncTypeId>,
60 pub values: Vec<(ComponentValType, bool)>,
61 pub instances: Vec<ComponentInstanceTypeId>,
62 pub components: Vec<ComponentTypeId>,
63
64 pub imports: IndexMap<String, ComponentEntityType>,
65 pub import_names: IndexSet<ComponentName>,
66 pub exports: IndexMap<String, ComponentEntityType>,
67 pub export_names: IndexSet<ComponentName>,
68
69 has_start: bool,
70 type_info: TypeInfo,
71
72 imported_resources: IndexMapAppendOnly<ResourceId, Vec<usize>>,
116
117 defined_resources: IndexMapAppendOnly<ResourceId, Option<ValType>>,
137
138 explicit_resources: IndexMap<ResourceId, Vec<usize>>,
145
146 exported_types: Set<ComponentAnyTypeId>,
155
156 imported_types: Set<ComponentAnyTypeId>,
158
159 toplevel_exported_resources: ComponentNameContext,
169
170 toplevel_imported_resources: ComponentNameContext,
172}
173
174#[derive(Copy, Clone, Debug, PartialEq, Eq)]
175pub enum ComponentKind {
176 Component,
177 InstanceType,
178 ComponentType,
179}
180
181#[derive(Default)]
184struct ComponentNameContext {
185 resource_name_map: Map<AliasableResourceId, usize>,
188
189 all_resource_names: IndexSet<String>,
193}
194
195#[derive(Debug, Copy, Clone)]
196pub enum ExternKind {
197 Import,
198 Export,
199}
200
201impl ExternKind {
202 pub fn desc(&self) -> &'static str {
203 match self {
204 ExternKind::Import => "import",
205 ExternKind::Export => "export",
206 }
207 }
208}
209
210#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
211pub(crate) enum StringEncoding {
212 #[default]
213 Utf8,
214 Utf16,
215 CompactUtf16,
216}
217
218impl core::fmt::Display for StringEncoding {
219 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
220 f.write_str(match self {
221 Self::Utf8 => "utf8",
222 Self::Utf16 => "utf16",
223 Self::CompactUtf16 => "latin1-utf16",
224 })
225 }
226}
227
228#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
229pub(crate) enum Concurrency {
230 #[default]
232 Sync,
233
234 Async {
236 callback: Option<u32>,
241 },
242}
243
244impl Concurrency {
245 pub(crate) fn is_sync(&self) -> bool {
246 matches!(self, Self::Sync)
247 }
248
249 pub(crate) fn is_async(&self) -> bool {
250 !self.is_sync()
251 }
252}
253
254#[derive(Clone, Copy)]
255pub(crate) struct CanonicalOptions {
256 pub(crate) string_encoding: StringEncoding,
257 pub(crate) memory: Option<u32>,
258 pub(crate) realloc: Option<u32>,
259 pub(crate) post_return: Option<u32>,
260 pub(crate) concurrency: Concurrency,
261 pub(crate) core_type: Option<CoreTypeId>,
262 pub(crate) gc: bool,
263}
264
265impl CanonicalOptions {
266 pub(crate) fn require_sync(&self, offset: usize, where_: &str) -> Result<&Self> {
267 if !self.concurrency.is_sync() {
268 bail!(offset, "cannot specify `async` option on `{where_}`")
269 }
270 Ok(self)
271 }
272
273 pub(crate) fn require_memory(&self, offset: usize) -> Result<&Self> {
274 if self.memory.is_none() {
275 bail!(offset, "canonical option `memory` is required");
276 }
277 Ok(self)
278 }
279
280 pub(crate) fn require_realloc(&self, offset: usize) -> Result<&Self> {
281 self.require_memory(offset)?;
283
284 if self.realloc.is_none() {
285 bail!(offset, "canonical option `realloc` is required")
286 }
287
288 Ok(self)
289 }
290
291 pub(crate) fn require_memory_if(
292 &self,
293 offset: usize,
294 when: impl Fn() -> bool,
295 ) -> Result<&Self> {
296 if self.memory.is_none() && when() {
297 self.require_memory(offset)?;
298 }
299 Ok(self)
300 }
301
302 pub(crate) fn require_realloc_if(
303 &self,
304 offset: usize,
305 when: impl Fn() -> bool,
306 ) -> Result<&Self> {
307 if self.realloc.is_none() && when() {
308 self.require_realloc(offset)?;
309 }
310 Ok(self)
311 }
312
313 pub(crate) fn check_lower(&self, offset: usize) -> Result<&Self> {
314 if self.post_return.is_some() {
315 bail!(
316 offset,
317 "canonical option `post-return` cannot be specified for lowerings"
318 );
319 }
320
321 if let Concurrency::Async { callback: Some(_) } = self.concurrency {
322 bail!(
323 offset,
324 "canonical option `callback` cannot be specified for lowerings"
325 );
326 }
327
328 if self.gc && self.core_type.is_none() {
329 bail!(
330 offset,
331 "cannot specify `gc` without also specifying a `core-type` for lowerings"
332 )
333 }
334
335 Ok(self)
336 }
337
338 pub(crate) fn check_lift(
339 &mut self,
340 types: &TypeList,
341 state: &ComponentState,
342 core_ty_id: CoreTypeId,
343 offset: usize,
344 ) -> Result<&Self> {
345 debug_assert!(matches!(
346 types[core_ty_id].composite_type.inner,
347 CompositeInnerType::Func(_)
348 ));
349
350 if let Some(idx) = self.post_return {
351 let post_return_func_ty = types[state.core_function_at(idx, offset)?].unwrap_func();
352 let core_ty = types[core_ty_id].unwrap_func();
353 if post_return_func_ty.params() != core_ty.results()
354 || !post_return_func_ty.results().is_empty()
355 {
356 bail!(
357 offset,
358 "canonical option `post-return` uses a core function with an incorrect signature"
359 );
360 }
361 }
362
363 match self.concurrency {
364 Concurrency::Sync => {}
365
366 Concurrency::Async { callback: None } if !state.features.cm_async_stackful() => {
367 bail!(
368 offset,
369 "requires the component model async stackful feature"
370 )
371 }
372 Concurrency::Async { callback: None } => {}
373
374 Concurrency::Async {
375 callback: Some(idx),
376 } => {
377 let func_ty = types[state.core_function_at(idx, offset)?].unwrap_func();
378 if func_ty.params() != [ValType::I32; 3] && func_ty.params() != [ValType::I32] {
379 return Err(BinaryReaderError::new(
380 "canonical option `callback` uses a core function with an incorrect signature",
381 offset,
382 ));
383 }
384 }
385 }
386
387 if self.core_type.is_some() {
388 bail!(
389 offset,
390 "canonical option `core-type` is not allowed in `canon lift`"
391 )
392 }
393 self.core_type = Some(core_ty_id);
394
395 Ok(self)
396 }
397
398 pub(crate) fn check_core_type(
399 &self,
400 types: &mut TypeAlloc,
401 actual: FuncType,
402 offset: usize,
403 ) -> Result<CoreTypeId> {
404 if let Some(declared_id) = self.core_type {
405 let declared = types[declared_id].unwrap_func();
406
407 if actual.params() != declared.params() {
408 bail!(
409 offset,
410 "declared core type has `{:?}` parameter types, but actual lowering has \
411 `{:?}` parameter types",
412 declared.params(),
413 actual.params(),
414 );
415 }
416
417 if actual.results() != declared.results() {
418 bail!(
419 offset,
420 "declared core type has `{:?}` result types, but actual lowering has \
421 `{:?}` result types",
422 declared.results(),
423 actual.results(),
424 );
425 }
426
427 Ok(declared_id)
428 } else {
429 Ok(types.intern_func_type(actual, offset))
430 }
431 }
432}
433
434impl ComponentState {
435 pub fn new(kind: ComponentKind, features: WasmFeatures) -> Self {
436 Self {
437 kind,
438 features,
439 core_types: Default::default(),
440 core_modules: Default::default(),
441 core_instances: Default::default(),
442 core_funcs: Default::default(),
443 core_memories: Default::default(),
444 core_tables: Default::default(),
445 core_globals: Default::default(),
446 core_tags: Default::default(),
447 types: Default::default(),
448 funcs: Default::default(),
449 values: Default::default(),
450 instances: Default::default(),
451 components: Default::default(),
452 imports: Default::default(),
453 exports: Default::default(),
454 import_names: Default::default(),
455 export_names: Default::default(),
456 has_start: Default::default(),
457 type_info: TypeInfo::new(),
458 imported_resources: Default::default(),
459 defined_resources: Default::default(),
460 explicit_resources: Default::default(),
461 exported_types: Default::default(),
462 imported_types: Default::default(),
463 toplevel_exported_resources: Default::default(),
464 toplevel_imported_resources: Default::default(),
465 }
466 }
467
468 pub fn type_count(&self) -> usize {
469 self.core_types.len() + self.types.len()
470 }
471
472 pub fn instance_count(&self) -> usize {
473 self.core_instances.len() + self.instances.len()
474 }
475
476 pub fn function_count(&self) -> usize {
477 self.core_funcs.len() + self.funcs.len()
478 }
479
480 pub fn add_core_type(
481 components: &mut [Self],
482 ty: crate::CoreType,
483 types: &mut TypeAlloc,
484 offset: usize,
485 check_limit: bool,
486 ) -> Result<()> {
487 let current = components.last_mut().unwrap();
488 if check_limit {
489 check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
490 }
491 match ty {
492 crate::CoreType::Rec(rec) => {
493 current.canonicalize_and_intern_rec_group(types, rec, offset)?;
494 }
495 crate::CoreType::Module(decls) => {
496 let mod_ty = Self::create_module_type(components, decls.into_vec(), types, offset)?;
497 let id = ComponentCoreTypeId::Module(types.push_ty(mod_ty));
498 components.last_mut().unwrap().core_types.push(id);
499 }
500 }
501
502 Ok(())
503 }
504
505 pub fn add_core_module(
506 &mut self,
507 module: &Module,
508 types: &mut TypeAlloc,
509 offset: usize,
510 ) -> Result<()> {
511 let imports = module.imports_for_module_type(offset)?;
512
513 let mod_ty = ModuleType {
517 info: TypeInfo::core(module.type_size),
518 imports,
519 exports: module.exports.clone(),
520 };
521
522 let mod_id = types.push_ty(mod_ty);
523 self.core_modules.push(mod_id);
524
525 Ok(())
526 }
527
528 pub fn add_core_instance(
529 &mut self,
530 instance: crate::Instance,
531 types: &mut TypeAlloc,
532 offset: usize,
533 ) -> Result<()> {
534 let instance = match instance {
535 crate::Instance::Instantiate { module_index, args } => {
536 self.instantiate_core_module(module_index, args.into_vec(), types, offset)?
537 }
538 crate::Instance::FromExports(exports) => {
539 self.instantiate_core_exports(exports.into_vec(), types, offset)?
540 }
541 };
542
543 self.core_instances.push(instance);
544
545 Ok(())
546 }
547
548 pub fn add_type(
549 components: &mut Vec<Self>,
550 ty: crate::ComponentType,
551 types: &mut TypeAlloc,
552 offset: usize,
553 check_limit: bool,
554 ) -> Result<()> {
555 assert!(!components.is_empty());
556
557 fn current(components: &mut Vec<ComponentState>) -> &mut ComponentState {
558 components.last_mut().unwrap()
559 }
560
561 let id = match ty {
562 crate::ComponentType::Defined(ty) => {
563 let ty = current(components).create_defined_type(ty, types, offset)?;
564 types.push(ty).into()
565 }
566 crate::ComponentType::Func(ty) => {
567 let ty = current(components).create_function_type(ty, types, offset)?;
568 types.push(ty).into()
569 }
570 crate::ComponentType::Component(decls) => {
571 let ty = Self::create_component_type(components, decls.into_vec(), types, offset)?;
572 types.push(ty).into()
573 }
574 crate::ComponentType::Instance(decls) => {
575 let ty = Self::create_instance_type(components, decls.into_vec(), types, offset)?;
576 types.push(ty).into()
577 }
578 crate::ComponentType::Resource { rep, dtor } => {
579 let component = current(components);
580
581 if component.kind != ComponentKind::Component {
584 bail!(
585 offset,
586 "resources can only be defined within a concrete component"
587 );
588 }
589
590 if rep != ValType::I32 {
592 bail!(offset, "resources can only be represented by `i32`");
593 }
594
595 if let Some(dtor) = dtor {
598 let ty = component.core_function_at(dtor, offset)?;
599 let ty = types[ty].composite_type.unwrap_func();
600 if ty.params() != [rep] || ty.results() != [] {
601 bail!(
602 offset,
603 "core function {dtor} has wrong signature for a destructor"
604 );
605 }
606 }
607
608 let id = types.alloc_resource_id();
614 component.defined_resources.insert(id.resource(), Some(rep));
615 id.into()
616 }
617 };
618
619 let current = current(components);
620 if check_limit {
621 check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
622 }
623 current.types.push(id);
624
625 Ok(())
626 }
627
628 pub fn add_import(
629 &mut self,
630 import: crate::ComponentImport,
631 types: &mut TypeAlloc,
632 offset: usize,
633 ) -> Result<()> {
634 let mut entity = self.check_type_ref(&import.ty, types, offset)?;
635 self.add_entity(
636 &mut entity,
637 Some((import.name.0, ExternKind::Import)),
638 types,
639 offset,
640 )?;
641 self.toplevel_imported_resources.validate_extern(
642 import.name.0,
643 ExternKind::Import,
644 &entity,
645 types,
646 offset,
647 &mut self.import_names,
648 &mut self.imports,
649 &mut self.type_info,
650 &self.features,
651 )?;
652 Ok(())
653 }
654
655 fn add_entity(
656 &mut self,
657 ty: &mut ComponentEntityType,
658 name_and_kind: Option<(&str, ExternKind)>,
659 types: &mut TypeAlloc,
660 offset: usize,
661 ) -> Result<()> {
662 let kind = name_and_kind.map(|(_, k)| k);
663 let (len, max, desc) = match ty {
664 ComponentEntityType::Module(id) => {
665 self.core_modules.push(*id);
666 (self.core_modules.len(), MAX_WASM_MODULES, "modules")
667 }
668 ComponentEntityType::Component(id) => {
669 self.components.push(*id);
670 (self.components.len(), MAX_WASM_COMPONENTS, "components")
671 }
672 ComponentEntityType::Instance(id) => {
673 match kind {
674 Some(ExternKind::Import) => self.prepare_instance_import(id, types),
675 Some(ExternKind::Export) => self.prepare_instance_export(id, types),
676 None => {}
677 }
678 self.instances.push(*id);
679 (self.instance_count(), MAX_WASM_INSTANCES, "instances")
680 }
681 ComponentEntityType::Func(id) => {
682 self.funcs.push(*id);
683 (self.function_count(), MAX_WASM_FUNCTIONS, "functions")
684 }
685 ComponentEntityType::Value(ty) => {
686 self.check_value_support(offset)?;
687 let value_used = match kind {
688 Some(ExternKind::Import) | None => false,
689 Some(ExternKind::Export) => true,
690 };
691 self.values.push((*ty, value_used));
692 (self.values.len(), MAX_WASM_VALUES, "values")
693 }
694 ComponentEntityType::Type {
695 created,
696 referenced,
697 } => {
698 self.types.push(*created);
699
700 if let ComponentAnyTypeId::Resource(id) = *created {
705 match kind {
706 Some(ExternKind::Import) => {
707 if created == referenced {
714 self.imported_resources
715 .insert(id.resource(), vec![self.imports.len()]);
716 }
717 }
718
719 Some(ExternKind::Export) => {
720 if created == referenced {
729 self.defined_resources.insert(id.resource(), None);
730 }
731
732 self.explicit_resources
737 .insert(id.resource(), vec![self.exports.len()]);
738 }
739
740 None => {}
741 }
742 }
743 (self.types.len(), MAX_WASM_TYPES, "types")
744 }
745 };
746
747 check_max(len, 0, max, desc, offset)?;
748
749 if let Some((name, kind)) = name_and_kind {
753 if !self.validate_and_register_named_types(Some(name), kind, ty, types) {
754 bail!(
755 offset,
756 "{} not valid to be used as {}",
757 ty.desc(),
758 kind.desc()
759 );
760 }
761 }
762 Ok(())
763 }
764
765 fn validate_and_register_named_types(
779 &mut self,
780 toplevel_name: Option<&str>,
781 kind: ExternKind,
782 ty: &ComponentEntityType,
783 types: &TypeAlloc,
784 ) -> bool {
785 if let ComponentEntityType::Type { created, .. } = ty {
786 if let Some(name) = toplevel_name {
790 if let ComponentAnyTypeId::Resource(id) = *created {
791 let cx = match kind {
792 ExternKind::Import => &mut self.toplevel_imported_resources,
793 ExternKind::Export => &mut self.toplevel_exported_resources,
794 };
795 cx.register(name, id);
796 }
797 }
798 }
799
800 match self.kind {
801 ComponentKind::Component | ComponentKind::ComponentType => {}
802 ComponentKind::InstanceType => return true,
803 }
804 let set = match kind {
805 ExternKind::Import => &self.imported_types,
806 ExternKind::Export => &self.exported_types,
807 };
808 match ty {
809 ComponentEntityType::Type {
816 created,
817 referenced,
818 } => {
819 if !self.all_valtypes_named(types, *referenced, set) {
820 return false;
821 }
822 match kind {
823 ExternKind::Import => {
826 self.imported_types.insert(*created);
827 self.exported_types.insert(*created);
828 }
829 ExternKind::Export => {
830 self.exported_types.insert(*created);
831 }
832 }
833
834 true
835 }
836
837 ComponentEntityType::Instance(i) => types[*i]
850 .exports
851 .iter()
852 .all(|(_name, ty)| self.validate_and_register_named_types(None, kind, ty, types)),
853
854 ComponentEntityType::Func(id) => self.all_valtypes_named_in_func(types, *id, set),
856
857 ComponentEntityType::Value(ty) => types.type_named_valtype(ty, set),
858
859 ComponentEntityType::Component(_) | ComponentEntityType::Module(_) => true,
862 }
863 }
864
865 fn all_valtypes_named(
866 &self,
867 types: &TypeAlloc,
868 id: ComponentAnyTypeId,
869 set: &Set<ComponentAnyTypeId>,
870 ) -> bool {
871 match id {
872 ComponentAnyTypeId::Resource(_) => true,
878
879 ComponentAnyTypeId::Component(_) => true,
883
884 ComponentAnyTypeId::Defined(id) => self.all_valtypes_named_in_defined(types, id, set),
885 ComponentAnyTypeId::Func(id) => self.all_valtypes_named_in_func(types, id, set),
886 ComponentAnyTypeId::Instance(id) => self.all_valtypes_named_in_instance(types, id, set),
887 }
888 }
889
890 fn all_valtypes_named_in_instance(
891 &self,
892 types: &TypeAlloc,
893 id: ComponentInstanceTypeId,
894 set: &Set<ComponentAnyTypeId>,
895 ) -> bool {
896 let ty = &types[id];
898 ty.exports.values().all(|ty| match ty {
899 ComponentEntityType::Module(_) => true,
900 ComponentEntityType::Func(id) => self.all_valtypes_named_in_func(types, *id, set),
901 ComponentEntityType::Type { created: id, .. } => {
902 self.all_valtypes_named(types, *id, set)
903 }
904 ComponentEntityType::Value(ComponentValType::Type(id)) => {
905 self.all_valtypes_named_in_defined(types, *id, set)
906 }
907 ComponentEntityType::Instance(id) => {
908 self.all_valtypes_named_in_instance(types, *id, set)
909 }
910 ComponentEntityType::Component(_)
911 | ComponentEntityType::Value(ComponentValType::Primitive(_)) => return true,
912 })
913 }
914
915 fn all_valtypes_named_in_defined(
916 &self,
917 types: &TypeAlloc,
918 id: ComponentDefinedTypeId,
919 set: &Set<ComponentAnyTypeId>,
920 ) -> bool {
921 let ty = &types[id];
922 match ty {
923 ComponentDefinedType::Primitive(_)
926 | ComponentDefinedType::Flags(_)
927 | ComponentDefinedType::Enum(_) => true,
928
929 ComponentDefinedType::Record(r) => {
932 r.fields.values().all(|t| types.type_named_valtype(t, set))
933 }
934 ComponentDefinedType::Tuple(r) => {
935 r.types.iter().all(|t| types.type_named_valtype(t, set))
936 }
937 ComponentDefinedType::Variant(r) => r
938 .cases
939 .values()
940 .filter_map(|t| t.ty.as_ref())
941 .all(|t| types.type_named_valtype(t, set)),
942 ComponentDefinedType::Result { ok, err } => {
943 ok.as_ref()
944 .map(|t| types.type_named_valtype(t, set))
945 .unwrap_or(true)
946 && err
947 .as_ref()
948 .map(|t| types.type_named_valtype(t, set))
949 .unwrap_or(true)
950 }
951 ComponentDefinedType::List(ty)
952 | ComponentDefinedType::FixedSizeList(ty, _)
953 | ComponentDefinedType::Option(ty) => types.type_named_valtype(ty, set),
954
955 ComponentDefinedType::Own(id) | ComponentDefinedType::Borrow(id) => {
957 set.contains(&ComponentAnyTypeId::from(*id))
958 }
959
960 ComponentDefinedType::Future(ty) => ty
961 .as_ref()
962 .map(|ty| types.type_named_valtype(ty, set))
963 .unwrap_or(true),
964 ComponentDefinedType::Stream(ty) => ty
965 .as_ref()
966 .map(|ty| types.type_named_valtype(ty, set))
967 .unwrap_or(true),
968 }
969 }
970
971 fn all_valtypes_named_in_func(
972 &self,
973 types: &TypeAlloc,
974 id: ComponentFuncTypeId,
975 set: &Set<ComponentAnyTypeId>,
976 ) -> bool {
977 let ty = &types[id];
978 ty.params
980 .iter()
981 .map(|(_, ty)| ty)
982 .chain(&ty.result)
983 .all(|ty| types.type_named_valtype(ty, set))
984 }
985
986 fn prepare_instance_import(&mut self, id: &mut ComponentInstanceTypeId, types: &mut TypeAlloc) {
1000 let ty = &types[*id];
1001
1002 if ty.defined_resources.is_empty() {
1005 return;
1006 }
1007
1008 let mut new_ty = ComponentInstanceType {
1009 info: ty.info,
1011
1012 exports: ty.exports.clone(),
1015 explicit_resources: ty.explicit_resources.clone(),
1016
1017 defined_resources: Default::default(),
1020 };
1021
1022 let resources = (0..ty.defined_resources.len())
1024 .map(|_| types.alloc_resource_id())
1025 .collect::<IndexSet<_>>();
1026
1027 let mut mapping = Remapping::default();
1034 let ty = &types[*id];
1035 for (old, new) in ty.defined_resources.iter().zip(&resources) {
1036 let prev = mapping.resources.insert(*old, new.resource());
1037 assert!(prev.is_none());
1038
1039 let mut base = vec![self.imports.len()];
1040 base.extend(ty.explicit_resources[old].iter().copied());
1041 self.imported_resources.insert(new.resource(), base);
1042 }
1043
1044 for ty in new_ty.exports.values_mut() {
1047 types.remap_component_entity(ty, &mut mapping);
1048 }
1049 for (id, path) in mem::take(&mut new_ty.explicit_resources) {
1050 let id = *mapping.resources.get(&id).unwrap_or(&id);
1051 new_ty.explicit_resources.insert(id, path);
1052 }
1053
1054 *id = types.push_ty(new_ty);
1057 }
1058
1059 fn prepare_instance_export(&mut self, id: &mut ComponentInstanceTypeId, types: &mut TypeAlloc) {
1066 let ty = &types[*id];
1072
1073 if !ty.defined_resources.is_empty() {
1093 let mut new_ty = ty.clone();
1094 let mut mapping = Remapping::default();
1095 for old in mem::take(&mut new_ty.defined_resources) {
1096 let new = types.alloc_resource_id();
1097 mapping.resources.insert(old, new.resource());
1098 self.defined_resources.insert(new.resource(), None);
1099 }
1100 for ty in new_ty.exports.values_mut() {
1101 types.remap_component_entity(ty, &mut mapping);
1102 }
1103 for (id, path) in mem::take(&mut new_ty.explicit_resources) {
1104 let id = mapping.resources.get(&id).copied().unwrap_or(id);
1105 new_ty.explicit_resources.insert(id, path);
1106 }
1107 *id = types.push_ty(new_ty);
1108 }
1109
1110 let ty = &types[*id];
1117 for (id, path) in ty.explicit_resources.iter() {
1118 let mut new_path = vec![self.exports.len()];
1119 new_path.extend(path);
1120 self.explicit_resources.insert(*id, new_path);
1121 }
1122 }
1123
1124 pub fn add_export(
1125 &mut self,
1126 name: ComponentExportName<'_>,
1127 mut ty: ComponentEntityType,
1128 types: &mut TypeAlloc,
1129 offset: usize,
1130 check_limit: bool,
1131 ) -> Result<()> {
1132 if check_limit {
1133 check_max(self.exports.len(), 1, MAX_WASM_EXPORTS, "exports", offset)?;
1134 }
1135 self.add_entity(&mut ty, Some((name.0, ExternKind::Export)), types, offset)?;
1136 self.toplevel_exported_resources.validate_extern(
1137 name.0,
1138 ExternKind::Export,
1139 &ty,
1140 types,
1141 offset,
1142 &mut self.export_names,
1143 &mut self.exports,
1144 &mut self.type_info,
1145 &self.features,
1146 )?;
1147 Ok(())
1148 }
1149
1150 pub fn canonical_function(
1151 &mut self,
1152 func: CanonicalFunction,
1153 types: &mut TypeAlloc,
1154 offset: usize,
1155 ) -> Result<()> {
1156 match func {
1157 CanonicalFunction::Lift {
1158 core_func_index,
1159 type_index,
1160 options,
1161 } => self.lift_function(core_func_index, type_index, &options, types, offset),
1162 CanonicalFunction::Lower {
1163 func_index,
1164 options,
1165 } => self.lower_function(func_index, &options, types, offset),
1166 CanonicalFunction::ResourceNew { resource } => {
1167 self.resource_new(resource, types, offset)
1168 }
1169 CanonicalFunction::ResourceDrop { resource } => {
1170 self.resource_drop(resource, types, offset)
1171 }
1172 CanonicalFunction::ResourceDropAsync { resource } => {
1173 self.resource_drop_async(resource, types, offset)
1174 }
1175 CanonicalFunction::ResourceRep { resource } => {
1176 self.resource_rep(resource, types, offset)
1177 }
1178 CanonicalFunction::ThreadSpawnRef { func_ty_index } => {
1179 self.thread_spawn_ref(func_ty_index, types, offset)
1180 }
1181 CanonicalFunction::ThreadSpawnIndirect {
1182 func_ty_index,
1183 table_index,
1184 } => self.thread_spawn_indirect(func_ty_index, table_index, types, offset),
1185 CanonicalFunction::ThreadAvailableParallelism => {
1186 self.thread_available_parallelism(types, offset)
1187 }
1188 CanonicalFunction::BackpressureSet => self.backpressure_set(types, offset),
1189 CanonicalFunction::BackpressureInc => self.backpressure_inc(types, offset),
1190 CanonicalFunction::BackpressureDec => self.backpressure_dec(types, offset),
1191 CanonicalFunction::TaskReturn { result, options } => {
1192 self.task_return(&result, &options, types, offset)
1193 }
1194 CanonicalFunction::TaskCancel => self.task_cancel(types, offset),
1195 CanonicalFunction::ContextGet(i) => self.context_get(i, types, offset),
1196 CanonicalFunction::ContextSet(i) => self.context_set(i, types, offset),
1197 CanonicalFunction::ThreadYield { cancellable } => {
1198 self.thread_yield(cancellable, types, offset)
1199 }
1200 CanonicalFunction::SubtaskDrop => self.subtask_drop(types, offset),
1201 CanonicalFunction::SubtaskCancel { async_ } => {
1202 self.subtask_cancel(async_, types, offset)
1203 }
1204 CanonicalFunction::StreamNew { ty } => self.stream_new(ty, types, offset),
1205 CanonicalFunction::StreamRead { ty, options } => {
1206 self.stream_read(ty, &options, types, offset)
1207 }
1208 CanonicalFunction::StreamWrite { ty, options } => {
1209 self.stream_write(ty, &options, types, offset)
1210 }
1211 CanonicalFunction::StreamCancelRead { ty, async_ } => {
1212 self.stream_cancel_read(ty, async_, types, offset)
1213 }
1214 CanonicalFunction::StreamCancelWrite { ty, async_ } => {
1215 self.stream_cancel_write(ty, async_, types, offset)
1216 }
1217 CanonicalFunction::StreamDropReadable { ty } => {
1218 self.stream_drop_readable(ty, types, offset)
1219 }
1220 CanonicalFunction::StreamDropWritable { ty } => {
1221 self.stream_drop_writable(ty, types, offset)
1222 }
1223 CanonicalFunction::FutureNew { ty } => self.future_new(ty, types, offset),
1224 CanonicalFunction::FutureRead { ty, options } => {
1225 self.future_read(ty, &options, types, offset)
1226 }
1227 CanonicalFunction::FutureWrite { ty, options } => {
1228 self.future_write(ty, options.into_vec(), types, offset)
1229 }
1230 CanonicalFunction::FutureCancelRead { ty, async_ } => {
1231 self.future_cancel_read(ty, async_, types, offset)
1232 }
1233 CanonicalFunction::FutureCancelWrite { ty, async_ } => {
1234 self.future_cancel_write(ty, async_, types, offset)
1235 }
1236 CanonicalFunction::FutureDropReadable { ty } => {
1237 self.future_drop_readable(ty, types, offset)
1238 }
1239 CanonicalFunction::FutureDropWritable { ty } => {
1240 self.future_drop_writable(ty, types, offset)
1241 }
1242 CanonicalFunction::ErrorContextNew { options } => {
1243 self.error_context_new(options.into_vec(), types, offset)
1244 }
1245 CanonicalFunction::ErrorContextDebugMessage { options } => {
1246 self.error_context_debug_message(options.into_vec(), types, offset)
1247 }
1248 CanonicalFunction::ErrorContextDrop => self.error_context_drop(types, offset),
1249 CanonicalFunction::WaitableSetNew => self.waitable_set_new(types, offset),
1250 CanonicalFunction::WaitableSetWait {
1251 cancellable,
1252 memory,
1253 } => self.waitable_set_wait(cancellable, memory, types, offset),
1254 CanonicalFunction::WaitableSetPoll {
1255 cancellable,
1256 memory,
1257 } => self.waitable_set_poll(cancellable, memory, types, offset),
1258 CanonicalFunction::WaitableSetDrop => self.waitable_set_drop(types, offset),
1259 CanonicalFunction::WaitableJoin => self.waitable_join(types, offset),
1260 CanonicalFunction::ThreadIndex => self.thread_index(types, offset),
1261 CanonicalFunction::ThreadNewIndirect {
1262 func_ty_index,
1263 table_index,
1264 } => self.thread_new_indirect(func_ty_index, table_index, types, offset),
1265 CanonicalFunction::ThreadSwitchTo { cancellable } => {
1266 self.thread_switch_to(cancellable, types, offset)
1267 }
1268 CanonicalFunction::ThreadSuspend { cancellable } => {
1269 self.thread_suspend(cancellable, types, offset)
1270 }
1271 CanonicalFunction::ThreadResumeLater => self.thread_resume_later(types, offset),
1272
1273 CanonicalFunction::ThreadYieldTo { cancellable } => {
1274 self.thread_yield_to(cancellable, types, offset)
1275 }
1276 }
1277 }
1278
1279 fn lift_function(
1280 &mut self,
1281 core_func_index: u32,
1282 type_index: u32,
1283 options: &[CanonicalOption],
1284 types: &mut TypeAlloc,
1285 offset: usize,
1286 ) -> Result<()> {
1287 let ty = self.function_type_at(type_index, types, offset)?;
1288 let core_ty_id = self.core_function_at(core_func_index, offset)?;
1289
1290 let mut options = self.check_options(types, options, offset)?;
1293 options.check_lift(types, self, core_ty_id, offset)?;
1294 let func_ty = ty.lower(types, &options, Abi::Lift, offset)?;
1295 let lowered_core_ty_id = func_ty.intern(types, offset);
1296
1297 if core_ty_id == lowered_core_ty_id {
1298 self.funcs
1299 .push(self.types[type_index as usize].unwrap_func());
1300 return Ok(());
1301 }
1302
1303 let ty = types[core_ty_id].unwrap_func();
1304 let lowered_ty = types[lowered_core_ty_id].unwrap_func();
1305
1306 if lowered_ty.params() != ty.params() {
1307 bail!(
1308 offset,
1309 "lowered parameter types `{:?}` do not match parameter types `{:?}` of \
1310 core function {core_func_index}",
1311 lowered_ty.params(),
1312 ty.params()
1313 );
1314 }
1315
1316 if lowered_ty.results() != ty.results() {
1317 bail!(
1318 offset,
1319 "lowered result types `{:?}` do not match result types `{:?}` of \
1320 core function {core_func_index}",
1321 lowered_ty.results(),
1322 ty.results()
1323 );
1324 }
1325
1326 bail!(
1329 offset,
1330 "lowered function type `{:?}` does not match type `{:?}` of \
1331 core function {core_func_index}",
1332 types[lowered_core_ty_id],
1333 types[core_ty_id],
1334 );
1335 }
1336
1337 fn lower_function(
1338 &mut self,
1339 func_index: u32,
1340 options: &[CanonicalOption],
1341 types: &mut TypeAlloc,
1342 offset: usize,
1343 ) -> Result<()> {
1344 let ty = &types[self.function_at(func_index, offset)?];
1345
1346 let options = self.check_options(types, options, offset)?;
1349 options.check_lower(offset)?;
1350 let func_ty = ty.lower(types, &options, Abi::Lower, offset)?;
1351 let ty_id = func_ty.intern(types, offset);
1352
1353 self.core_funcs.push(ty_id);
1354 Ok(())
1355 }
1356
1357 fn resource_new(&mut self, resource: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1358 let rep = self.check_local_resource(resource, types, offset)?;
1359 let id = types.intern_func_type(FuncType::new([rep], [ValType::I32]), offset);
1360 self.core_funcs.push(id);
1361 Ok(())
1362 }
1363
1364 fn resource_drop(&mut self, resource: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1365 self.resource_at(resource, types, offset)?;
1366 let id = types.intern_func_type(FuncType::new([ValType::I32], []), offset);
1367 self.core_funcs.push(id);
1368 Ok(())
1369 }
1370
1371 fn resource_drop_async(
1372 &mut self,
1373 resource: u32,
1374 types: &mut TypeAlloc,
1375 offset: usize,
1376 ) -> Result<()> {
1377 if !self.features.cm_async_builtins() {
1378 bail!(
1379 offset,
1380 "`resource.drop` as `async` requires the component model async builtins feature"
1381 )
1382 }
1383 self.resource_at(resource, types, offset)?;
1384 let id = types.intern_func_type(FuncType::new([ValType::I32], []), offset);
1385 self.core_funcs.push(id);
1386 Ok(())
1387 }
1388
1389 fn resource_rep(&mut self, resource: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1390 let rep = self.check_local_resource(resource, types, offset)?;
1391 let id = types.intern_func_type(FuncType::new([ValType::I32], [rep]), offset);
1392 self.core_funcs.push(id);
1393 Ok(())
1394 }
1395
1396 fn backpressure_set(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1397 if !self.features.cm_async() {
1398 bail!(
1399 offset,
1400 "`backpressure.set` requires the component model async feature"
1401 )
1402 }
1403
1404 self.core_funcs
1405 .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
1406 Ok(())
1407 }
1408
1409 fn backpressure_inc(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1410 if !self.features.cm_async() {
1411 bail!(
1412 offset,
1413 "`backpressure.inc` requires the component model async feature"
1414 )
1415 }
1416
1417 self.core_funcs
1418 .push(types.intern_func_type(FuncType::new([], []), offset));
1419 Ok(())
1420 }
1421
1422 fn backpressure_dec(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1423 if !self.features.cm_async() {
1424 bail!(
1425 offset,
1426 "`backpressure.dec` requires the component model async feature"
1427 )
1428 }
1429
1430 self.core_funcs
1431 .push(types.intern_func_type(FuncType::new([], []), offset));
1432 Ok(())
1433 }
1434
1435 fn task_return(
1436 &mut self,
1437 result: &Option<crate::ComponentValType>,
1438 options: &[CanonicalOption],
1439 types: &mut TypeAlloc,
1440 offset: usize,
1441 ) -> Result<()> {
1442 if !self.features.cm_async() {
1443 bail!(
1444 offset,
1445 "`task.return` requires the component model async feature"
1446 )
1447 }
1448
1449 let func_ty = ComponentFuncType {
1450 info: TypeInfo::new(),
1451 params: result
1452 .iter()
1453 .map(|ty| {
1454 Ok((
1455 KebabString::new("v").unwrap(),
1456 match ty {
1457 crate::ComponentValType::Primitive(ty) => {
1458 ComponentValType::Primitive(*ty)
1459 }
1460 crate::ComponentValType::Type(index) => {
1461 ComponentValType::Type(self.defined_type_at(*index, offset)?)
1462 }
1463 },
1464 ))
1465 })
1466 .collect::<Result<_>>()?,
1467 result: None,
1468 };
1469
1470 let options = self.check_options(types, options, offset)?;
1471 if options.realloc.is_some() {
1472 bail!(offset, "cannot specify `realloc` option on `task.return`")
1473 }
1474 if options.post_return.is_some() {
1475 bail!(
1476 offset,
1477 "cannot specify `post-return` option on `task.return`"
1478 )
1479 }
1480 options.check_lower(offset)?;
1481 options.require_sync(offset, "task.return")?;
1482
1483 let func_ty = func_ty.lower(types, &options, Abi::Lower, offset)?;
1484 let ty_id = func_ty.intern(types, offset);
1485
1486 self.core_funcs.push(ty_id);
1487 Ok(())
1488 }
1489
1490 fn task_cancel(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1491 if !self.features.cm_async() {
1492 bail!(
1493 offset,
1494 "`task.cancel` requires the component model async feature"
1495 )
1496 }
1497
1498 self.core_funcs
1499 .push(types.intern_func_type(FuncType::new([], []), offset));
1500 Ok(())
1501 }
1502
1503 fn validate_context_immediate(
1504 &self,
1505 immediate: u32,
1506 operation: &str,
1507 offset: usize,
1508 ) -> Result<()> {
1509 if !self.features.cm_threading() && immediate > 0 {
1510 bail!(offset, "`{operation}` immediate must be zero: {immediate}")
1511 } else if immediate > 1 {
1512 bail!(
1513 offset,
1514 "`{operation}` immediate must be zero or one: {immediate}"
1515 )
1516 }
1517 Ok(())
1518 }
1519
1520 fn context_get(&mut self, i: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1521 if !self.features.cm_async() {
1522 bail!(
1523 offset,
1524 "`context.get` requires the component model async feature"
1525 )
1526 }
1527 self.validate_context_immediate(i, "context.get", offset)?;
1528
1529 self.core_funcs
1530 .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset));
1531 Ok(())
1532 }
1533
1534 fn context_set(&mut self, i: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1535 if !self.features.cm_async() {
1536 bail!(
1537 offset,
1538 "`context.set` requires the component model async feature"
1539 )
1540 }
1541 self.validate_context_immediate(i, "context.set", offset)?;
1542
1543 self.core_funcs
1544 .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
1545 Ok(())
1546 }
1547
1548 fn thread_yield(
1549 &mut self,
1550 cancellable: bool,
1551 types: &mut TypeAlloc,
1552 offset: usize,
1553 ) -> Result<()> {
1554 if !self.features.cm_async() {
1555 bail!(
1556 offset,
1557 "`thread.yield` requires the component model async feature"
1558 )
1559 }
1560 if cancellable && !self.features.cm_async_stackful() {
1561 bail!(
1562 offset,
1563 "cancellable `thread.yield` requires the component model async stackful feature"
1564 )
1565 }
1566
1567 self.core_funcs
1568 .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset));
1569 Ok(())
1570 }
1571
1572 fn subtask_drop(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1573 if !self.features.cm_async() {
1574 bail!(
1575 offset,
1576 "`subtask.drop` requires the component model async feature"
1577 )
1578 }
1579
1580 self.core_funcs
1581 .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
1582 Ok(())
1583 }
1584
1585 fn subtask_cancel(&mut self, async_: bool, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1586 if !self.features.cm_async() {
1587 bail!(
1588 offset,
1589 "`subtask.cancel` requires the component model async feature"
1590 )
1591 }
1592 if async_ && !self.features.cm_async_builtins() {
1593 bail!(
1594 offset,
1595 "async `subtask.cancel` requires the component model async builtins feature"
1596 )
1597 }
1598
1599 self.core_funcs
1600 .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
1601 Ok(())
1602 }
1603
1604 fn stream_new(&mut self, ty: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1605 if !self.features.cm_async() {
1606 bail!(
1607 offset,
1608 "`stream.new` requires the component model async feature"
1609 )
1610 }
1611
1612 let ty = self.defined_type_at(ty, offset)?;
1613 let ComponentDefinedType::Stream(_) = &types[ty] else {
1614 bail!(offset, "`stream.new` requires a stream type")
1615 };
1616
1617 self.core_funcs
1618 .push(types.intern_func_type(FuncType::new([], [ValType::I64]), offset));
1619 Ok(())
1620 }
1621
1622 fn stream_read(
1623 &mut self,
1624 ty: u32,
1625 options: &[CanonicalOption],
1626 types: &mut TypeAlloc,
1627 offset: usize,
1628 ) -> Result<()> {
1629 if !self.features.cm_async() {
1630 bail!(
1631 offset,
1632 "`stream.read` requires the component model async feature"
1633 )
1634 }
1635
1636 let ty = self.defined_type_at(ty, offset)?;
1637 let ComponentDefinedType::Stream(elem_ty) = &types[ty] else {
1638 bail!(offset, "`stream.read` requires a stream type")
1639 };
1640
1641 let ty_id = self
1642 .check_options(types, options, offset)?
1643 .require_memory(offset)?
1644 .require_realloc_if(offset, || elem_ty.is_some_and(|ty| ty.contains_ptr(types)))?
1645 .check_lower(offset)?
1646 .check_core_type(
1647 types,
1648 FuncType::new([ValType::I32; 3], [ValType::I32]),
1649 offset,
1650 )?;
1651
1652 self.core_funcs.push(ty_id);
1653 Ok(())
1654 }
1655
1656 fn stream_write(
1657 &mut self,
1658 ty: u32,
1659 options: &[CanonicalOption],
1660 types: &mut TypeAlloc,
1661 offset: usize,
1662 ) -> Result<()> {
1663 if !self.features.cm_async() {
1664 bail!(
1665 offset,
1666 "`stream.write` requires the component model async feature"
1667 )
1668 }
1669
1670 let ty = self.defined_type_at(ty, offset)?;
1671 let ComponentDefinedType::Stream(_) = &types[ty] else {
1672 bail!(offset, "`stream.write` requires a stream type")
1673 };
1674
1675 let ty_id = self
1676 .check_options(types, options, offset)?
1677 .require_memory(offset)?
1678 .check_lower(offset)?
1679 .check_core_type(
1680 types,
1681 FuncType::new([ValType::I32; 3], [ValType::I32]),
1682 offset,
1683 )?;
1684
1685 self.core_funcs.push(ty_id);
1686 Ok(())
1687 }
1688
1689 fn stream_cancel_read(
1690 &mut self,
1691 ty: u32,
1692 cancellable: bool,
1693 types: &mut TypeAlloc,
1694 offset: usize,
1695 ) -> Result<()> {
1696 if !self.features.cm_async() {
1697 bail!(
1698 offset,
1699 "`stream.cancel-read` requires the component model async feature"
1700 )
1701 }
1702 if cancellable && !self.features.cm_async_builtins() {
1703 bail!(
1704 offset,
1705 "async `stream.cancel-read` requires the component model async builtins feature"
1706 )
1707 }
1708
1709 let ty = self.defined_type_at(ty, offset)?;
1710 let ComponentDefinedType::Stream(_) = &types[ty] else {
1711 bail!(offset, "`stream.cancel-read` requires a stream type")
1712 };
1713
1714 self.core_funcs
1715 .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
1716 Ok(())
1717 }
1718
1719 fn stream_cancel_write(
1720 &mut self,
1721 ty: u32,
1722 cancellable: bool,
1723 types: &mut TypeAlloc,
1724 offset: usize,
1725 ) -> Result<()> {
1726 if !self.features.cm_async() {
1727 bail!(
1728 offset,
1729 "`stream.cancel-write` requires the component model async feature"
1730 )
1731 }
1732 if cancellable && !self.features.cm_async_builtins() {
1733 bail!(
1734 offset,
1735 "async `stream.cancel-write` requires the component model async builtins feature"
1736 )
1737 }
1738
1739 let ty = self.defined_type_at(ty, offset)?;
1740 let ComponentDefinedType::Stream(_) = &types[ty] else {
1741 bail!(offset, "`stream.cancel-write` requires a stream type")
1742 };
1743
1744 self.core_funcs
1745 .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
1746 Ok(())
1747 }
1748
1749 fn stream_drop_readable(
1750 &mut self,
1751 ty: u32,
1752 types: &mut TypeAlloc,
1753 offset: usize,
1754 ) -> Result<()> {
1755 if !self.features.cm_async() {
1756 bail!(
1757 offset,
1758 "`stream.drop-readable` requires the component model async feature"
1759 )
1760 }
1761
1762 let ty = self.defined_type_at(ty, offset)?;
1763 let ComponentDefinedType::Stream(_) = &types[ty] else {
1764 bail!(offset, "`stream.drop-readable` requires a stream type")
1765 };
1766
1767 self.core_funcs
1768 .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
1769 Ok(())
1770 }
1771
1772 fn stream_drop_writable(
1773 &mut self,
1774 ty: u32,
1775 types: &mut TypeAlloc,
1776 offset: usize,
1777 ) -> Result<()> {
1778 if !self.features.cm_async() {
1779 bail!(
1780 offset,
1781 "`stream.drop-writable` requires the component model async feature"
1782 )
1783 }
1784
1785 let ty = self.defined_type_at(ty, offset)?;
1786 let ComponentDefinedType::Stream(_) = &types[ty] else {
1787 bail!(offset, "`stream.drop-writable` requires a stream type")
1788 };
1789
1790 self.core_funcs
1791 .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
1792 Ok(())
1793 }
1794
1795 fn future_new(&mut self, ty: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1796 if !self.features.cm_async() {
1797 bail!(
1798 offset,
1799 "`future.new` requires the component model async feature"
1800 )
1801 }
1802
1803 let ty = self.defined_type_at(ty, offset)?;
1804 let ComponentDefinedType::Future(_) = &types[ty] else {
1805 bail!(offset, "`future.new` requires a future type")
1806 };
1807
1808 self.core_funcs
1809 .push(types.intern_func_type(FuncType::new([], [ValType::I64]), offset));
1810 Ok(())
1811 }
1812
1813 fn future_read(
1814 &mut self,
1815 ty: u32,
1816 options: &[CanonicalOption],
1817 types: &mut TypeAlloc,
1818 offset: usize,
1819 ) -> Result<()> {
1820 if !self.features.cm_async() {
1821 bail!(
1822 offset,
1823 "`future.read` requires the component model async feature"
1824 )
1825 }
1826
1827 let ty = self.defined_type_at(ty, offset)?;
1828 let ComponentDefinedType::Future(elem_ty) = &types[ty] else {
1829 bail!(offset, "`future.read` requires a future type")
1830 };
1831
1832 let ty_id = self
1833 .check_options(types, options, offset)?
1834 .require_memory_if(offset, || elem_ty.is_some())?
1835 .require_realloc_if(offset, || elem_ty.is_some_and(|ty| ty.contains_ptr(types)))?
1836 .check_lower(offset)?
1837 .check_core_type(
1838 types,
1839 FuncType::new([ValType::I32; 2], [ValType::I32]),
1840 offset,
1841 )?;
1842
1843 self.core_funcs.push(ty_id);
1844 Ok(())
1845 }
1846
1847 fn future_write(
1848 &mut self,
1849 ty: u32,
1850 options: Vec<CanonicalOption>,
1851 types: &mut TypeAlloc,
1852 offset: usize,
1853 ) -> Result<()> {
1854 if !self.features.cm_async() {
1855 bail!(
1856 offset,
1857 "`future.write` requires the component model async feature"
1858 )
1859 }
1860
1861 let ty = self.defined_type_at(ty, offset)?;
1862 let ComponentDefinedType::Future(elem_ty) = &types[ty] else {
1863 bail!(offset, "`future.write` requires a future type")
1864 };
1865
1866 let ty_id = self
1867 .check_options(types, &options, offset)?
1868 .require_memory_if(offset, || elem_ty.is_some())?
1869 .check_core_type(
1870 types,
1871 FuncType::new([ValType::I32; 2], [ValType::I32]),
1872 offset,
1873 )?;
1874
1875 self.core_funcs.push(ty_id);
1876 Ok(())
1877 }
1878
1879 fn future_cancel_read(
1880 &mut self,
1881 ty: u32,
1882 cancellable: bool,
1883 types: &mut TypeAlloc,
1884 offset: usize,
1885 ) -> Result<()> {
1886 if !self.features.cm_async() {
1887 bail!(
1888 offset,
1889 "`future.cancel-read` requires the component model async feature"
1890 )
1891 }
1892 if cancellable && !self.features.cm_async_builtins() {
1893 bail!(
1894 offset,
1895 "async `future.cancel-read` requires the component model async builtins feature"
1896 )
1897 }
1898
1899 let ty = self.defined_type_at(ty, offset)?;
1900 let ComponentDefinedType::Future(_) = &types[ty] else {
1901 bail!(offset, "`future.cancel-read` requires a future type")
1902 };
1903
1904 self.core_funcs
1905 .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
1906 Ok(())
1907 }
1908
1909 fn future_cancel_write(
1910 &mut self,
1911 ty: u32,
1912 cancellable: bool,
1913 types: &mut TypeAlloc,
1914 offset: usize,
1915 ) -> Result<()> {
1916 if !self.features.cm_async() {
1917 bail!(
1918 offset,
1919 "`future.cancel-write` requires the component model async feature"
1920 )
1921 }
1922 if cancellable && !self.features.cm_async_builtins() {
1923 bail!(
1924 offset,
1925 "async `future.cancel-write` requires the component model async builtins feature"
1926 )
1927 }
1928
1929 let ty = self.defined_type_at(ty, offset)?;
1930 let ComponentDefinedType::Future(_) = &types[ty] else {
1931 bail!(offset, "`future.cancel-write` requires a future type")
1932 };
1933
1934 self.core_funcs
1935 .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
1936 Ok(())
1937 }
1938
1939 fn future_drop_readable(
1940 &mut self,
1941 ty: u32,
1942 types: &mut TypeAlloc,
1943 offset: usize,
1944 ) -> Result<()> {
1945 if !self.features.cm_async() {
1946 bail!(
1947 offset,
1948 "`future.drop-readable` requires the component model async feature"
1949 )
1950 }
1951
1952 let ty = self.defined_type_at(ty, offset)?;
1953 let ComponentDefinedType::Future(_) = &types[ty] else {
1954 bail!(offset, "`future.drop-readable` requires a future type")
1955 };
1956
1957 self.core_funcs
1958 .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
1959 Ok(())
1960 }
1961
1962 fn future_drop_writable(
1963 &mut self,
1964 ty: u32,
1965 types: &mut TypeAlloc,
1966 offset: usize,
1967 ) -> Result<()> {
1968 if !self.features.cm_async() {
1969 bail!(
1970 offset,
1971 "`future.drop-writable` requires the component model async feature"
1972 )
1973 }
1974
1975 let ty = self.defined_type_at(ty, offset)?;
1976 let ComponentDefinedType::Future(_) = &types[ty] else {
1977 bail!(offset, "`future.drop-writable` requires a future type")
1978 };
1979
1980 self.core_funcs
1981 .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
1982 Ok(())
1983 }
1984
1985 fn error_context_new(
1986 &mut self,
1987 options: Vec<CanonicalOption>,
1988 types: &mut TypeAlloc,
1989 offset: usize,
1990 ) -> Result<()> {
1991 if !self.features.cm_error_context() {
1992 bail!(
1993 offset,
1994 "`error-context.new` requires the component model error-context feature"
1995 )
1996 }
1997
1998 let ty_id = self
1999 .check_options(types, &options, offset)?
2000 .require_memory(offset)?
2001 .require_sync(offset, "error-context.new")?
2002 .check_lower(offset)?
2003 .check_core_type(
2004 types,
2005 FuncType::new([ValType::I32; 2], [ValType::I32]),
2006 offset,
2007 )?;
2008
2009 self.core_funcs.push(ty_id);
2010 Ok(())
2011 }
2012
2013 fn error_context_debug_message(
2014 &mut self,
2015 options: Vec<CanonicalOption>,
2016 types: &mut TypeAlloc,
2017 offset: usize,
2018 ) -> Result<()> {
2019 if !self.features.cm_error_context() {
2020 bail!(
2021 offset,
2022 "`error-context.debug-message` requires the component model error-context feature"
2023 )
2024 }
2025
2026 let ty_id = self
2027 .check_options(types, &options, offset)?
2028 .require_memory(offset)?
2029 .require_realloc(offset)?
2030 .require_sync(offset, "error-context.debug-message")?
2031 .check_lower(offset)?
2032 .check_core_type(types, FuncType::new([ValType::I32; 2], []), offset)?;
2033
2034 self.core_funcs.push(ty_id);
2035 Ok(())
2036 }
2037
2038 fn error_context_drop(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
2039 if !self.features.cm_error_context() {
2040 bail!(
2041 offset,
2042 "`error-context.drop` requires the component model error-context feature"
2043 )
2044 }
2045
2046 self.core_funcs
2047 .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
2048 Ok(())
2049 }
2050
2051 fn waitable_set_new(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
2052 if !self.features.cm_async() {
2053 bail!(
2054 offset,
2055 "`waitable-set.new` requires the component model async feature"
2056 )
2057 }
2058
2059 self.core_funcs
2060 .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset));
2061 Ok(())
2062 }
2063
2064 fn waitable_set_wait(
2065 &mut self,
2066 cancellable: bool,
2067 memory: u32,
2068 types: &mut TypeAlloc,
2069 offset: usize,
2070 ) -> Result<()> {
2071 if !self.features.cm_async() {
2072 bail!(
2073 offset,
2074 "`waitable-set.wait` requires the component model async feature"
2075 )
2076 }
2077 if cancellable && !self.features.cm_async_stackful() {
2078 bail!(
2079 offset,
2080 "cancellable `waitable-set.wait` requires the component model async stackful feature"
2081 )
2082 }
2083
2084 self.cabi_memory_at(memory, offset)?;
2085
2086 self.core_funcs
2087 .push(types.intern_func_type(FuncType::new([ValType::I32; 2], [ValType::I32]), offset));
2088 Ok(())
2089 }
2090
2091 fn waitable_set_poll(
2092 &mut self,
2093 cancellable: bool,
2094 memory: u32,
2095 types: &mut TypeAlloc,
2096 offset: usize,
2097 ) -> Result<()> {
2098 if !self.features.cm_async() {
2099 bail!(
2100 offset,
2101 "`waitable-set.poll` requires the component model async feature"
2102 )
2103 }
2104 if cancellable && !self.features.cm_async_stackful() {
2105 bail!(
2106 offset,
2107 "cancellable `waitable-set.poll` requires the component model async stackful feature"
2108 )
2109 }
2110
2111 self.cabi_memory_at(memory, offset)?;
2112
2113 self.core_funcs
2114 .push(types.intern_func_type(FuncType::new([ValType::I32; 2], [ValType::I32]), offset));
2115 Ok(())
2116 }
2117
2118 fn waitable_set_drop(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
2119 if !self.features.cm_async() {
2120 bail!(
2121 offset,
2122 "`waitable-set.drop` requires the component model async feature"
2123 )
2124 }
2125
2126 self.core_funcs
2127 .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
2128 Ok(())
2129 }
2130
2131 fn waitable_join(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
2132 if !self.features.cm_async() {
2133 bail!(
2134 offset,
2135 "`waitable.join` requires the component model async feature"
2136 )
2137 }
2138
2139 self.core_funcs
2140 .push(types.intern_func_type(FuncType::new([ValType::I32; 2], []), offset));
2141 Ok(())
2142 }
2143
2144 fn thread_index(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
2145 if !self.features.cm_threading() {
2146 bail!(
2147 offset,
2148 "`thread.index` requires the component model threading feature"
2149 )
2150 }
2151
2152 self.core_funcs
2153 .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset));
2154 Ok(())
2155 }
2156
2157 fn thread_new_indirect(
2158 &mut self,
2159 func_ty_index: u32,
2160 table_index: u32,
2161 types: &mut TypeAlloc,
2162 offset: usize,
2163 ) -> Result<()> {
2164 if !self.features.cm_threading() {
2165 bail!(
2166 offset,
2167 "`thread.new_indirect` requires the component model threading feature"
2168 )
2169 }
2170
2171 let core_type_id = match self.core_type_at(func_ty_index, offset)? {
2172 ComponentCoreTypeId::Sub(c) => c,
2173 ComponentCoreTypeId::Module(_) => bail!(offset, "expected a core function type"),
2174 };
2175 let sub_ty = &types[core_type_id];
2176 match &sub_ty.composite_type.inner {
2177 CompositeInnerType::Func(func_ty) => {
2178 if func_ty.params() != [ValType::I32] {
2179 bail!(
2180 offset,
2181 "start function must take a single `i32` argument (currently)"
2182 );
2183 }
2184 if func_ty.results() != [] {
2185 bail!(offset, "start function must not return any values");
2186 }
2187 }
2188 _ => bail!(offset, "start type must be a function"),
2189 }
2190
2191 let table = self.table_at(table_index, offset)?;
2192
2193 SubtypeCx::table_type(
2194 table,
2195 &TableType {
2196 initial: 0,
2197 maximum: None,
2198 table64: false,
2199 shared: false,
2200 element_type: RefType::FUNCREF,
2201 },
2202 offset,
2203 )
2204 .map_err(|mut e| {
2205 e.add_context("table is not a 32-bit table of (ref null (func))".into());
2206 e
2207 })?;
2208
2209 self.core_funcs.push(types.intern_func_type(
2210 FuncType::new([ValType::I32, ValType::I32], [ValType::I32]),
2211 offset,
2212 ));
2213 Ok(())
2214 }
2215
2216 fn thread_switch_to(
2217 &mut self,
2218 _cancellable: bool,
2219 types: &mut TypeAlloc,
2220 offset: usize,
2221 ) -> Result<()> {
2222 if !self.features.cm_threading() {
2223 bail!(
2224 offset,
2225 "`thread.switch_to` requires the component model threading feature"
2226 )
2227 }
2228
2229 self.core_funcs
2230 .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
2231 Ok(())
2232 }
2233
2234 fn thread_suspend(
2235 &mut self,
2236 _cancellable: bool,
2237 types: &mut TypeAlloc,
2238 offset: usize,
2239 ) -> Result<()> {
2240 if !self.features.cm_threading() {
2241 bail!(
2242 offset,
2243 "`thread.suspend` requires the component model threading feature"
2244 )
2245 }
2246 self.core_funcs
2247 .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset));
2248 Ok(())
2249 }
2250
2251 fn thread_resume_later(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
2252 if !self.features.cm_threading() {
2253 bail!(
2254 offset,
2255 "`thread.resume_later` requires the component model threading feature"
2256 )
2257 }
2258 self.core_funcs
2259 .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
2260 Ok(())
2261 }
2262
2263 fn thread_yield_to(
2264 &mut self,
2265 _cancellable: bool,
2266 types: &mut TypeAlloc,
2267 offset: usize,
2268 ) -> Result<()> {
2269 if !self.features.cm_threading() {
2270 bail!(
2271 offset,
2272 "`thread.yield_to` requires the component model threading feature"
2273 )
2274 }
2275 self.core_funcs
2276 .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
2277 Ok(())
2278 }
2279
2280 fn check_local_resource(&self, idx: u32, types: &TypeList, offset: usize) -> Result<ValType> {
2281 let resource = self.resource_at(idx, types, offset)?;
2282 match self
2283 .defined_resources
2284 .get(&resource.resource())
2285 .and_then(|rep| *rep)
2286 {
2287 Some(ty) => Ok(ty),
2288 None => bail!(offset, "type {idx} is not a local resource"),
2289 }
2290 }
2291
2292 fn resource_at<'a>(
2293 &self,
2294 idx: u32,
2295 _types: &'a TypeList,
2296 offset: usize,
2297 ) -> Result<AliasableResourceId> {
2298 if let ComponentAnyTypeId::Resource(id) = self.component_type_at(idx, offset)? {
2299 return Ok(id);
2300 }
2301 bail!(offset, "type index {} is not a resource type", idx)
2302 }
2303
2304 fn thread_spawn_ref(
2305 &mut self,
2306 func_ty_index: u32,
2307 types: &mut TypeAlloc,
2308 offset: usize,
2309 ) -> Result<()> {
2310 if !self.features.shared_everything_threads() {
2311 bail!(
2312 offset,
2313 "`thread.spawn_ref` requires the shared-everything-threads proposal"
2314 )
2315 }
2316 let core_type_id = self.validate_spawn_type(func_ty_index, types, offset)?;
2317
2318 let packed_index = PackedIndex::from_id(core_type_id).ok_or_else(|| {
2320 format_err!(offset, "implementation limit: too many types in `TypeList`")
2321 })?;
2322 let start_func_ref = RefType::concrete(true, packed_index);
2323 let func_ty = FuncType::new([ValType::Ref(start_func_ref), ValType::I32], [ValType::I32]);
2324 let core_ty = SubType::func(func_ty, true);
2325 let id = types.intern_sub_type(core_ty, offset);
2326 self.core_funcs.push(id);
2327
2328 Ok(())
2329 }
2330
2331 fn thread_spawn_indirect(
2332 &mut self,
2333 func_ty_index: u32,
2334 table_index: u32,
2335 types: &mut TypeAlloc,
2336 offset: usize,
2337 ) -> Result<()> {
2338 if !self.features.shared_everything_threads() {
2339 bail!(
2340 offset,
2341 "`thread.spawn_indirect` requires the shared-everything-threads proposal"
2342 )
2343 }
2344 let _ = self.validate_spawn_type(func_ty_index, types, offset)?;
2345
2346 let table = self.table_at(table_index, offset)?;
2352
2353 SubtypeCx::table_type(
2354 table,
2355 &TableType {
2356 initial: 0,
2357 maximum: None,
2358 table64: false,
2359 shared: true,
2360 element_type: RefType::FUNCREF
2361 .shared()
2362 .expect("a funcref can always be shared"),
2363 },
2364 offset,
2365 )
2366 .map_err(|mut e| {
2367 e.add_context("table is not a 32-bit shared table of (ref null (shared func))".into());
2368 e
2369 })?;
2370
2371 let func_ty = FuncType::new([ValType::I32, ValType::I32], [ValType::I32]);
2373 let core_ty = SubType::func(func_ty, true);
2374 let id = types.intern_sub_type(core_ty, offset);
2375 self.core_funcs.push(id);
2376
2377 Ok(())
2378 }
2379
2380 fn validate_spawn_type(
2387 &self,
2388 func_ty_index: u32,
2389 types: &TypeAlloc,
2390 offset: usize,
2391 ) -> Result<CoreTypeId> {
2392 let core_type_id = match self.core_type_at(func_ty_index, offset)? {
2393 ComponentCoreTypeId::Sub(c) => c,
2394 ComponentCoreTypeId::Module(_) => bail!(offset, "expected a core function type"),
2395 };
2396 let sub_ty = &types[core_type_id];
2397 if !sub_ty.composite_type.shared {
2398 bail!(offset, "spawn type must be shared");
2399 }
2400 match &sub_ty.composite_type.inner {
2401 CompositeInnerType::Func(func_ty) => {
2402 if func_ty.params() != [ValType::I32] {
2403 bail!(
2404 offset,
2405 "spawn function must take a single `i32` argument (currently)"
2406 );
2407 }
2408 if func_ty.results() != [] {
2409 bail!(offset, "spawn function must not return any values");
2410 }
2411 }
2412 _ => bail!(offset, "spawn type must be a function"),
2413 }
2414 Ok(core_type_id)
2415 }
2416
2417 fn thread_available_parallelism(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
2418 if !self.features.shared_everything_threads() {
2419 bail!(
2420 offset,
2421 "`thread.available_parallelism` requires the shared-everything-threads proposal"
2422 )
2423 }
2424
2425 let func_ty = FuncType::new([], [ValType::I32]);
2426 let core_ty = SubType::func(func_ty, true);
2427 let id = types.intern_sub_type(core_ty, offset);
2428 self.core_funcs.push(id);
2429
2430 Ok(())
2431 }
2432
2433 pub fn add_component(&mut self, component: ComponentType, types: &mut TypeAlloc) -> Result<()> {
2434 let id = types.push_ty(component);
2435 self.components.push(id);
2436 Ok(())
2437 }
2438
2439 pub fn add_instance(
2440 &mut self,
2441 instance: crate::ComponentInstance,
2442 types: &mut TypeAlloc,
2443 offset: usize,
2444 ) -> Result<()> {
2445 let instance = match instance {
2446 crate::ComponentInstance::Instantiate {
2447 component_index,
2448 args,
2449 } => self.instantiate_component(component_index, args.into_vec(), types, offset)?,
2450 crate::ComponentInstance::FromExports(exports) => {
2451 self.instantiate_component_exports(exports.into_vec(), types, offset)?
2452 }
2453 };
2454
2455 self.instances.push(instance);
2456
2457 Ok(())
2458 }
2459
2460 pub fn add_alias(
2461 components: &mut [Self],
2462 alias: crate::ComponentAlias,
2463 types: &mut TypeAlloc,
2464 offset: usize,
2465 ) -> Result<()> {
2466 match alias {
2467 crate::ComponentAlias::InstanceExport {
2468 instance_index,
2469 kind,
2470 name,
2471 } => components.last_mut().unwrap().alias_instance_export(
2472 instance_index,
2473 kind,
2474 name,
2475 types,
2476 offset,
2477 ),
2478 crate::ComponentAlias::CoreInstanceExport {
2479 instance_index,
2480 kind,
2481 name,
2482 } => components.last_mut().unwrap().alias_core_instance_export(
2483 instance_index,
2484 kind,
2485 name,
2486 types,
2487 offset,
2488 ),
2489 crate::ComponentAlias::Outer { kind, count, index } => match kind {
2490 ComponentOuterAliasKind::CoreModule => {
2491 Self::alias_module(components, count, index, offset)
2492 }
2493 ComponentOuterAliasKind::CoreType => {
2494 Self::alias_core_type(components, count, index, offset)
2495 }
2496 ComponentOuterAliasKind::Type => {
2497 Self::alias_type(components, count, index, types, offset)
2498 }
2499 ComponentOuterAliasKind::Component => {
2500 Self::alias_component(components, count, index, offset)
2501 }
2502 },
2503 }
2504 }
2505
2506 pub fn add_start(
2507 &mut self,
2508 func_index: u32,
2509 args: &[u32],
2510 results: u32,
2511 types: &mut TypeList,
2512 offset: usize,
2513 ) -> Result<()> {
2514 if !self.features.cm_values() {
2515 bail!(
2516 offset,
2517 "support for component model `value`s is not enabled"
2518 );
2519 }
2520 if self.has_start {
2521 return Err(BinaryReaderError::new(
2522 "component cannot have more than one start function",
2523 offset,
2524 ));
2525 }
2526
2527 let ft = &types[self.function_at(func_index, offset)?];
2528
2529 if ft.params.len() != args.len() {
2530 bail!(
2531 offset,
2532 "component start function requires {} arguments but was given {}",
2533 ft.params.len(),
2534 args.len()
2535 );
2536 }
2537
2538 if u32::from(ft.result.is_some()) != results {
2539 bail!(
2540 offset,
2541 "component start function has a result count of {results} \
2542 but the function type has a result count of {type_results}",
2543 type_results = u32::from(ft.result.is_some()),
2544 );
2545 }
2546
2547 let cx = SubtypeCx::new(types, types);
2548 for (i, ((_, ty), arg)) in ft.params.iter().zip(args).enumerate() {
2549 cx.component_val_type(self.value_at(*arg, offset)?, ty, offset)
2551 .with_context(|| {
2552 format!("value type mismatch for component start function argument {i}")
2553 })?;
2554 }
2555
2556 if let Some(ty) = ft.result {
2557 self.values.push((ty, false));
2558 }
2559
2560 self.has_start = true;
2561
2562 Ok(())
2563 }
2564
2565 fn check_options(
2566 &self,
2567 types: &TypeList,
2568 options: &[CanonicalOption],
2569 offset: usize,
2570 ) -> Result<CanonicalOptions> {
2571 fn display(option: CanonicalOption) -> &'static str {
2572 match option {
2573 CanonicalOption::UTF8 => "utf8",
2574 CanonicalOption::UTF16 => "utf16",
2575 CanonicalOption::CompactUTF16 => "latin1-utf16",
2576 CanonicalOption::Memory(_) => "memory",
2577 CanonicalOption::Realloc(_) => "realloc",
2578 CanonicalOption::PostReturn(_) => "post-return",
2579 CanonicalOption::Async => "async",
2580 CanonicalOption::Callback(_) => "callback",
2581 CanonicalOption::CoreType(_) => "core-type",
2582 CanonicalOption::Gc => "gc",
2583 }
2584 }
2585
2586 let mut encoding = None;
2587 let mut memory = None;
2588 let mut realloc = None;
2589 let mut post_return = None;
2590 let mut is_async = false;
2591 let mut callback = None;
2592 let mut core_type = None;
2593 let mut gc = false;
2594
2595 for option in options {
2596 match option {
2597 CanonicalOption::UTF8 | CanonicalOption::UTF16 | CanonicalOption::CompactUTF16 => {
2598 match encoding {
2599 Some(existing) => {
2600 bail!(
2601 offset,
2602 "canonical encoding option `{existing}` conflicts with option `{}`",
2603 display(*option),
2604 )
2605 }
2606 None => {
2607 encoding = Some(match option {
2608 CanonicalOption::UTF8 => StringEncoding::Utf8,
2609 CanonicalOption::UTF16 => StringEncoding::Utf16,
2610 CanonicalOption::CompactUTF16 => StringEncoding::CompactUtf16,
2611 _ => unreachable!(),
2612 });
2613 }
2614 }
2615 }
2616 CanonicalOption::Memory(idx) => {
2617 memory = match memory {
2618 None => {
2619 self.cabi_memory_at(*idx, offset)?;
2620 Some(*idx)
2621 }
2622 Some(_) => {
2623 return Err(BinaryReaderError::new(
2624 "canonical option `memory` is specified more than once",
2625 offset,
2626 ));
2627 }
2628 }
2629 }
2630 CanonicalOption::Realloc(idx) => {
2631 realloc = match realloc {
2632 None => {
2633 let ty_id = self.core_function_at(*idx, offset)?;
2634 let func_ty = types[ty_id].unwrap_func();
2635 if func_ty.params()
2636 != [ValType::I32, ValType::I32, ValType::I32, ValType::I32]
2637 || func_ty.results() != [ValType::I32]
2638 {
2639 return Err(BinaryReaderError::new(
2640 "canonical option `realloc` uses a core function with an incorrect signature",
2641 offset,
2642 ));
2643 }
2644 Some(*idx)
2645 }
2646 Some(_) => {
2647 return Err(BinaryReaderError::new(
2648 "canonical option `realloc` is specified more than once",
2649 offset,
2650 ));
2651 }
2652 }
2653 }
2654 CanonicalOption::PostReturn(idx) => {
2655 post_return = match post_return {
2656 None => Some(*idx),
2657 Some(_) => {
2658 return Err(BinaryReaderError::new(
2659 "canonical option `post-return` is specified more than once",
2660 offset,
2661 ));
2662 }
2663 }
2664 }
2665 CanonicalOption::Async => {
2666 if is_async {
2667 return Err(BinaryReaderError::new(
2668 "canonical option `async` is specified more than once",
2669 offset,
2670 ));
2671 } else {
2672 if !self.features.cm_async() {
2673 bail!(
2674 offset,
2675 "canonical option `async` requires the component model async feature"
2676 );
2677 }
2678
2679 is_async = true;
2680 }
2681 }
2682 CanonicalOption::Callback(idx) => {
2683 callback = match callback {
2684 None => Some(*idx),
2685 Some(_) => {
2686 return Err(BinaryReaderError::new(
2687 "canonical option `callback` is specified more than once",
2688 offset,
2689 ));
2690 }
2691 }
2692 }
2693 CanonicalOption::CoreType(idx) => {
2694 core_type = match core_type {
2695 None => {
2696 if !self.features.cm_gc() {
2697 bail!(
2698 offset,
2699 "canonical option `core type` requires the component model gc feature"
2700 )
2701 }
2702 let ty = match self.core_type_at(*idx, offset)? {
2703 ComponentCoreTypeId::Sub(ty) => ty,
2704 ComponentCoreTypeId::Module(_) => {
2705 return Err(BinaryReaderError::new(
2706 "canonical option `core type` must reference a core function \
2707 type",
2708 offset,
2709 ));
2710 }
2711 };
2712 match &types[ty].composite_type.inner {
2713 CompositeInnerType::Func(_) => {}
2714 CompositeInnerType::Array(_)
2715 | CompositeInnerType::Struct(_)
2716 | CompositeInnerType::Cont(_) => {
2717 return Err(BinaryReaderError::new(
2718 "canonical option `core type` must reference a core function \
2719 type",
2720 offset,
2721 ));
2722 }
2723 }
2724 Some(ty)
2725 }
2726 Some(_) => {
2727 return Err(BinaryReaderError::new(
2728 "canonical option `core type` is specified more than once",
2729 offset,
2730 ));
2731 }
2732 };
2733 }
2734 CanonicalOption::Gc => {
2735 if gc {
2736 return Err(BinaryReaderError::new(
2737 "canonical option `gc` is specified more than once",
2738 offset,
2739 ));
2740 }
2741 if !self.features.cm_gc() {
2742 return Err(BinaryReaderError::new(
2743 "canonical option `gc` requires the `cm-gc` feature",
2744 offset,
2745 ));
2746 }
2747 gc = true;
2748 }
2749 }
2750 }
2751
2752 let string_encoding = encoding.unwrap_or_default();
2753
2754 let concurrency = match (is_async, callback, post_return.is_some()) {
2755 (false, Some(_), _) => {
2756 bail!(offset, "cannot specify callback without async")
2757 }
2758 (true, _, true) => {
2759 bail!(offset, "cannot specify post-return function in async")
2760 }
2761 (false, None, _) => Concurrency::Sync,
2762 (true, callback, false) => Concurrency::Async { callback },
2763 };
2764
2765 if !gc && core_type.is_some() {
2766 bail!(offset, "cannot specify `core-type` without `gc`")
2767 }
2768
2769 Ok(CanonicalOptions {
2770 string_encoding,
2771 memory,
2772 realloc,
2773 post_return,
2774 concurrency,
2775 core_type,
2776 gc,
2777 })
2778 }
2779
2780 fn check_type_ref(
2781 &mut self,
2782 ty: &ComponentTypeRef,
2783 types: &mut TypeAlloc,
2784 offset: usize,
2785 ) -> Result<ComponentEntityType> {
2786 Ok(match ty {
2787 ComponentTypeRef::Module(index) => {
2788 let id = self.core_type_at(*index, offset)?;
2789 match id {
2790 ComponentCoreTypeId::Sub(_) => {
2791 bail!(offset, "core type index {index} is not a module type")
2792 }
2793 ComponentCoreTypeId::Module(id) => ComponentEntityType::Module(id),
2794 }
2795 }
2796 ComponentTypeRef::Func(index) => {
2797 let id = self.component_type_at(*index, offset)?;
2798 match id {
2799 ComponentAnyTypeId::Func(id) => ComponentEntityType::Func(id),
2800 _ => bail!(offset, "type index {index} is not a function type"),
2801 }
2802 }
2803 ComponentTypeRef::Value(ty) => {
2804 self.check_value_support(offset)?;
2805 let ty = match ty {
2806 crate::ComponentValType::Primitive(ty) => ComponentValType::Primitive(*ty),
2807 crate::ComponentValType::Type(index) => {
2808 ComponentValType::Type(self.defined_type_at(*index, offset)?)
2809 }
2810 };
2811 ComponentEntityType::Value(ty)
2812 }
2813 ComponentTypeRef::Type(TypeBounds::Eq(index)) => {
2814 let referenced = self.component_type_at(*index, offset)?;
2815 let created = types.with_unique(referenced);
2816 ComponentEntityType::Type {
2817 referenced,
2818 created,
2819 }
2820 }
2821 ComponentTypeRef::Type(TypeBounds::SubResource) => {
2822 let id = types.alloc_resource_id();
2823 ComponentEntityType::Type {
2824 referenced: id.into(),
2825 created: id.into(),
2826 }
2827 }
2828 ComponentTypeRef::Instance(index) => {
2829 let id = self.component_type_at(*index, offset)?;
2830 match id {
2831 ComponentAnyTypeId::Instance(id) => ComponentEntityType::Instance(id),
2832 _ => bail!(offset, "type index {index} is not an instance type"),
2833 }
2834 }
2835 ComponentTypeRef::Component(index) => {
2836 let id = self.component_type_at(*index, offset)?;
2837 match id {
2838 ComponentAnyTypeId::Component(id) => ComponentEntityType::Component(id),
2839 _ => bail!(offset, "type index {index} is not a component type"),
2840 }
2841 }
2842 })
2843 }
2844
2845 pub fn export_to_entity_type(
2846 &mut self,
2847 export: &crate::ComponentExport,
2848 types: &mut TypeAlloc,
2849 offset: usize,
2850 ) -> Result<ComponentEntityType> {
2851 let actual = match export.kind {
2852 ComponentExternalKind::Module => {
2853 ComponentEntityType::Module(self.module_at(export.index, offset)?)
2854 }
2855 ComponentExternalKind::Func => {
2856 ComponentEntityType::Func(self.function_at(export.index, offset)?)
2857 }
2858 ComponentExternalKind::Value => {
2859 self.check_value_support(offset)?;
2860 ComponentEntityType::Value(*self.value_at(export.index, offset)?)
2861 }
2862 ComponentExternalKind::Type => {
2863 let referenced = self.component_type_at(export.index, offset)?;
2864 let created = types.with_unique(referenced);
2865 ComponentEntityType::Type {
2866 referenced,
2867 created,
2868 }
2869 }
2870 ComponentExternalKind::Instance => {
2871 ComponentEntityType::Instance(self.instance_at(export.index, offset)?)
2872 }
2873 ComponentExternalKind::Component => {
2874 ComponentEntityType::Component(self.component_at(export.index, offset)?)
2875 }
2876 };
2877
2878 let ascribed = match &export.ty {
2879 Some(ty) => self.check_type_ref(ty, types, offset)?,
2880 None => return Ok(actual),
2881 };
2882
2883 SubtypeCx::new(types, types)
2884 .component_entity_type(&actual, &ascribed, offset)
2885 .with_context(|| "ascribed type of export is not compatible with item's type")?;
2886
2887 Ok(ascribed)
2888 }
2889
2890 fn create_module_type(
2891 components: &[Self],
2892 decls: Vec<crate::ModuleTypeDeclaration>,
2893 types: &mut TypeAlloc,
2894 offset: usize,
2895 ) -> Result<ModuleType> {
2896 let mut state = Module::new(components[0].features);
2897
2898 for decl in decls {
2899 match decl {
2900 crate::ModuleTypeDeclaration::Type(rec) => {
2901 state.add_types(rec, types, offset, true)?;
2902 }
2903 crate::ModuleTypeDeclaration::Export { name, mut ty } => {
2904 let ty = state.check_type_ref(&mut ty, types, offset)?;
2905 state.add_export(name, ty, offset, true, types)?;
2906 }
2907 crate::ModuleTypeDeclaration::OuterAlias { kind, count, index } => {
2908 match kind {
2909 crate::OuterAliasKind::Type => {
2910 let ty = if count == 0 {
2911 ComponentCoreTypeId::Sub(state.type_id_at(index, offset)?)
2913 } else {
2914 let component =
2916 Self::check_alias_count(components, count - 1, offset)?;
2917 component.core_type_at(index, offset)?
2918 };
2919
2920 check_max(state.types.len(), 1, MAX_WASM_TYPES, "types", offset)?;
2921
2922 match ty {
2923 ComponentCoreTypeId::Sub(ty) => state.types.push(ty),
2924 ComponentCoreTypeId::Module(_) => bail!(
2926 offset,
2927 "not implemented: aliasing core module types into a core \
2928 module's types index space"
2929 ),
2930 }
2931 }
2932 }
2933 }
2934 crate::ModuleTypeDeclaration::Import(import) => {
2935 state.add_import(import, types, offset)?;
2936 }
2937 }
2938 }
2939
2940 let imports = state.imports_for_module_type(offset)?;
2941
2942 Ok(ModuleType {
2943 info: TypeInfo::core(state.type_size),
2944 imports,
2945 exports: state.exports,
2946 })
2947 }
2948
2949 fn create_component_type(
2950 components: &mut Vec<Self>,
2951 decls: Vec<crate::ComponentTypeDeclaration>,
2952 types: &mut TypeAlloc,
2953 offset: usize,
2954 ) -> Result<ComponentType> {
2955 let features = components[0].features;
2956 components.push(ComponentState::new(ComponentKind::ComponentType, features));
2957
2958 for decl in decls {
2959 match decl {
2960 crate::ComponentTypeDeclaration::CoreType(ty) => {
2961 Self::add_core_type(components, ty, types, offset, true)?;
2962 }
2963 crate::ComponentTypeDeclaration::Type(ty) => {
2964 Self::add_type(components, ty, types, offset, true)?;
2965 }
2966 crate::ComponentTypeDeclaration::Export { name, ty } => {
2967 let current = components.last_mut().unwrap();
2968 let ty = current.check_type_ref(&ty, types, offset)?;
2969 current.add_export(name, ty, types, offset, true)?;
2970 }
2971 crate::ComponentTypeDeclaration::Import(import) => {
2972 components
2973 .last_mut()
2974 .unwrap()
2975 .add_import(import, types, offset)?;
2976 }
2977 crate::ComponentTypeDeclaration::Alias(alias) => {
2978 Self::add_alias(components, alias, types, offset)?;
2979 }
2980 };
2981 }
2982
2983 components.pop().unwrap().finish(types, offset)
2984 }
2985
2986 fn create_instance_type(
2987 components: &mut Vec<Self>,
2988 decls: Vec<crate::InstanceTypeDeclaration>,
2989 types: &mut TypeAlloc,
2990 offset: usize,
2991 ) -> Result<ComponentInstanceType> {
2992 let features = components[0].features;
2993 components.push(ComponentState::new(ComponentKind::InstanceType, features));
2994
2995 for decl in decls {
2996 match decl {
2997 crate::InstanceTypeDeclaration::CoreType(ty) => {
2998 Self::add_core_type(components, ty, types, offset, true)?;
2999 }
3000 crate::InstanceTypeDeclaration::Type(ty) => {
3001 Self::add_type(components, ty, types, offset, true)?;
3002 }
3003 crate::InstanceTypeDeclaration::Export { name, ty } => {
3004 let current = components.last_mut().unwrap();
3005 let ty = current.check_type_ref(&ty, types, offset)?;
3006 current.add_export(name, ty, types, offset, true)?;
3007 }
3008 crate::InstanceTypeDeclaration::Alias(alias) => {
3009 Self::add_alias(components, alias, types, offset)?;
3010 }
3011 };
3012 }
3013
3014 let mut state = components.pop().unwrap();
3015
3016 assert!(state.imported_resources.is_empty());
3017
3018 Ok(ComponentInstanceType {
3019 info: state.type_info,
3020
3021 defined_resources: mem::take(&mut state.defined_resources)
3031 .into_iter()
3032 .map(|(id, rep)| {
3033 assert!(rep.is_none());
3034 id
3035 })
3036 .collect(),
3037
3038 explicit_resources: mem::take(&mut state.explicit_resources),
3041
3042 exports: mem::take(&mut state.exports),
3043 })
3044 }
3045
3046 fn create_function_type(
3047 &self,
3048 ty: crate::ComponentFuncType,
3049 types: &TypeList,
3050 offset: usize,
3051 ) -> Result<ComponentFuncType> {
3052 let mut info = TypeInfo::new();
3053
3054 let mut set = Set::default();
3055 set.reserve(core::cmp::max(
3056 ty.params.len(),
3057 usize::from(ty.result.is_some()),
3058 ));
3059
3060 let params = ty
3061 .params
3062 .iter()
3063 .map(|(name, ty)| {
3064 let name: &KebabStr = to_kebab_str(name, "function parameter", offset)?;
3065 if !set.insert(name) {
3066 bail!(
3067 offset,
3068 "function parameter name `{name}` conflicts with previous parameter name `{prev}`",
3069 prev = set.get(&name).unwrap(),
3070 );
3071 }
3072
3073 let ty = self.create_component_val_type(*ty, offset)?;
3074 info.combine(ty.info(types), offset)?;
3075 Ok((name.to_owned(), ty))
3076 })
3077 .collect::<Result<_>>()?;
3078
3079 set.clear();
3080
3081 let result = ty
3082 .result
3083 .map(|ty| {
3084 let ty = self.create_component_val_type(ty, offset)?;
3085 let ty_info = ty.info(types);
3086 if ty_info.contains_borrow() {
3087 bail!(offset, "function result cannot contain a `borrow` type");
3088 }
3089 info.combine(ty.info(types), offset)?;
3090 Ok(ty)
3091 })
3092 .transpose()?;
3093
3094 Ok(ComponentFuncType {
3095 info,
3096 params,
3097 result,
3098 })
3099 }
3100
3101 fn instantiate_core_module(
3102 &self,
3103 module_index: u32,
3104 module_args: Vec<crate::InstantiationArg>,
3105 types: &mut TypeAlloc,
3106 offset: usize,
3107 ) -> Result<ComponentCoreInstanceTypeId> {
3108 fn insert_arg<'a>(
3109 name: &'a str,
3110 arg: &'a InstanceType,
3111 args: &mut IndexMap<&'a str, &'a InstanceType>,
3112 offset: usize,
3113 ) -> Result<()> {
3114 if args.insert(name, arg).is_some() {
3115 bail!(
3116 offset,
3117 "duplicate module instantiation argument named `{name}`"
3118 );
3119 }
3120
3121 Ok(())
3122 }
3123
3124 let module_type_id = self.module_at(module_index, offset)?;
3125 let mut args = IndexMap::default();
3126
3127 for module_arg in module_args {
3129 match module_arg.kind {
3130 InstantiationArgKind::Instance => {
3131 let instance_type = &types[self.core_instance_at(module_arg.index, offset)?];
3132 insert_arg(module_arg.name, instance_type, &mut args, offset)?;
3133 }
3134 }
3135 }
3136
3137 let module_type = &types[module_type_id];
3139 let cx = SubtypeCx::new(types, types);
3140 for ((module, name), expected) in module_type.imports.iter() {
3141 let instance = args.get(module.as_str()).ok_or_else(|| {
3142 format_err!(
3143 offset,
3144 "missing module instantiation argument named `{module}`"
3145 )
3146 })?;
3147
3148 let arg = instance
3149 .internal_exports(types)
3150 .get(name.as_str())
3151 .ok_or_else(|| {
3152 format_err!(
3153 offset,
3154 "module instantiation argument `{module}` does not \
3155 export an item named `{name}`",
3156 )
3157 })?;
3158
3159 cx.entity_type(arg, expected, offset).with_context(|| {
3160 format!(
3161 "type mismatch for export `{name}` of module \
3162 instantiation argument `{module}`"
3163 )
3164 })?;
3165 }
3166
3167 let mut info = TypeInfo::new();
3168 for (_, ty) in module_type.exports.iter() {
3169 info.combine(ty.info(types), offset)?;
3170 }
3171
3172 Ok(types.push_ty(InstanceType {
3173 info,
3174 kind: CoreInstanceTypeKind::Instantiated(module_type_id),
3175 }))
3176 }
3177
3178 fn instantiate_component(
3179 &mut self,
3180 component_index: u32,
3181 component_args: Vec<crate::ComponentInstantiationArg>,
3182 types: &mut TypeAlloc,
3183 offset: usize,
3184 ) -> Result<ComponentInstanceTypeId> {
3185 let component_type_id = self.component_at(component_index, offset)?;
3186 let mut args = IndexMap::default();
3187
3188 for component_arg in component_args {
3190 let ty = match component_arg.kind {
3191 ComponentExternalKind::Module => {
3192 ComponentEntityType::Module(self.module_at(component_arg.index, offset)?)
3193 }
3194 ComponentExternalKind::Component => {
3195 ComponentEntityType::Component(self.component_at(component_arg.index, offset)?)
3196 }
3197 ComponentExternalKind::Instance => {
3198 ComponentEntityType::Instance(self.instance_at(component_arg.index, offset)?)
3199 }
3200 ComponentExternalKind::Func => {
3201 ComponentEntityType::Func(self.function_at(component_arg.index, offset)?)
3202 }
3203 ComponentExternalKind::Value => {
3204 self.check_value_support(offset)?;
3205 ComponentEntityType::Value(*self.value_at(component_arg.index, offset)?)
3206 }
3207 ComponentExternalKind::Type => {
3208 let ty = self.component_type_at(component_arg.index, offset)?;
3209 ComponentEntityType::Type {
3210 referenced: ty,
3211 created: ty,
3212 }
3213 }
3214 };
3215 match args.entry(component_arg.name.to_string()) {
3216 Entry::Occupied(e) => {
3217 bail!(
3218 offset,
3219 "instantiation argument `{name}` conflicts with previous argument `{prev}`",
3220 prev = e.key(),
3221 name = component_arg.name
3222 );
3223 }
3224 Entry::Vacant(e) => {
3225 e.insert(ty);
3226 }
3227 }
3228 }
3229
3230 let component_type = &types[component_type_id];
3310 let mut exports = component_type.exports.clone();
3311 let mut info = TypeInfo::new();
3312 for (_, ty) in component_type.exports.iter() {
3313 info.combine(ty.info(types), offset)?;
3314 }
3315
3316 let mut mapping = SubtypeCx::new(types, types).open_instance_type(
3324 &args,
3325 component_type_id,
3326 ExternKind::Import,
3327 offset,
3328 )?;
3329
3330 let fresh_defined_resources = (0..component_type.defined_resources.len())
3352 .map(|_| types.alloc_resource_id().resource())
3353 .collect::<IndexSet<_>>();
3354 let component_type = &types[component_type_id];
3355 for ((old, _path), new) in component_type
3356 .defined_resources
3357 .iter()
3358 .zip(&fresh_defined_resources)
3359 {
3360 let prev = mapping.resources.insert(*old, *new);
3361 assert!(prev.is_none());
3362 }
3363
3364 for entity in exports.values_mut() {
3375 types.remap_component_entity(entity, &mut mapping);
3376 }
3377 let component_type = &types[component_type_id];
3378 let explicit_resources = component_type
3379 .explicit_resources
3380 .iter()
3381 .map(|(id, path)| {
3382 (
3383 mapping.resources.get(id).copied().unwrap_or(*id),
3384 path.clone(),
3385 )
3386 })
3387 .collect::<IndexMap<_, _>>();
3388
3389 if cfg!(debug_assertions) {
3409 let mut free = IndexSet::default();
3410 for ty in exports.values() {
3411 types.free_variables_component_entity(ty, &mut free);
3412 }
3413 assert!(fresh_defined_resources.is_subset(&free));
3414 for resource in fresh_defined_resources.iter() {
3415 assert!(explicit_resources.contains_key(resource));
3416 }
3417 }
3418
3419 for resource in fresh_defined_resources {
3435 self.defined_resources.insert(resource, None);
3436 }
3437
3438 Ok(types.push_ty(ComponentInstanceType {
3439 info,
3440 defined_resources: Default::default(),
3441 explicit_resources,
3442 exports,
3443 }))
3444 }
3445
3446 fn instantiate_component_exports(
3447 &mut self,
3448 exports: Vec<crate::ComponentExport>,
3449 types: &mut TypeAlloc,
3450 offset: usize,
3451 ) -> Result<ComponentInstanceTypeId> {
3452 let mut info = TypeInfo::new();
3453 let mut inst_exports = IndexMap::default();
3454 let mut explicit_resources = IndexMap::default();
3455 let mut export_names = IndexSet::default();
3456
3457 let names = ComponentNameContext::default();
3461
3462 for export in exports {
3463 assert!(export.ty.is_none());
3464 let ty = match export.kind {
3465 ComponentExternalKind::Module => {
3466 ComponentEntityType::Module(self.module_at(export.index, offset)?)
3467 }
3468 ComponentExternalKind::Component => {
3469 ComponentEntityType::Component(self.component_at(export.index, offset)?)
3470 }
3471 ComponentExternalKind::Instance => {
3472 let ty = self.instance_at(export.index, offset)?;
3473
3474 explicit_resources.extend(types[ty].explicit_resources.iter().map(
3479 |(id, path)| {
3480 let mut new_path = vec![inst_exports.len()];
3481 new_path.extend(path);
3482 (*id, new_path)
3483 },
3484 ));
3485 ComponentEntityType::Instance(ty)
3486 }
3487 ComponentExternalKind::Func => {
3488 ComponentEntityType::Func(self.function_at(export.index, offset)?)
3489 }
3490 ComponentExternalKind::Value => {
3491 self.check_value_support(offset)?;
3492 ComponentEntityType::Value(*self.value_at(export.index, offset)?)
3493 }
3494 ComponentExternalKind::Type => {
3495 let ty = self.component_type_at(export.index, offset)?;
3496 if let ComponentAnyTypeId::Resource(id) = ty {
3501 explicit_resources.insert(id.resource(), vec![inst_exports.len()]);
3502 }
3503 ComponentEntityType::Type {
3504 referenced: ty,
3505 created: ty,
3511 }
3512 }
3513 };
3514
3515 names.validate_extern(
3516 export.name.0,
3517 ExternKind::Export,
3518 &ty,
3519 types,
3520 offset,
3521 &mut export_names,
3522 &mut inst_exports,
3523 &mut info,
3524 &self.features,
3525 )?;
3526 }
3527
3528 Ok(types.push_ty(ComponentInstanceType {
3529 info,
3530 explicit_resources,
3531 exports: inst_exports,
3532
3533 defined_resources: Default::default(),
3562 }))
3563 }
3564
3565 fn instantiate_core_exports(
3566 &mut self,
3567 exports: Vec<crate::Export>,
3568 types: &mut TypeAlloc,
3569 offset: usize,
3570 ) -> Result<ComponentCoreInstanceTypeId> {
3571 fn insert_export(
3572 types: &TypeList,
3573 name: &str,
3574 export: EntityType,
3575 exports: &mut IndexMap<String, EntityType>,
3576 info: &mut TypeInfo,
3577 offset: usize,
3578 ) -> Result<()> {
3579 info.combine(export.info(types), offset)?;
3580
3581 if exports.insert(name.to_string(), export).is_some() {
3582 bail!(
3583 offset,
3584 "duplicate instantiation export name `{name}` already defined",
3585 )
3586 }
3587
3588 Ok(())
3589 }
3590
3591 let mut info = TypeInfo::new();
3592 let mut inst_exports = IndexMap::default();
3593 for export in exports {
3594 match export.kind {
3595 ExternalKind::Func => {
3596 insert_export(
3597 types,
3598 export.name,
3599 EntityType::Func(self.core_function_at(export.index, offset)?),
3600 &mut inst_exports,
3601 &mut info,
3602 offset,
3603 )?;
3604 }
3605 ExternalKind::Table => insert_export(
3606 types,
3607 export.name,
3608 EntityType::Table(*self.table_at(export.index, offset)?),
3609 &mut inst_exports,
3610 &mut info,
3611 offset,
3612 )?,
3613 ExternalKind::Memory => insert_export(
3614 types,
3615 export.name,
3616 EntityType::Memory(*self.memory_at(export.index, offset)?),
3617 &mut inst_exports,
3618 &mut info,
3619 offset,
3620 )?,
3621 ExternalKind::Global => {
3622 insert_export(
3623 types,
3624 export.name,
3625 EntityType::Global(*self.global_at(export.index, offset)?),
3626 &mut inst_exports,
3627 &mut info,
3628 offset,
3629 )?;
3630 }
3631 ExternalKind::Tag => {
3632 if !self.features.exceptions() {
3633 bail!(offset, "exceptions proposal not enabled");
3634 }
3635 insert_export(
3636 types,
3637 export.name,
3638 EntityType::Tag(self.tag_at(export.index, offset)?),
3639 &mut inst_exports,
3640 &mut info,
3641 offset,
3642 )?
3643 }
3644 }
3645 }
3646
3647 Ok(types.push_ty(InstanceType {
3648 info,
3649 kind: CoreInstanceTypeKind::Exports(inst_exports),
3650 }))
3651 }
3652
3653 fn alias_core_instance_export(
3654 &mut self,
3655 instance_index: u32,
3656 kind: ExternalKind,
3657 name: &str,
3658 types: &TypeList,
3659 offset: usize,
3660 ) -> Result<()> {
3661 macro_rules! push_module_export {
3662 ($expected:path, $collection:ident, $ty:literal) => {{
3663 match self.core_instance_export(instance_index, name, types, offset)? {
3664 $expected(ty) => {
3665 self.$collection.push(*ty);
3666 }
3667 _ => {
3668 bail!(
3669 offset,
3670 "export `{name}` for core instance {instance_index} is not a {}",
3671 $ty
3672 )
3673 }
3674 }
3675 }};
3676 }
3677
3678 match kind {
3679 ExternalKind::Func => {
3680 check_max(
3681 self.function_count(),
3682 1,
3683 MAX_WASM_FUNCTIONS,
3684 "functions",
3685 offset,
3686 )?;
3687 push_module_export!(EntityType::Func, core_funcs, "function");
3688 }
3689 ExternalKind::Table => {
3690 check_max(
3691 self.core_tables.len(),
3692 1,
3693 MAX_CORE_INDEX_SPACE_ITEMS,
3694 "tables",
3695 offset,
3696 )?;
3697 push_module_export!(EntityType::Table, core_tables, "table");
3698 }
3699 ExternalKind::Memory => {
3700 check_max(
3701 self.core_memories.len(),
3702 1,
3703 MAX_CORE_INDEX_SPACE_ITEMS,
3704 "memories",
3705 offset,
3706 )?;
3707 push_module_export!(EntityType::Memory, core_memories, "memory");
3708 }
3709 ExternalKind::Global => {
3710 check_max(
3711 self.core_globals.len(),
3712 1,
3713 MAX_CORE_INDEX_SPACE_ITEMS,
3714 "globals",
3715 offset,
3716 )?;
3717 push_module_export!(EntityType::Global, core_globals, "global");
3718 }
3719 ExternalKind::Tag => {
3720 if !self.features.exceptions() {
3721 bail!(offset, "exceptions proposal not enabled");
3722 }
3723 check_max(
3724 self.core_tags.len(),
3725 1,
3726 MAX_CORE_INDEX_SPACE_ITEMS,
3727 "tags",
3728 offset,
3729 )?;
3730 push_module_export!(EntityType::Tag, core_tags, "tag");
3731 }
3732 }
3733
3734 Ok(())
3735 }
3736
3737 fn alias_instance_export(
3738 &mut self,
3739 instance_index: u32,
3740 kind: ComponentExternalKind,
3741 name: &str,
3742 types: &mut TypeAlloc,
3743 offset: usize,
3744 ) -> Result<()> {
3745 if let ComponentExternalKind::Value = kind {
3746 self.check_value_support(offset)?;
3747 }
3748 let mut ty = match types[self.instance_at(instance_index, offset)?]
3749 .exports
3750 .get(name)
3751 {
3752 Some(ty) => *ty,
3753 None => bail!(
3754 offset,
3755 "instance {instance_index} has no export named `{name}`"
3756 ),
3757 };
3758
3759 let ok = match (&ty, kind) {
3760 (ComponentEntityType::Module(_), ComponentExternalKind::Module) => true,
3761 (ComponentEntityType::Module(_), _) => false,
3762 (ComponentEntityType::Component(_), ComponentExternalKind::Component) => true,
3763 (ComponentEntityType::Component(_), _) => false,
3764 (ComponentEntityType::Func(_), ComponentExternalKind::Func) => true,
3765 (ComponentEntityType::Func(_), _) => false,
3766 (ComponentEntityType::Instance(_), ComponentExternalKind::Instance) => true,
3767 (ComponentEntityType::Instance(_), _) => false,
3768 (ComponentEntityType::Value(_), ComponentExternalKind::Value) => true,
3769 (ComponentEntityType::Value(_), _) => false,
3770 (ComponentEntityType::Type { .. }, ComponentExternalKind::Type) => true,
3771 (ComponentEntityType::Type { .. }, _) => false,
3772 };
3773 if !ok {
3774 bail!(
3775 offset,
3776 "export `{name}` for instance {instance_index} is not a {}",
3777 kind.desc(),
3778 );
3779 }
3780
3781 self.add_entity(&mut ty, None, types, offset)?;
3782 Ok(())
3783 }
3784
3785 fn alias_module(components: &mut [Self], count: u32, index: u32, offset: usize) -> Result<()> {
3786 let component = Self::check_alias_count(components, count, offset)?;
3787 let ty = component.module_at(index, offset)?;
3788
3789 let current = components.last_mut().unwrap();
3790 check_max(
3791 current.core_modules.len(),
3792 1,
3793 MAX_WASM_MODULES,
3794 "modules",
3795 offset,
3796 )?;
3797
3798 current.core_modules.push(ty);
3799 Ok(())
3800 }
3801
3802 fn alias_component(
3803 components: &mut [Self],
3804 count: u32,
3805 index: u32,
3806 offset: usize,
3807 ) -> Result<()> {
3808 let component = Self::check_alias_count(components, count, offset)?;
3809 let ty = component.component_at(index, offset)?;
3810
3811 let current = components.last_mut().unwrap();
3812 check_max(
3813 current.components.len(),
3814 1,
3815 MAX_WASM_COMPONENTS,
3816 "components",
3817 offset,
3818 )?;
3819
3820 current.components.push(ty);
3821 Ok(())
3822 }
3823
3824 fn alias_core_type(
3825 components: &mut [Self],
3826 count: u32,
3827 index: u32,
3828 offset: usize,
3829 ) -> Result<()> {
3830 let component = Self::check_alias_count(components, count, offset)?;
3831 let ty = component.core_type_at(index, offset)?;
3832
3833 let current = components.last_mut().unwrap();
3834 check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
3835
3836 current.core_types.push(ty);
3837
3838 Ok(())
3839 }
3840
3841 fn alias_type(
3842 components: &mut [Self],
3843 count: u32,
3844 index: u32,
3845 types: &mut TypeAlloc,
3846 offset: usize,
3847 ) -> Result<()> {
3848 let component = Self::check_alias_count(components, count, offset)?;
3849 let ty = component.component_type_at(index, offset)?;
3850
3851 let pos_after_component = components.len() - (count as usize);
3874 if let Some(component) = components.get(pos_after_component) {
3875 if component.kind == ComponentKind::Component {
3876 let mut free = IndexSet::default();
3877 types.free_variables_any_type_id(ty, &mut free);
3878 if !free.is_empty() {
3879 bail!(
3880 offset,
3881 "cannot alias outer type which transitively refers \
3882 to resources not defined in the current component"
3883 );
3884 }
3885 }
3886 }
3887
3888 let current = components.last_mut().unwrap();
3889 check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
3890
3891 current.types.push(ty);
3892
3893 Ok(())
3894 }
3895
3896 fn check_alias_count(components: &[Self], count: u32, offset: usize) -> Result<&Self> {
3897 let count = count as usize;
3898 if count >= components.len() {
3899 bail!(offset, "invalid outer alias count of {count}");
3900 }
3901
3902 Ok(&components[components.len() - count - 1])
3903 }
3904
3905 fn create_defined_type(
3906 &self,
3907 ty: crate::ComponentDefinedType,
3908 types: &TypeList,
3909 offset: usize,
3910 ) -> Result<ComponentDefinedType> {
3911 match ty {
3912 crate::ComponentDefinedType::Primitive(ty) => {
3913 if ty == crate::PrimitiveValType::ErrorContext && !self.features.cm_error_context()
3914 {
3915 bail!(
3916 offset,
3917 "`error-context` requires the component model error-context feature"
3918 )
3919 }
3920 Ok(ComponentDefinedType::Primitive(ty))
3921 }
3922 crate::ComponentDefinedType::Record(fields) => {
3923 self.create_record_type(fields.as_ref(), types, offset)
3924 }
3925 crate::ComponentDefinedType::Variant(cases) => {
3926 self.create_variant_type(cases.as_ref(), types, offset)
3927 }
3928 crate::ComponentDefinedType::List(ty) => Ok(ComponentDefinedType::List(
3929 self.create_component_val_type(ty, offset)?,
3930 )),
3931 crate::ComponentDefinedType::FixedSizeList(ty, elements) => {
3932 if !self.features.cm_fixed_size_list() {
3933 bail!(
3934 offset,
3935 "Fixed size lists require the component model fixed size list feature"
3936 )
3937 }
3938 if elements < 1 {
3939 bail!(offset, "Fixed size lists must have more than zero elements")
3940 }
3941 Ok(ComponentDefinedType::FixedSizeList(
3942 self.create_component_val_type(ty, offset)?,
3943 elements,
3944 ))
3945 }
3946 crate::ComponentDefinedType::Tuple(tys) => {
3947 self.create_tuple_type(tys.as_ref(), types, offset)
3948 }
3949 crate::ComponentDefinedType::Flags(names) => {
3950 self.create_flags_type(names.as_ref(), offset)
3951 }
3952 crate::ComponentDefinedType::Enum(cases) => {
3953 self.create_enum_type(cases.as_ref(), offset)
3954 }
3955 crate::ComponentDefinedType::Option(ty) => Ok(ComponentDefinedType::Option(
3956 self.create_component_val_type(ty, offset)?,
3957 )),
3958 crate::ComponentDefinedType::Result { ok, err } => Ok(ComponentDefinedType::Result {
3959 ok: ok
3960 .map(|ty| self.create_component_val_type(ty, offset))
3961 .transpose()?,
3962 err: err
3963 .map(|ty| self.create_component_val_type(ty, offset))
3964 .transpose()?,
3965 }),
3966 crate::ComponentDefinedType::Own(idx) => Ok(ComponentDefinedType::Own(
3967 self.resource_at(idx, types, offset)?,
3968 )),
3969 crate::ComponentDefinedType::Borrow(idx) => Ok(ComponentDefinedType::Borrow(
3970 self.resource_at(idx, types, offset)?,
3971 )),
3972 crate::ComponentDefinedType::Future(ty) => {
3973 if !self.features.cm_async() {
3974 bail!(
3975 offset,
3976 "`future` requires the component model async feature"
3977 )
3978 }
3979 Ok(ComponentDefinedType::Future(
3980 ty.map(|ty| self.create_component_val_type(ty, offset))
3981 .transpose()?,
3982 ))
3983 }
3984 crate::ComponentDefinedType::Stream(ty) => {
3985 if !self.features.cm_async() {
3986 bail!(
3987 offset,
3988 "`stream` requires the component model async feature"
3989 )
3990 }
3991 Ok(ComponentDefinedType::Stream(
3992 ty.map(|ty| self.create_component_val_type(ty, offset))
3993 .transpose()?,
3994 ))
3995 }
3996 }
3997 }
3998
3999 fn create_record_type(
4000 &self,
4001 fields: &[(&str, crate::ComponentValType)],
4002 types: &TypeList,
4003 offset: usize,
4004 ) -> Result<ComponentDefinedType> {
4005 let mut info = TypeInfo::new();
4006 let mut field_map = IndexMap::default();
4007 field_map.reserve(fields.len());
4008
4009 if fields.is_empty() {
4010 bail!(offset, "record type must have at least one field");
4011 }
4012
4013 for (name, ty) in fields {
4014 let name = to_kebab_str(name, "record field", offset)?;
4015 let ty = self.create_component_val_type(*ty, offset)?;
4016
4017 match field_map.entry(name.to_owned()) {
4018 Entry::Occupied(e) => bail!(
4019 offset,
4020 "record field name `{name}` conflicts with previous field name `{prev}`",
4021 prev = e.key()
4022 ),
4023 Entry::Vacant(e) => {
4024 info.combine(ty.info(types), offset)?;
4025 e.insert(ty);
4026 }
4027 }
4028 }
4029
4030 Ok(ComponentDefinedType::Record(RecordType {
4031 info,
4032 fields: field_map,
4033 }))
4034 }
4035
4036 fn create_variant_type(
4037 &self,
4038 cases: &[crate::VariantCase],
4039 types: &TypeList,
4040 offset: usize,
4041 ) -> Result<ComponentDefinedType> {
4042 let mut info = TypeInfo::new();
4043 let mut case_map: IndexMap<KebabString, VariantCase> = IndexMap::default();
4044 case_map.reserve(cases.len());
4045
4046 if cases.is_empty() {
4047 bail!(offset, "variant type must have at least one case");
4048 }
4049
4050 if cases.len() > u32::MAX as usize {
4051 return Err(BinaryReaderError::new(
4052 "variant type cannot be represented with a 32-bit discriminant value",
4053 offset,
4054 ));
4055 }
4056
4057 for (i, case) in cases.iter().enumerate() {
4058 if let Some(refines) = case.refines {
4059 if refines >= i as u32 {
4060 return Err(BinaryReaderError::new(
4061 "variant case can only refine a previously defined case",
4062 offset,
4063 ));
4064 }
4065 }
4066
4067 let name = to_kebab_str(case.name, "variant case", offset)?;
4068
4069 let ty = case
4070 .ty
4071 .map(|ty| self.create_component_val_type(ty, offset))
4072 .transpose()?;
4073
4074 match case_map.entry(name.to_owned()) {
4075 Entry::Occupied(e) => bail!(
4076 offset,
4077 "variant case name `{name}` conflicts with previous case name `{prev}`",
4078 name = case.name,
4079 prev = e.key()
4080 ),
4081 Entry::Vacant(e) => {
4082 if let Some(ty) = ty {
4083 info.combine(ty.info(types), offset)?;
4084 }
4085
4086 e.insert(VariantCase {
4089 ty,
4090 refines: case
4091 .refines
4092 .map(|i| KebabStr::new_unchecked(cases[i as usize].name).to_owned()),
4093 });
4094 }
4095 }
4096 }
4097
4098 Ok(ComponentDefinedType::Variant(VariantType {
4099 info,
4100 cases: case_map,
4101 }))
4102 }
4103
4104 fn create_tuple_type(
4105 &self,
4106 tys: &[crate::ComponentValType],
4107 types: &TypeList,
4108 offset: usize,
4109 ) -> Result<ComponentDefinedType> {
4110 let mut info = TypeInfo::new();
4111 if tys.is_empty() {
4112 bail!(offset, "tuple type must have at least one type");
4113 }
4114 let types = tys
4115 .iter()
4116 .map(|ty| {
4117 let ty = self.create_component_val_type(*ty, offset)?;
4118 info.combine(ty.info(types), offset)?;
4119 Ok(ty)
4120 })
4121 .collect::<Result<_>>()?;
4122
4123 Ok(ComponentDefinedType::Tuple(TupleType { info, types }))
4124 }
4125
4126 fn create_flags_type(&self, names: &[&str], offset: usize) -> Result<ComponentDefinedType> {
4127 let mut names_set = IndexSet::default();
4128 names_set.reserve(names.len());
4129
4130 if names.is_empty() {
4131 bail!(offset, "flags must have at least one entry");
4132 }
4133
4134 if names.len() > 32 {
4135 bail!(offset, "cannot have more than 32 flags");
4136 }
4137
4138 for name in names {
4139 let name = to_kebab_str(name, "flag", offset)?;
4140 if !names_set.insert(name.to_owned()) {
4141 bail!(
4142 offset,
4143 "flag name `{name}` conflicts with previous flag name `{prev}`",
4144 prev = names_set.get(name).unwrap()
4145 );
4146 }
4147 }
4148
4149 Ok(ComponentDefinedType::Flags(names_set))
4150 }
4151
4152 fn create_enum_type(&self, cases: &[&str], offset: usize) -> Result<ComponentDefinedType> {
4153 if cases.len() > u32::MAX as usize {
4154 return Err(BinaryReaderError::new(
4155 "enumeration type cannot be represented with a 32-bit discriminant value",
4156 offset,
4157 ));
4158 }
4159
4160 if cases.is_empty() {
4161 bail!(offset, "enum type must have at least one variant");
4162 }
4163
4164 let mut tags = IndexSet::default();
4165 tags.reserve(cases.len());
4166
4167 for tag in cases {
4168 let tag = to_kebab_str(tag, "enum tag", offset)?;
4169 if !tags.insert(tag.to_owned()) {
4170 bail!(
4171 offset,
4172 "enum tag name `{tag}` conflicts with previous tag name `{prev}`",
4173 prev = tags.get(tag).unwrap()
4174 );
4175 }
4176 }
4177
4178 Ok(ComponentDefinedType::Enum(tags))
4179 }
4180
4181 fn create_component_val_type(
4182 &self,
4183 ty: crate::ComponentValType,
4184 offset: usize,
4185 ) -> Result<ComponentValType> {
4186 Ok(match ty {
4187 crate::ComponentValType::Primitive(pt) => ComponentValType::Primitive(pt),
4188 crate::ComponentValType::Type(idx) => {
4189 ComponentValType::Type(self.defined_type_at(idx, offset)?)
4190 }
4191 })
4192 }
4193
4194 pub fn core_type_at(&self, idx: u32, offset: usize) -> Result<ComponentCoreTypeId> {
4195 self.core_types
4196 .get(idx as usize)
4197 .copied()
4198 .ok_or_else(|| format_err!(offset, "unknown type {idx}: type index out of bounds"))
4199 }
4200
4201 pub fn component_type_at(&self, idx: u32, offset: usize) -> Result<ComponentAnyTypeId> {
4202 self.types
4203 .get(idx as usize)
4204 .copied()
4205 .ok_or_else(|| format_err!(offset, "unknown type {idx}: type index out of bounds"))
4206 }
4207
4208 fn function_type_at<'a>(
4209 &self,
4210 idx: u32,
4211 types: &'a TypeList,
4212 offset: usize,
4213 ) -> Result<&'a ComponentFuncType> {
4214 let id = self.component_type_at(idx, offset)?;
4215 match id {
4216 ComponentAnyTypeId::Func(id) => Ok(&types[id]),
4217 _ => bail!(offset, "type index {idx} is not a function type"),
4218 }
4219 }
4220
4221 fn function_at(&self, idx: u32, offset: usize) -> Result<ComponentFuncTypeId> {
4222 self.funcs.get(idx as usize).copied().ok_or_else(|| {
4223 format_err!(
4224 offset,
4225 "unknown function {idx}: function index out of bounds"
4226 )
4227 })
4228 }
4229
4230 fn component_at(&self, idx: u32, offset: usize) -> Result<ComponentTypeId> {
4231 self.components.get(idx as usize).copied().ok_or_else(|| {
4232 format_err!(
4233 offset,
4234 "unknown component {idx}: component index out of bounds"
4235 )
4236 })
4237 }
4238
4239 fn instance_at(&self, idx: u32, offset: usize) -> Result<ComponentInstanceTypeId> {
4240 self.instances.get(idx as usize).copied().ok_or_else(|| {
4241 format_err!(
4242 offset,
4243 "unknown instance {idx}: instance index out of bounds"
4244 )
4245 })
4246 }
4247
4248 fn value_at(&mut self, idx: u32, offset: usize) -> Result<&ComponentValType> {
4249 match self.values.get_mut(idx as usize) {
4250 Some((ty, used)) if !*used => {
4251 *used = true;
4252 Ok(ty)
4253 }
4254 Some(_) => bail!(offset, "value {idx} cannot be used more than once"),
4255 None => bail!(offset, "unknown value {idx}: value index out of bounds"),
4256 }
4257 }
4258
4259 fn defined_type_at(&self, idx: u32, offset: usize) -> Result<ComponentDefinedTypeId> {
4260 match self.component_type_at(idx, offset)? {
4261 ComponentAnyTypeId::Defined(id) => Ok(id),
4262 _ => bail!(offset, "type index {idx} is not a defined type"),
4263 }
4264 }
4265
4266 fn core_function_at(&self, idx: u32, offset: usize) -> Result<CoreTypeId> {
4267 match self.core_funcs.get(idx as usize) {
4268 Some(id) => Ok(*id),
4269 None => bail!(
4270 offset,
4271 "unknown core function {idx}: function index out of bounds"
4272 ),
4273 }
4274 }
4275
4276 fn module_at(&self, idx: u32, offset: usize) -> Result<ComponentCoreModuleTypeId> {
4277 match self.core_modules.get(idx as usize) {
4278 Some(id) => Ok(*id),
4279 None => bail!(offset, "unknown module {idx}: module index out of bounds"),
4280 }
4281 }
4282
4283 fn core_instance_at(&self, idx: u32, offset: usize) -> Result<ComponentCoreInstanceTypeId> {
4284 match self.core_instances.get(idx as usize) {
4285 Some(id) => Ok(*id),
4286 None => bail!(
4287 offset,
4288 "unknown core instance {idx}: instance index out of bounds"
4289 ),
4290 }
4291 }
4292
4293 fn core_instance_export<'a>(
4294 &self,
4295 instance_index: u32,
4296 name: &str,
4297 types: &'a TypeList,
4298 offset: usize,
4299 ) -> Result<&'a EntityType> {
4300 match types[self.core_instance_at(instance_index, offset)?]
4301 .internal_exports(types)
4302 .get(name)
4303 {
4304 Some(export) => Ok(export),
4305 None => bail!(
4306 offset,
4307 "core instance {instance_index} has no export named `{name}`"
4308 ),
4309 }
4310 }
4311
4312 fn global_at(&self, idx: u32, offset: usize) -> Result<&GlobalType> {
4313 match self.core_globals.get(idx as usize) {
4314 Some(t) => Ok(t),
4315 None => bail!(offset, "unknown global {idx}: global index out of bounds"),
4316 }
4317 }
4318
4319 fn table_at(&self, idx: u32, offset: usize) -> Result<&TableType> {
4320 match self.core_tables.get(idx as usize) {
4321 Some(t) => Ok(t),
4322 None => bail!(offset, "unknown table {idx}: table index out of bounds"),
4323 }
4324 }
4325
4326 fn memory_at(&self, idx: u32, offset: usize) -> Result<&MemoryType> {
4327 match self.core_memories.get(idx as usize) {
4328 Some(t) => Ok(t),
4329 None => bail!(offset, "unknown memory {idx}: memory index out of bounds"),
4330 }
4331 }
4332
4333 fn tag_at(&self, idx: u32, offset: usize) -> Result<CoreTypeId> {
4334 match self.core_tags.get(idx as usize) {
4335 Some(t) => Ok(*t),
4336 None => bail!(offset, "unknown tag {idx}: tag index out of bounds"),
4337 }
4338 }
4339
4340 fn cabi_memory_at(&self, idx: u32, offset: usize) -> Result<()> {
4346 let ty = self.memory_at(idx, offset)?;
4347 SubtypeCx::memory_type(
4348 ty,
4349 &MemoryType {
4350 initial: 0,
4351 maximum: None,
4352 memory64: false,
4353 shared: false,
4354 page_size_log2: None,
4355 },
4356 offset,
4357 )
4358 .map_err(|mut e| {
4359 e.add_context("canonical ABI memory is not a 32-bit linear memory".into());
4360 e
4361 })
4362 }
4363
4364 pub fn finish(&mut self, types: &TypeAlloc, offset: usize) -> Result<ComponentType> {
4372 let mut ty = ComponentType {
4373 info: self.type_info,
4375 imports: self.imports.clone(),
4376 exports: self.exports.clone(),
4377
4378 defined_resources: Default::default(),
4382
4383 imported_resources: mem::take(&mut self.imported_resources)
4386 .into_iter()
4387 .collect(),
4388 explicit_resources: mem::take(&mut self.explicit_resources),
4389 };
4390
4391 let mut free = IndexSet::default();
4396 for ty in ty.imports.values() {
4397 types.free_variables_component_entity(ty, &mut free);
4398 }
4399 for (resource, _path) in self.defined_resources.iter() {
4400 if free.contains(resource) {
4408 bail!(offset, "local resource type found in imports");
4409 }
4410 }
4411
4412 free.clear();
4435 for ty in ty.exports.values() {
4436 types.free_variables_component_entity(ty, &mut free);
4437 }
4438 for (id, _rep) in mem::take(&mut self.defined_resources) {
4439 if !free.contains(&id) {
4440 continue;
4441 }
4442
4443 let path = match ty.explicit_resources.get(&id).cloned() {
4444 Some(path) => path,
4445 None => bail!(
4453 offset,
4454 "local resource type found in export but not exported itself"
4455 ),
4456 };
4457
4458 ty.defined_resources.push((id, path));
4459 }
4460
4461 Ok(ty)
4462 }
4463
4464 fn check_value_support(&self, offset: usize) -> Result<()> {
4465 if !self.features.cm_values() {
4466 bail!(
4467 offset,
4468 "support for component model `value`s is not enabled"
4469 );
4470 }
4471 Ok(())
4472 }
4473}
4474
4475impl InternRecGroup for ComponentState {
4476 fn features(&self) -> &WasmFeatures {
4477 &self.features
4478 }
4479
4480 fn add_type_id(&mut self, id: CoreTypeId) {
4481 self.core_types.push(ComponentCoreTypeId::Sub(id));
4482 }
4483
4484 fn type_id_at(&self, idx: u32, offset: usize) -> Result<CoreTypeId> {
4485 match self.core_type_at(idx, offset)? {
4486 ComponentCoreTypeId::Sub(id) => Ok(id),
4487 ComponentCoreTypeId::Module(_) => {
4488 bail!(offset, "type index {idx} is a module type, not a sub type");
4489 }
4490 }
4491 }
4492
4493 fn types_len(&self) -> u32 {
4494 u32::try_from(self.core_types.len()).unwrap()
4495 }
4496}
4497
4498impl ComponentNameContext {
4499 fn register(&mut self, name: &str, id: AliasableResourceId) {
4501 let idx = self.all_resource_names.len();
4502 let prev = self.resource_name_map.insert(id, idx);
4503 assert!(
4504 prev.is_none(),
4505 "for {id:?}, inserted {idx:?} but already had {prev:?}"
4506 );
4507 self.all_resource_names.insert(name.to_string());
4508 }
4509
4510 fn validate_extern(
4511 &self,
4512 name: &str,
4513 kind: ExternKind,
4514 ty: &ComponentEntityType,
4515 types: &TypeAlloc,
4516 offset: usize,
4517 kind_names: &mut IndexSet<ComponentName>,
4518 items: &mut IndexMap<String, ComponentEntityType>,
4519 info: &mut TypeInfo,
4520 features: &WasmFeatures,
4521 ) -> Result<()> {
4522 let kebab = ComponentName::new_with_features(name, offset, *features)
4525 .with_context(|| format!("{} name `{name}` is not a valid extern name", kind.desc()))?;
4526
4527 if let ExternKind::Export = kind {
4528 match kebab.kind() {
4529 ComponentNameKind::Label(_)
4530 | ComponentNameKind::AsyncLabel(_)
4531 | ComponentNameKind::Method(_)
4532 | ComponentNameKind::AsyncMethod(_)
4533 | ComponentNameKind::Static(_)
4534 | ComponentNameKind::AsyncStatic(_)
4535 | ComponentNameKind::Constructor(_)
4536 | ComponentNameKind::Interface(_) => {}
4537
4538 ComponentNameKind::Hash(_)
4539 | ComponentNameKind::Url(_)
4540 | ComponentNameKind::Dependency(_) => {
4541 bail!(offset, "name `{name}` is not a valid export name")
4542 }
4543 }
4544 }
4545
4546 self.validate(&kebab, ty, types, offset, features)
4549 .with_context(|| format!("{} name `{kebab}` is not valid", kind.desc()))?;
4550
4551 if let Some(prev) = kind_names.replace(kebab.clone()) {
4555 bail!(
4556 offset,
4557 "{} name `{kebab}` conflicts with previous name `{prev}`",
4558 kind.desc()
4559 );
4560 }
4561
4562 match items.entry(name.to_string()) {
4566 Entry::Occupied(e) => {
4567 bail!(
4568 offset,
4569 "{kind} name `{name}` conflicts with previous name `{prev}`",
4570 kind = kind.desc(),
4571 prev = e.key(),
4572 );
4573 }
4574 Entry::Vacant(e) => {
4575 e.insert(*ty);
4576 info.combine(ty.info(types), offset)?;
4577 }
4578 }
4579 Ok(())
4580 }
4581
4582 fn validate(
4584 &self,
4585 name: &ComponentName,
4586 ty: &ComponentEntityType,
4587 types: &TypeAlloc,
4588 offset: usize,
4589 features: &WasmFeatures,
4590 ) -> Result<()> {
4591 let func = || {
4592 let id = match ty {
4593 ComponentEntityType::Func(id) => *id,
4594 _ => bail!(offset, "item is not a func"),
4595 };
4596 Ok(&types[id])
4597 };
4598 match name.kind() {
4599 ComponentNameKind::AsyncLabel(_)
4600 | ComponentNameKind::AsyncMethod(_)
4601 | ComponentNameKind::AsyncStatic(_) => {
4602 if !features.cm_async() {
4603 bail!(
4604 offset,
4605 "async kebab-names require the component model async feature"
4606 );
4607 }
4608 }
4609 _ => {}
4610 }
4611
4612 match name.kind() {
4613 ComponentNameKind::Label(_)
4615 | ComponentNameKind::AsyncLabel(_)
4616 | ComponentNameKind::Interface(_)
4617 | ComponentNameKind::Url(_)
4618 | ComponentNameKind::Dependency(_)
4619 | ComponentNameKind::Hash(_) => {}
4620
4621 ComponentNameKind::Constructor(rname) => {
4625 let ty = func()?;
4626 let ty = match ty.result {
4627 Some(result) => result,
4628 None => bail!(offset, "function should return one value"),
4629 };
4630 let resource = match ty {
4631 ComponentValType::Primitive(_) => None,
4632 ComponentValType::Type(ty) => match &types[ty] {
4633 ComponentDefinedType::Own(id) => Some(id),
4634 ComponentDefinedType::Result {
4635 ok: Some(ComponentValType::Type(ok)),
4636 ..
4637 } => match &types[*ok] {
4638 ComponentDefinedType::Own(id) => Some(id),
4639 _ => None,
4640 },
4641 _ => None,
4642 },
4643 };
4644 let resource = match resource {
4645 Some(id) => id,
4646 None => bail!(
4647 offset,
4648 "function should return `(own $T)` or `(result (own $T))`"
4649 ),
4650 };
4651 self.validate_resource_name(*resource, rname, offset)?;
4652 }
4653
4654 ComponentNameKind::Method(name) | ComponentNameKind::AsyncMethod(name) => {
4658 let ty = func()?;
4659 if ty.params.len() == 0 {
4660 bail!(offset, "function should have at least one argument");
4661 }
4662 let (pname, pty) = &ty.params[0];
4663 if pname.as_str() != "self" {
4664 bail!(
4665 offset,
4666 "function should have a first argument called `self`",
4667 );
4668 }
4669 let id = match pty {
4670 ComponentValType::Primitive(_) => None,
4671 ComponentValType::Type(ty) => match &types[*ty] {
4672 ComponentDefinedType::Borrow(id) => Some(id),
4673 _ => None,
4674 },
4675 };
4676 let id = match id {
4677 Some(id) => id,
4678 None => bail!(
4679 offset,
4680 "function should take a first argument of `(borrow $T)`"
4681 ),
4682 };
4683 self.validate_resource_name(*id, name.resource(), offset)?;
4684 }
4685
4686 ComponentNameKind::Static(name) | ComponentNameKind::AsyncStatic(name) => {
4690 func()?;
4691 if !self.all_resource_names.contains(name.resource().as_str()) {
4692 bail!(offset, "static resource name is not known in this context");
4693 }
4694 }
4695 }
4696
4697 Ok(())
4698 }
4699
4700 fn validate_resource_name(
4701 &self,
4702 id: AliasableResourceId,
4703 name: &KebabStr,
4704 offset: usize,
4705 ) -> Result<()> {
4706 let expected_name_idx = match self.resource_name_map.get(&id) {
4707 Some(idx) => *idx,
4708 None => {
4709 bail!(
4710 offset,
4711 "resource used in function does not have a name in this context"
4712 )
4713 }
4714 };
4715 let expected_name = &self.all_resource_names[expected_name_idx];
4716 if name.as_str() != expected_name {
4717 bail!(
4718 offset,
4719 "function does not match expected \
4720 resource name `{expected_name}`"
4721 );
4722 }
4723 Ok(())
4724 }
4725}
4726
4727use self::append_only::*;
4728
4729mod append_only {
4730 use crate::prelude::IndexMap;
4731 use core::hash::Hash;
4732 use core::ops::Deref;
4733
4734 pub struct IndexMapAppendOnly<K, V>(IndexMap<K, V>);
4735
4736 impl<K, V> IndexMapAppendOnly<K, V>
4737 where
4738 K: Hash + Eq + Ord + PartialEq + Clone,
4739 {
4740 pub fn insert(&mut self, key: K, value: V) {
4741 let prev = self.0.insert(key, value);
4742 assert!(prev.is_none());
4743 }
4744 }
4745
4746 impl<K, V> Deref for IndexMapAppendOnly<K, V> {
4747 type Target = IndexMap<K, V>;
4748 fn deref(&self) -> &IndexMap<K, V> {
4749 &self.0
4750 }
4751 }
4752
4753 impl<K, V> Default for IndexMapAppendOnly<K, V> {
4754 fn default() -> Self {
4755 Self(Default::default())
4756 }
4757 }
4758
4759 impl<K, V> IntoIterator for IndexMapAppendOnly<K, V> {
4760 type IntoIter = <IndexMap<K, V> as IntoIterator>::IntoIter;
4761 type Item = <IndexMap<K, V> as IntoIterator>::Item;
4762 fn into_iter(self) -> Self::IntoIter {
4763 self.0.into_iter()
4764 }
4765 }
4766}