1//! State relating to validating a WebAssembly component.
2
3use 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, LoweringInfo, ModuleType,
11 RecordType, 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, CanonicalOption, ComponentExportName, ComponentExternalKind,
22 ComponentOuterAliasKind, ComponentTypeRef, CompositeInnerType, CompositeType, ExternalKind,
23 FuncType, GlobalType, InstantiationArgKind, MemoryType, PackedIndex, RefType, Result, SubType,
24 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: &KebabStr) => 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 /// Whether this state is a concrete component, an instance type, or a
43 /// component type.
44 kind: ComponentKind,
45
46 // Core index spaces
47 pub core_types: Vec<ComponentCoreTypeId>,
48 pub core_funcs: Vec<CoreTypeId>,
49 pub core_tags: Vec<CoreTypeId>,
50 pub core_modules: Vec<ComponentCoreModuleTypeId>,
51 pub core_instances: Vec<ComponentCoreInstanceTypeId>,
52 pub core_memories: Vec<MemoryType>,
53 pub core_tables: Vec<TableType>,
54 pub core_globals: Vec<GlobalType>,
55
56 // Component index spaces
57 pub types: Vec<ComponentAnyTypeId>,
58 pub funcs: Vec<ComponentFuncTypeId>,
59 pub values: Vec<(ComponentValType, bool)>,
60 pub instances: Vec<ComponentInstanceTypeId>,
61 pub components: Vec<ComponentTypeId>,
62
63 pub imports: IndexMap<String, ComponentEntityType>,
64 pub import_names: IndexSet<ComponentName>,
65 pub exports: IndexMap<String, ComponentEntityType>,
66 pub export_names: IndexSet<ComponentName>,
67
68 has_start: bool,
69 type_info: TypeInfo,
70
71 /// A mapping of imported resources in this component.
72 ///
73 /// This mapping represents all "type variables" imported into the
74 /// component, or resources. This could be resources imported directly as
75 /// a top-level type import or additionally transitively through other
76 /// imported instances.
77 ///
78 /// The mapping element here is a "path" which is a list of indexes into
79 /// the import map that will be generated for this component. Each index
80 /// is an index into an `IndexMap`, and each list is guaranteed to have at
81 /// least one element.
82 ///
83 /// An example of this map is:
84 ///
85 /// ```wasm
86 /// (component
87 /// ;; [0] - the first import
88 /// (import "r" (type (sub resource)))
89 ///
90 /// ;; [1] - the second import
91 /// (import "r2" (type (sub resource)))
92 ///
93 /// (import "i" (instance
94 /// ;; [2, 0] - the third import, and the first export the instance
95 /// (export "r3" (type (sub resource)))
96 /// ;; [2, 1] - the third import, and the second export the instance
97 /// (export "r4" (type (sub resource)))
98 /// ))
99 ///
100 /// ;; ...
101 /// )
102 /// ```
103 ///
104 /// The `Vec<usize>` here can be thought of as `Vec<String>` but a
105 /// (hopefully) more efficient representation.
106 ///
107 /// Finally note that this map is listed as an "append only" map because all
108 /// insertions into it should always succeed. Any insertion which overlaps
109 /// with a previous entry indicates a bug in the validator which needs to be
110 /// corrected via other means.
111 //
112 // TODO: make these `SkolemResourceId` and then go fix all the compile
113 // errors, don't add skolem things into the type area
114 imported_resources: IndexMapAppendOnly<ResourceId, Vec<usize>>,
115
116 /// A mapping of "defined" resources in this component, or those which
117 /// are defined within the instantiation of this component.
118 ///
119 /// Defined resources, as the name implies, can sort of be thought of as
120 /// "these are defined within the component". Note though that the means by
121 /// which a local definition can occur are not simply those defined in the
122 /// component but also in its transitively instantiated components
123 /// internally. This means that this set closes over many transitive
124 /// internal items in addition to those defined immediately in the component
125 /// itself.
126 ///
127 /// The `Option<ValType>` in this mapping is whether or not the underlying
128 /// representation of the resource is known to this component. Immediately
129 /// defined resources, for example, will have `Some(I32)` here. Resources
130 /// that come from transitively defined components, for example, will have
131 /// `None`. In the type context all entries here are `None`.
132 ///
133 /// Note that like `imported_resources` all insertions into this map are
134 /// expected to succeed to it's declared as append-only.
135 defined_resources: IndexMapAppendOnly<ResourceId, Option<ValType>>,
136
137 /// A mapping of explicitly exported resources from this component in
138 /// addition to the path that they're exported at.
139 ///
140 /// For more information on the path here see the documentation for
141 /// `imported_resources`. Note that the indexes here index into the
142 /// list of exports of this component.
143 explicit_resources: IndexMap<ResourceId, Vec<usize>>,
144
145 /// The set of types which are considered "exported" from this component.
146 ///
147 /// This is added to whenever a type export is found, or an instance export
148 /// which itself contains a type export. This additionally includes all
149 /// imported types since those are suitable for export as well.
150 ///
151 /// This set is consulted whenever an exported item is added since all
152 /// referenced types must be members of this set.
153 exported_types: Set<ComponentAnyTypeId>,
154
155 /// Same as `exported_types`, but for imports.
156 imported_types: Set<ComponentAnyTypeId>,
157
158 /// The set of top-level resource exports and their names.
159 ///
160 /// This context is used to validate method names such as `[method]foo.bar`
161 /// to ensure that `foo` is an exported resource and that the type mentioned
162 /// in a function type is actually named `foo`.
163 ///
164 /// Note that imports/exports have disjoint contexts to ensure that they're
165 /// validated correctly. Namely you can't retroactively attach methods to an
166 /// import, for example.
167 toplevel_exported_resources: ComponentNameContext,
168
169 /// Same as `toplevel_exported_resources`, but for imports.
170 toplevel_imported_resources: ComponentNameContext,
171}
172
173#[derive(Copy, Clone, Debug, PartialEq, Eq)]
174pub enum ComponentKind {
175 Component,
176 InstanceType,
177 ComponentType,
178}
179
180/// Helper context used to track information about resource names for method
181/// name validation.
182#[derive(Default)]
183struct ComponentNameContext {
184 /// A map from a resource type id to an index in the `all_resource_names`
185 /// set for the name of that resource.
186 resource_name_map: Map<AliasableResourceId, usize>,
187
188 /// All known resource names in this context, used to validate static method
189 /// names to by ensuring that static methods' resource names are somewhere
190 /// in this set.
191 all_resource_names: IndexSet<String>,
192}
193
194#[derive(Debug, Copy, Clone)]
195pub enum ExternKind {
196 Import,
197 Export,
198}
199
200impl ExternKind {
201 pub fn desc(&self) -> &'static str {
202 match self {
203 ExternKind::Import => "import",
204 ExternKind::Export => "export",
205 }
206 }
207}
208
209impl ComponentState {
210 pub fn new(kind: ComponentKind) -> Self {
211 Self {
212 kind,
213 core_types: Default::default(),
214 core_modules: Default::default(),
215 core_instances: Default::default(),
216 core_funcs: Default::default(),
217 core_memories: Default::default(),
218 core_tables: Default::default(),
219 core_globals: Default::default(),
220 core_tags: Default::default(),
221 types: Default::default(),
222 funcs: Default::default(),
223 values: Default::default(),
224 instances: Default::default(),
225 components: Default::default(),
226 imports: Default::default(),
227 exports: Default::default(),
228 import_names: Default::default(),
229 export_names: Default::default(),
230 has_start: Default::default(),
231 type_info: TypeInfo::new(),
232 imported_resources: Default::default(),
233 defined_resources: Default::default(),
234 explicit_resources: Default::default(),
235 exported_types: Default::default(),
236 imported_types: Default::default(),
237 toplevel_exported_resources: Default::default(),
238 toplevel_imported_resources: Default::default(),
239 }
240 }
241
242 pub fn type_count(&self) -> usize {
243 self.core_types.len() + self.types.len()
244 }
245
246 pub fn instance_count(&self) -> usize {
247 self.core_instances.len() + self.instances.len()
248 }
249
250 pub fn function_count(&self) -> usize {
251 self.core_funcs.len() + self.funcs.len()
252 }
253
254 pub fn add_core_type(
255 components: &mut [Self],
256 ty: crate::CoreType,
257 features: &WasmFeatures,
258 types: &mut TypeAlloc,
259 offset: usize,
260 check_limit: bool,
261 ) -> Result<()> {
262 let current = components.last_mut().unwrap();
263 if check_limit {
264 check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
265 }
266 match ty {
267 crate::CoreType::Rec(rec) => {
268 current.canonicalize_and_intern_rec_group(features, types, rec, offset)?;
269 }
270 crate::CoreType::Module(decls) => {
271 let mod_ty = Self::create_module_type(
272 components,
273 decls.into_vec(),
274 features,
275 types,
276 offset,
277 )?;
278 let id = ComponentCoreTypeId::Module(types.push_ty(mod_ty));
279 components.last_mut().unwrap().core_types.push(id);
280 }
281 }
282
283 Ok(())
284 }
285
286 pub fn add_core_module(
287 &mut self,
288 module: &Module,
289 types: &mut TypeAlloc,
290 offset: usize,
291 ) -> Result<()> {
292 let imports = module.imports_for_module_type(offset)?;
293
294 // We have to clone the module's imports and exports here
295 // because we cannot take the data out of the `MaybeOwned`
296 // as it might be shared with a function validator.
297 let mod_ty = ModuleType {
298 info: TypeInfo::core(module.type_size),
299 imports,
300 exports: module.exports.clone(),
301 };
302
303 let mod_id = types.push_ty(mod_ty);
304 self.core_modules.push(mod_id);
305
306 Ok(())
307 }
308
309 pub fn add_core_instance(
310 &mut self,
311 instance: crate::Instance,
312 types: &mut TypeAlloc,
313 offset: usize,
314 ) -> Result<()> {
315 let instance = match instance {
316 crate::Instance::Instantiate { module_index, args } => {
317 self.instantiate_core_module(module_index, args.into_vec(), types, offset)?
318 }
319 crate::Instance::FromExports(exports) => {
320 self.instantiate_core_exports(exports.into_vec(), types, offset)?
321 }
322 };
323
324 self.core_instances.push(instance);
325
326 Ok(())
327 }
328
329 pub fn add_type(
330 components: &mut Vec<Self>,
331 ty: crate::ComponentType,
332 features: &WasmFeatures,
333 types: &mut TypeAlloc,
334 offset: usize,
335 check_limit: bool,
336 ) -> Result<()> {
337 assert!(!components.is_empty());
338
339 fn current(components: &mut Vec<ComponentState>) -> &mut ComponentState {
340 components.last_mut().unwrap()
341 }
342
343 let id = match ty {
344 crate::ComponentType::Defined(ty) => {
345 let ty = current(components).create_defined_type(ty, types, features, offset)?;
346 types.push(ty).into()
347 }
348 crate::ComponentType::Func(ty) => {
349 let ty = current(components).create_function_type(ty, types, features, offset)?;
350 types.push(ty).into()
351 }
352 crate::ComponentType::Component(decls) => {
353 let ty = Self::create_component_type(
354 components,
355 decls.into_vec(),
356 features,
357 types,
358 offset,
359 )?;
360 types.push(ty).into()
361 }
362 crate::ComponentType::Instance(decls) => {
363 let ty = Self::create_instance_type(
364 components,
365 decls.into_vec(),
366 features,
367 types,
368 offset,
369 )?;
370 types.push(ty).into()
371 }
372 crate::ComponentType::Resource { rep, dtor } => {
373 let component = current(components);
374
375 // Resource types cannot be declared in a type context, only
376 // within a component context.
377 if component.kind != ComponentKind::Component {
378 bail!(
379 offset,
380 "resources can only be defined within a concrete component"
381 );
382 }
383
384 // Current MVP restriction of the component model.
385 if rep != ValType::I32 {
386 bail!(offset, "resources can only be represented by `i32`");
387 }
388
389 // If specified validate that the destructor is both a valid
390 // function and has the correct signature.
391 if let Some(dtor) = dtor {
392 let ty = component.core_function_at(dtor, offset)?;
393 let ty = types[ty].composite_type.unwrap_func();
394 if ty.params() != [rep] || ty.results() != [] {
395 bail!(
396 offset,
397 "core function {dtor} has wrong signature for a destructor"
398 );
399 }
400 }
401
402 // As this is the introduction of a resource create a fresh new
403 // identifier for the resource. This is then added into the
404 // list of defined resources for this component, notably with a
405 // rep listed to enable getting access to various intrinsics
406 // such as `resource.rep`.
407 let id = types.alloc_resource_id();
408 component.defined_resources.insert(id.resource(), Some(rep));
409 id.into()
410 }
411 };
412
413 let current = current(components);
414 if check_limit {
415 check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
416 }
417 current.types.push(id);
418
419 Ok(())
420 }
421
422 pub fn add_import(
423 &mut self,
424 import: crate::ComponentImport,
425 features: &WasmFeatures,
426 types: &mut TypeAlloc,
427 offset: usize,
428 ) -> Result<()> {
429 let mut entity = self.check_type_ref(&import.ty, features, types, offset)?;
430 self.add_entity(
431 &mut entity,
432 Some((import.name.0, ExternKind::Import)),
433 features,
434 types,
435 offset,
436 )?;
437 self.toplevel_imported_resources.validate_extern(
438 import.name.0,
439 ExternKind::Import,
440 &entity,
441 types,
442 offset,
443 &mut self.import_names,
444 &mut self.imports,
445 &mut self.type_info,
446 features,
447 )?;
448 Ok(())
449 }
450
451 fn add_entity(
452 &mut self,
453 ty: &mut ComponentEntityType,
454 name_and_kind: Option<(&str, ExternKind)>,
455 features: &WasmFeatures,
456 types: &mut TypeAlloc,
457 offset: usize,
458 ) -> Result<()> {
459 let kind = name_and_kind.map(|(_, k)| k);
460 let (len, max, desc) = match ty {
461 ComponentEntityType::Module(id) => {
462 self.core_modules.push(*id);
463 (self.core_modules.len(), MAX_WASM_MODULES, "modules")
464 }
465 ComponentEntityType::Component(id) => {
466 self.components.push(*id);
467 (self.components.len(), MAX_WASM_COMPONENTS, "components")
468 }
469 ComponentEntityType::Instance(id) => {
470 match kind {
471 Some(ExternKind::Import) => self.prepare_instance_import(id, types),
472 Some(ExternKind::Export) => self.prepare_instance_export(id, types),
473 None => {}
474 }
475 self.instances.push(*id);
476 (self.instance_count(), MAX_WASM_INSTANCES, "instances")
477 }
478 ComponentEntityType::Func(id) => {
479 self.funcs.push(*id);
480 (self.function_count(), MAX_WASM_FUNCTIONS, "functions")
481 }
482 ComponentEntityType::Value(ty) => {
483 self.check_value_support(features, offset)?;
484 let value_used = match kind {
485 Some(ExternKind::Import) | None => false,
486 Some(ExternKind::Export) => true,
487 };
488 self.values.push((*ty, value_used));
489 (self.values.len(), MAX_WASM_VALUES, "values")
490 }
491 ComponentEntityType::Type {
492 created,
493 referenced,
494 } => {
495 self.types.push(*created);
496
497 // Extra logic here for resources being imported and exported.
498 // Note that if `created` is the same as `referenced` then this
499 // is the original introduction of the resource which is where
500 // `self.{imported,defined}_resources` are updated.
501 if let ComponentAnyTypeId::Resource(id) = *created {
502 match kind {
503 Some(ExternKind::Import) => {
504 // A fresh new resource is being imported into a
505 // component. This arises from the import section of
506 // a component or from the import declaration in a
507 // component type. In both cases a new imported
508 // resource is injected with a fresh new identifier
509 // into our state.
510 if created == referenced {
511 self.imported_resources
512 .insert(id.resource(), vec![self.imports.len()]);
513 }
514 }
515
516 Some(ExternKind::Export) => {
517 // A fresh resource is being exported from this
518 // component. This arises as part of the
519 // declaration of a component type, for example. In
520 // this situation brand new resource identifier is
521 // allocated and a definition is added, unlike the
522 // import case where an imported resource is added.
523 // Notably the representation of this new resource
524 // is unknown so it's listed as `None`.
525 if created == referenced {
526 self.defined_resources.insert(id.resource(), None);
527 }
528
529 // If this is a type export of a resource type then
530 // update the `explicit_resources` list. A new
531 // export path is about to be created for this
532 // resource and this keeps track of that.
533 self.explicit_resources
534 .insert(id.resource(), vec![self.exports.len()]);
535 }
536
537 None => {}
538 }
539 }
540 (self.types.len(), MAX_WASM_TYPES, "types")
541 }
542 };
543
544 check_max(len, 0, max, desc, offset)?;
545
546 // Before returning perform the final validation of the type of the item
547 // being imported/exported. This will ensure that everything is
548 // appropriately named with respect to type definitions, resources, etc.
549 if let Some((name, kind)) = name_and_kind {
550 if !self.validate_and_register_named_types(Some(name), kind, ty, types) {
551 bail!(
552 offset,
553 "{} not valid to be used as {}",
554 ty.desc(),
555 kind.desc()
556 );
557 }
558 }
559 Ok(())
560 }
561
562 /// Validates that the `ty` referenced only refers to named types internally
563 /// and then inserts anything necessary, if applicable, to the defined sets
564 /// within this component.
565 ///
566 /// This function will validate that `ty` only refers to named types. For
567 /// example if it's a record then all of its fields must refer to named
568 /// types. This consults either `self.imported_types` or
569 /// `self.exported_types` as specified by `kind`. Note that this is not
570 /// inherently recursive itself but it ends up being recursive since if
571 /// recursive members were named then all their components must also be
572 /// named. Consequently this check stops at the "one layer deep" position,
573 /// or more accurately the position where types must be named (e.g. tuples
574 /// aren't required to be named).
575 fn validate_and_register_named_types(
576 &mut self,
577 toplevel_name: Option<&str>,
578 kind: ExternKind,
579 ty: &ComponentEntityType,
580 types: &TypeAlloc,
581 ) -> bool {
582 if let ComponentEntityType::Type { created, .. } = ty {
583 // If this is a top-level resource then register it in the
584 // appropriate context so later validation of method-like-names
585 // works out.
586 if let Some(name) = toplevel_name {
587 if let ComponentAnyTypeId::Resource(id) = *created {
588 let cx = match kind {
589 ExternKind::Import => &mut self.toplevel_imported_resources,
590 ExternKind::Export => &mut self.toplevel_exported_resources,
591 };
592 cx.register(name, id);
593 }
594 }
595 }
596
597 match self.kind {
598 ComponentKind::Component | ComponentKind::ComponentType => {}
599 ComponentKind::InstanceType => return true,
600 }
601 let set = match kind {
602 ExternKind::Import => &self.imported_types,
603 ExternKind::Export => &self.exported_types,
604 };
605 match ty {
606 // When a type is imported or exported than any recursive type
607 // referred to by that import/export must additionally be exported
608 // or imported. Here this walks the "first layer" of the type which
609 // delegates to `TypeAlloc::type_named_type_id` to determine whether
610 // the components of the type being named here are indeed all they
611 // themselves named.
612 ComponentEntityType::Type {
613 created,
614 referenced,
615 } => {
616 if !self.all_valtypes_named(types, *referenced, set) {
617 return false;
618 }
619 match kind {
620 // Imported types are both valid for import and valid for
621 // export.
622 ExternKind::Import => {
623 self.imported_types.insert(*created);
624 self.exported_types.insert(*created);
625 }
626 ExternKind::Export => {
627 self.exported_types.insert(*created);
628 }
629 }
630
631 true
632 }
633
634 // Instances are slightly nuanced here. The general idea is that if
635 // an instance is imported, then any type exported by the instance
636 // is then also exported. Additionally for exports. To get this to
637 // work out this arm will recursively call
638 // `validate_and_register_named_types` which means that types are
639 // inserted into `self.{imported,exported}_types` as-we-go rather
640 // than all at once.
641 //
642 // This then recursively validates that all items in the instance
643 // itself are valid to import/export, recursive instances are
644 // captured, and everything is appropriately added to the right
645 // imported/exported set.
646 ComponentEntityType::Instance(i) => types[*i]
647 .exports
648 .iter()
649 .all(|(_name, ty)| self.validate_and_register_named_types(None, kind, ty, types)),
650
651 // All types referred to by a function must be named.
652 ComponentEntityType::Func(id) => self.all_valtypes_named_in_func(types, *id, set),
653
654 ComponentEntityType::Value(ty) => types.type_named_valtype(ty, set),
655
656 // Components/modules are always "closed" or "standalone" and don't
657 // need validation with respect to their named types.
658 ComponentEntityType::Component(_) | ComponentEntityType::Module(_) => true,
659 }
660 }
661
662 fn all_valtypes_named(
663 &self,
664 types: &TypeAlloc,
665 id: ComponentAnyTypeId,
666 set: &Set<ComponentAnyTypeId>,
667 ) -> bool {
668 match id {
669 // Resource types, in isolation, are always valid to import or
670 // export since they're either attached to an import or being
671 // exported.
672 //
673 // Note that further validation of this happens in `finish`, too.
674 ComponentAnyTypeId::Resource(_) => true,
675
676 // Component types are validated as they are constructed,
677 // so all component types are valid to export if they've
678 // already been constructed.
679 ComponentAnyTypeId::Component(_) => true,
680
681 ComponentAnyTypeId::Defined(id) => self.all_valtypes_named_in_defined(types, id, set),
682 ComponentAnyTypeId::Func(id) => self.all_valtypes_named_in_func(types, id, set),
683 ComponentAnyTypeId::Instance(id) => self.all_valtypes_named_in_instance(types, id, set),
684 }
685 }
686
687 fn all_valtypes_named_in_instance(
688 &self,
689 types: &TypeAlloc,
690 id: ComponentInstanceTypeId,
691 set: &Set<ComponentAnyTypeId>,
692 ) -> bool {
693 // Instances must recursively have all referenced types named.
694 let ty = &types[id];
695 ty.exports.values().all(|ty| match ty {
696 ComponentEntityType::Module(_) => true,
697 ComponentEntityType::Func(id) => self.all_valtypes_named_in_func(types, *id, set),
698 ComponentEntityType::Type { created: id, .. } => {
699 self.all_valtypes_named(types, *id, set)
700 }
701 ComponentEntityType::Value(ComponentValType::Type(id)) => {
702 self.all_valtypes_named_in_defined(types, *id, set)
703 }
704 ComponentEntityType::Instance(id) => {
705 self.all_valtypes_named_in_instance(types, *id, set)
706 }
707 ComponentEntityType::Component(_)
708 | ComponentEntityType::Value(ComponentValType::Primitive(_)) => return true,
709 })
710 }
711
712 fn all_valtypes_named_in_defined(
713 &self,
714 types: &TypeAlloc,
715 id: ComponentDefinedTypeId,
716 set: &Set<ComponentAnyTypeId>,
717 ) -> bool {
718 let ty = &types[id];
719 match ty {
720 // These types do not contain anything which must be
721 // named.
722 ComponentDefinedType::Primitive(_)
723 | ComponentDefinedType::Flags(_)
724 | ComponentDefinedType::Enum(_)
725 | ComponentDefinedType::ErrorContext => true,
726
727 // Referenced types of all these aggregates must all be
728 // named.
729 ComponentDefinedType::Record(r) => {
730 r.fields.values().all(|t| types.type_named_valtype(t, set))
731 }
732 ComponentDefinedType::Tuple(r) => {
733 r.types.iter().all(|t| types.type_named_valtype(t, set))
734 }
735 ComponentDefinedType::Variant(r) => r
736 .cases
737 .values()
738 .filter_map(|t| t.ty.as_ref())
739 .all(|t| types.type_named_valtype(t, set)),
740 ComponentDefinedType::Result { ok, err } => {
741 ok.as_ref()
742 .map(|t| types.type_named_valtype(t, set))
743 .unwrap_or(true)
744 && err
745 .as_ref()
746 .map(|t| types.type_named_valtype(t, set))
747 .unwrap_or(true)
748 }
749 ComponentDefinedType::List(ty) | ComponentDefinedType::Option(ty) => {
750 types.type_named_valtype(ty, set)
751 }
752
753 // The resource referred to by own/borrow must be named.
754 ComponentDefinedType::Own(id) | ComponentDefinedType::Borrow(id) => {
755 set.contains(&ComponentAnyTypeId::from(*id))
756 }
757
758 ComponentDefinedType::Future(ty) => ty
759 .as_ref()
760 .map(|ty| types.type_named_valtype(ty, set))
761 .unwrap_or(true),
762 ComponentDefinedType::Stream(ty) => types.type_named_valtype(ty, set),
763 }
764 }
765
766 fn all_valtypes_named_in_func(
767 &self,
768 types: &TypeAlloc,
769 id: ComponentFuncTypeId,
770 set: &Set<ComponentAnyTypeId>,
771 ) -> bool {
772 let ty = &types[id];
773 // Function types must have all their parameters/results named.
774 ty.params
775 .iter()
776 .map(|(_, ty)| ty)
777 .chain(ty.results.iter().map(|(_, ty)| ty))
778 .all(|ty| types.type_named_valtype(ty, set))
779 }
780
781 /// Updates the type `id` specified, an identifier for a component instance
782 /// type, to be imported into this component.
783 ///
784 /// Importing an instance type into a component specially handles the
785 /// defined resources registered in the instance type. Notably all
786 /// defined resources are "freshened" into brand new type variables and
787 /// these new variables are substituted within the type. This is what
788 /// creates a new `TypeId` and may update the `id` specified.
789 ///
790 /// One side effect of this operation, for example, is that if an instance
791 /// type is used twice to import two different instances then the instances
792 /// do not share resource types despite sharing the same original instance
793 /// type.
794 fn prepare_instance_import(&mut self, id: &mut ComponentInstanceTypeId, types: &mut TypeAlloc) {
795 let ty = &types[*id];
796
797 // No special treatment for imports of instances which themselves have
798 // no defined resources
799 if ty.defined_resources.is_empty() {
800 return;
801 }
802
803 let mut new_ty = ComponentInstanceType {
804 // Copied from the input verbatim
805 info: ty.info,
806
807 // Copied over as temporary storage for now, and both of these are
808 // filled out and expanded below.
809 exports: ty.exports.clone(),
810 explicit_resources: ty.explicit_resources.clone(),
811
812 // Explicitly discard this field since the
813 // defined resources are lifted into `self`
814 defined_resources: Default::default(),
815 };
816
817 // Create brand new resources for all defined ones in the instance.
818 let resources = (0..ty.defined_resources.len())
819 .map(|_| types.alloc_resource_id())
820 .collect::<IndexSet<_>>();
821
822 // Build a map from the defined resources in `ty` to those in `new_ty`.
823 //
824 // As part of this same loop the new resources, which were previously
825 // defined in `ty`, now become imported variables in `self`. Their
826 // path for where they're imported is updated as well with
827 // `self.next_import_index` as the import-to-be soon.
828 let mut mapping = Remapping::default();
829 let ty = &types[*id];
830 for (old, new) in ty.defined_resources.iter().zip(&resources) {
831 let prev = mapping.resources.insert(*old, new.resource());
832 assert!(prev.is_none());
833
834 let mut base = vec![self.imports.len()];
835 base.extend(ty.explicit_resources[old].iter().copied());
836 self.imported_resources.insert(new.resource(), base);
837 }
838
839 // Using the old-to-new resource mapping perform a substitution on
840 // the `exports` and `explicit_resources` fields of `new_ty`
841 for ty in new_ty.exports.values_mut() {
842 types.remap_component_entity(ty, &mut mapping);
843 }
844 for (id, path) in mem::take(&mut new_ty.explicit_resources) {
845 let id = *mapping.resources.get(&id).unwrap_or(&id);
846 new_ty.explicit_resources.insert(id, path);
847 }
848
849 // Now that `new_ty` is complete finish its registration and then
850 // update `id` on the way out.
851 *id = types.push_ty(new_ty);
852 }
853
854 /// Prepares an instance type, pointed to `id`, for being exported as a
855 /// concrete instance from `self`.
856 ///
857 /// This will internally perform any resource "freshening" as required and
858 /// then additionally update metadata within `self` about resources being
859 /// exported or defined.
860 fn prepare_instance_export(&mut self, id: &mut ComponentInstanceTypeId, types: &mut TypeAlloc) {
861 // Exports of an instance mean that the enclosing context
862 // is inheriting the resources that the instance
863 // encapsulates. This means that the instance type
864 // recorded for this export will itself have no
865 // defined resources.
866 let ty = &types[*id];
867
868 // Check to see if `defined_resources` is non-empty, and if so then
869 // "freshen" all the resources and inherit them to our own defined
870 // resources, updating `id` in the process.
871 //
872 // Note though that this specifically is not rewriting the resources of
873 // exported instances. The `defined_resources` set on instance types is
874 // a little subtle (see its documentation for more info), but the
875 // general idea is that for a concrete instance it's always empty. Only
876 // for instance type definitions does it ever have elements in it.
877 //
878 // That means that if this set is non-empty then what's happening is
879 // that we're in a type context an exporting an instance of a previously
880 // specified type. In this case all resources are required to be
881 // "freshened" to ensure that multiple exports of the same type all
882 // export different types of resources.
883 //
884 // And finally note that this operation empties out the
885 // `defined_resources` set of the type that is registered for the
886 // instance, as this export is modeled as producing a concrete instance.
887 if !ty.defined_resources.is_empty() {
888 let mut new_ty = ty.clone();
889 let mut mapping = Remapping::default();
890 for old in mem::take(&mut new_ty.defined_resources) {
891 let new = types.alloc_resource_id();
892 mapping.resources.insert(old, new.resource());
893 self.defined_resources.insert(new.resource(), None);
894 }
895 for ty in new_ty.exports.values_mut() {
896 types.remap_component_entity(ty, &mut mapping);
897 }
898 for (id, path) in mem::take(&mut new_ty.explicit_resources) {
899 let id = mapping.resources.get(&id).copied().unwrap_or(id);
900 new_ty.explicit_resources.insert(id, path);
901 }
902 *id = types.push_ty(new_ty);
903 }
904
905 // Any explicit resources in the instance are now additionally explicit
906 // in this component since it's exported.
907 //
908 // The path to each explicit resources gets one element prepended which
909 // is `self.next_export_index`, the index of the export about to be
910 // generated.
911 let ty = &types[*id];
912 for (id, path) in ty.explicit_resources.iter() {
913 let mut new_path = vec![self.exports.len()];
914 new_path.extend(path);
915 self.explicit_resources.insert(*id, new_path);
916 }
917 }
918
919 pub fn add_export(
920 &mut self,
921 name: ComponentExportName<'_>,
922 mut ty: ComponentEntityType,
923 features: &WasmFeatures,
924 types: &mut TypeAlloc,
925 offset: usize,
926 check_limit: bool,
927 ) -> Result<()> {
928 if check_limit {
929 check_max(self.exports.len(), 1, MAX_WASM_EXPORTS, "exports", offset)?;
930 }
931 self.add_entity(
932 &mut ty,
933 Some((name.0, ExternKind::Export)),
934 features,
935 types,
936 offset,
937 )?;
938 self.toplevel_exported_resources.validate_extern(
939 name.0,
940 ExternKind::Export,
941 &ty,
942 types,
943 offset,
944 &mut self.export_names,
945 &mut self.exports,
946 &mut self.type_info,
947 features,
948 )?;
949 Ok(())
950 }
951
952 pub fn lift_function(
953 &mut self,
954 core_func_index: u32,
955 type_index: u32,
956 options: Vec<CanonicalOption>,
957 types: &TypeList,
958 offset: usize,
959 features: &WasmFeatures,
960 ) -> Result<()> {
961 let ty = self.function_type_at(type_index, types, offset)?;
962 let core_ty = types[self.core_function_at(core_func_index, offset)?].unwrap_func();
963
964 // Lifting a function is for an export, so match the expected canonical ABI
965 // export signature
966 let info = ty.lower(
967 types,
968 if options.contains(&CanonicalOption::Async) {
969 if options
970 .iter()
971 .any(|v| matches!(v, CanonicalOption::Callback(_)))
972 {
973 Abi::LiftAsync
974 } else {
975 Abi::LiftAsyncStackful
976 }
977 } else {
978 Abi::LiftSync
979 },
980 );
981 self.check_options(
982 Some(core_ty),
983 &info,
984 &options,
985 types,
986 offset,
987 features,
988 true,
989 )?;
990
991 if core_ty.params() != info.params.as_slice() {
992 bail!(
993 offset,
994 "lowered parameter types `{:?}` do not match parameter types \
995 `{:?}` of core function {core_func_index}",
996 info.params.as_slice(),
997 core_ty.params(),
998 );
999 }
1000
1001 if core_ty.results() != info.results.as_slice() {
1002 bail!(
1003 offset,
1004 "lowered result types `{:?}` do not match result types \
1005 `{:?}` of core function {core_func_index}",
1006 info.results.as_slice(),
1007 core_ty.results()
1008 );
1009 }
1010
1011 self.funcs
1012 .push(self.types[type_index as usize].unwrap_func());
1013
1014 Ok(())
1015 }
1016
1017 pub fn lower_function(
1018 &mut self,
1019 func_index: u32,
1020 options: Vec<CanonicalOption>,
1021 types: &mut TypeAlloc,
1022 offset: usize,
1023 features: &WasmFeatures,
1024 ) -> Result<()> {
1025 let ty = &types[self.function_at(func_index, offset)?];
1026
1027 // Lowering a function is for an import, so use a function type that matches
1028 // the expected canonical ABI import signature.
1029 let info = ty.lower(
1030 types,
1031 if options.contains(&CanonicalOption::Async) {
1032 Abi::LowerAsync
1033 } else {
1034 Abi::LowerSync
1035 },
1036 );
1037
1038 self.check_options(None, &info, &options, types, offset, features, true)?;
1039
1040 let id = types.intern_func_type(info.into_func_type(), offset);
1041 self.core_funcs.push(id);
1042
1043 Ok(())
1044 }
1045
1046 pub fn resource_new(
1047 &mut self,
1048 resource: u32,
1049 types: &mut TypeAlloc,
1050 offset: usize,
1051 ) -> Result<()> {
1052 let rep = self.check_local_resource(resource, types, offset)?;
1053 let id = types.intern_func_type(FuncType::new([rep], [ValType::I32]), offset);
1054 self.core_funcs.push(id);
1055 Ok(())
1056 }
1057
1058 pub fn resource_drop(
1059 &mut self,
1060 resource: u32,
1061 types: &mut TypeAlloc,
1062 offset: usize,
1063 ) -> Result<()> {
1064 self.resource_at(resource, types, offset)?;
1065 let id = types.intern_func_type(FuncType::new([ValType::I32], []), offset);
1066 self.core_funcs.push(id);
1067 Ok(())
1068 }
1069
1070 pub fn resource_rep(
1071 &mut self,
1072 resource: u32,
1073 types: &mut TypeAlloc,
1074 offset: usize,
1075 ) -> Result<()> {
1076 let rep = self.check_local_resource(resource, types, offset)?;
1077 let id = types.intern_func_type(FuncType::new([ValType::I32], [rep]), offset);
1078 self.core_funcs.push(id);
1079 Ok(())
1080 }
1081
1082 pub fn task_backpressure(
1083 &mut self,
1084 types: &mut TypeAlloc,
1085 offset: usize,
1086 features: &WasmFeatures,
1087 ) -> Result<()> {
1088 if !features.component_model_async() {
1089 bail!(
1090 offset,
1091 "`task.backpressure` requires the component model async feature"
1092 )
1093 }
1094
1095 self.core_funcs
1096 .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
1097 Ok(())
1098 }
1099
1100 pub fn task_return(
1101 &mut self,
1102 type_index: u32,
1103 types: &mut TypeAlloc,
1104 offset: usize,
1105 features: &WasmFeatures,
1106 ) -> Result<()> {
1107 if !features.component_model_async() {
1108 bail!(
1109 offset,
1110 "`task.return` requires the component model async feature"
1111 )
1112 }
1113
1114 let id = self.type_id_at(type_index, offset)?;
1115 let Some(SubType {
1116 composite_type:
1117 CompositeType {
1118 inner: CompositeInnerType::Func(_),
1119 ..
1120 },
1121 ..
1122 }) = types.get(id)
1123 else {
1124 bail!(offset, "invalid `task.return` type index");
1125 };
1126
1127 self.core_funcs.push(id);
1128 Ok(())
1129 }
1130
1131 pub fn task_wait(
1132 &mut self,
1133 _async_: bool,
1134 memory: u32,
1135 types: &mut TypeAlloc,
1136 offset: usize,
1137 features: &WasmFeatures,
1138 ) -> Result<()> {
1139 if !features.component_model_async() {
1140 bail!(
1141 offset,
1142 "`task.wait` requires the component model async feature"
1143 )
1144 }
1145
1146 self.memory_at(memory, offset)?;
1147
1148 self.core_funcs
1149 .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
1150 Ok(())
1151 }
1152
1153 pub fn task_poll(
1154 &mut self,
1155 _async_: bool,
1156 memory: u32,
1157 types: &mut TypeAlloc,
1158 offset: usize,
1159 features: &WasmFeatures,
1160 ) -> Result<()> {
1161 if !features.component_model_async() {
1162 bail!(
1163 offset,
1164 "`task.poll` requires the component model async feature"
1165 )
1166 }
1167
1168 self.memory_at(memory, offset)?;
1169
1170 self.core_funcs
1171 .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
1172 Ok(())
1173 }
1174
1175 pub fn task_yield(
1176 &mut self,
1177 _async_: bool,
1178 types: &mut TypeAlloc,
1179 offset: usize,
1180 features: &WasmFeatures,
1181 ) -> Result<()> {
1182 if !features.component_model_async() {
1183 bail!(
1184 offset,
1185 "`task.yield` requires the component model async feature"
1186 )
1187 }
1188
1189 self.core_funcs
1190 .push(types.intern_func_type(FuncType::new([], []), offset));
1191 Ok(())
1192 }
1193
1194 pub fn subtask_drop(
1195 &mut self,
1196 types: &mut TypeAlloc,
1197 offset: usize,
1198 features: &WasmFeatures,
1199 ) -> Result<()> {
1200 if !features.component_model_async() {
1201 bail!(
1202 offset,
1203 "`subtask.drop` requires the component model async feature"
1204 )
1205 }
1206
1207 self.core_funcs
1208 .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
1209 Ok(())
1210 }
1211
1212 pub fn stream_new(
1213 &mut self,
1214 ty: u32,
1215 types: &mut TypeAlloc,
1216 offset: usize,
1217 features: &WasmFeatures,
1218 ) -> Result<()> {
1219 if !features.component_model_async() {
1220 bail!(
1221 offset,
1222 "`stream.new` requires the component model async feature"
1223 )
1224 }
1225
1226 let ty = self.defined_type_at(ty, offset)?;
1227 let ComponentDefinedType::Stream(_) = &types[ty] else {
1228 bail!(offset, "`stream.new` requires a stream type")
1229 };
1230
1231 self.core_funcs
1232 .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset));
1233 Ok(())
1234 }
1235
1236 pub fn stream_read(
1237 &mut self,
1238 ty: u32,
1239 options: Vec<CanonicalOption>,
1240 types: &mut TypeAlloc,
1241 offset: usize,
1242 features: &WasmFeatures,
1243 ) -> Result<()> {
1244 if !features.component_model_async() {
1245 bail!(
1246 offset,
1247 "`stream.read` requires the component model async feature"
1248 )
1249 }
1250
1251 let ty = self.defined_type_at(ty, offset)?;
1252 let ComponentDefinedType::Stream(payload_type) = &types[ty] else {
1253 bail!(offset, "`stream.read` requires a stream type")
1254 };
1255
1256 let mut info = LoweringInfo::default();
1257 info.requires_memory = true;
1258 info.requires_realloc = payload_type.contains_ptr(types);
1259 self.check_options(None, &info, &options, types, offset, features, true)?;
1260
1261 self.core_funcs
1262 .push(types.intern_func_type(FuncType::new([ValType::I32; 3], [ValType::I32]), offset));
1263 Ok(())
1264 }
1265
1266 pub fn stream_write(
1267 &mut self,
1268 ty: u32,
1269 options: Vec<CanonicalOption>,
1270 types: &mut TypeAlloc,
1271 offset: usize,
1272 features: &WasmFeatures,
1273 ) -> Result<()> {
1274 if !features.component_model_async() {
1275 bail!(
1276 offset,
1277 "`stream.write` requires the component model async feature"
1278 )
1279 }
1280
1281 let ty = self.defined_type_at(ty, offset)?;
1282 let ComponentDefinedType::Stream(_) = &types[ty] else {
1283 bail!(offset, "`stream.write` requires a stream type")
1284 };
1285
1286 let mut info = LoweringInfo::default();
1287 info.requires_memory = true;
1288 info.requires_realloc = false;
1289 self.check_options(None, &info, &options, types, offset, features, true)?;
1290
1291 self.core_funcs
1292 .push(types.intern_func_type(FuncType::new([ValType::I32; 3], [ValType::I32]), offset));
1293 Ok(())
1294 }
1295
1296 pub fn stream_cancel_read(
1297 &mut self,
1298 ty: u32,
1299 _async_: bool,
1300 types: &mut TypeAlloc,
1301 offset: usize,
1302 features: &WasmFeatures,
1303 ) -> Result<()> {
1304 if !features.component_model_async() {
1305 bail!(
1306 offset,
1307 "`stream.cancel-read` requires the component model async feature"
1308 )
1309 }
1310
1311 let ty = self.defined_type_at(ty, offset)?;
1312 let ComponentDefinedType::Stream(_) = &types[ty] else {
1313 bail!(offset, "`stream.cancel-read` requires a stream type")
1314 };
1315
1316 self.core_funcs
1317 .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
1318 Ok(())
1319 }
1320
1321 pub fn stream_cancel_write(
1322 &mut self,
1323 ty: u32,
1324 _async_: bool,
1325 types: &mut TypeAlloc,
1326 offset: usize,
1327 features: &WasmFeatures,
1328 ) -> Result<()> {
1329 if !features.component_model_async() {
1330 bail!(
1331 offset,
1332 "`stream.cancel-write` requires the component model async feature"
1333 )
1334 }
1335
1336 let ty = self.defined_type_at(ty, offset)?;
1337 let ComponentDefinedType::Stream(_) = &types[ty] else {
1338 bail!(offset, "`stream.cancel-write` requires a stream type")
1339 };
1340
1341 self.core_funcs
1342 .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
1343 Ok(())
1344 }
1345
1346 pub fn stream_close_readable(
1347 &mut self,
1348 ty: u32,
1349 types: &mut TypeAlloc,
1350 offset: usize,
1351 features: &WasmFeatures,
1352 ) -> Result<()> {
1353 if !features.component_model_async() {
1354 bail!(
1355 offset,
1356 "`stream.close-readable` requires the component model async feature"
1357 )
1358 }
1359
1360 let ty = self.defined_type_at(ty, offset)?;
1361 let ComponentDefinedType::Stream(_) = &types[ty] else {
1362 bail!(offset, "`stream.close-readable` requires a stream type")
1363 };
1364
1365 self.core_funcs
1366 .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
1367 Ok(())
1368 }
1369
1370 pub fn stream_close_writable(
1371 &mut self,
1372 ty: u32,
1373 types: &mut TypeAlloc,
1374 offset: usize,
1375 features: &WasmFeatures,
1376 ) -> Result<()> {
1377 if !features.component_model_async() {
1378 bail!(
1379 offset,
1380 "`stream.close-writable` requires the component model async feature"
1381 )
1382 }
1383
1384 let ty = self.defined_type_at(ty, offset)?;
1385 let ComponentDefinedType::Stream(_) = &types[ty] else {
1386 bail!(offset, "`stream.close-writable` requires a stream type")
1387 };
1388
1389 self.core_funcs
1390 .push(types.intern_func_type(FuncType::new([ValType::I32; 2], []), offset));
1391 Ok(())
1392 }
1393
1394 pub fn future_new(
1395 &mut self,
1396 ty: u32,
1397 types: &mut TypeAlloc,
1398 offset: usize,
1399 features: &WasmFeatures,
1400 ) -> Result<()> {
1401 if !features.component_model_async() {
1402 bail!(
1403 offset,
1404 "`future.new` requires the component model async feature"
1405 )
1406 }
1407
1408 let ty = self.defined_type_at(ty, offset)?;
1409 let ComponentDefinedType::Future(_) = &types[ty] else {
1410 bail!(offset, "`future.new` requires a future type")
1411 };
1412
1413 self.core_funcs
1414 .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset));
1415 Ok(())
1416 }
1417
1418 pub fn future_read(
1419 &mut self,
1420 ty: u32,
1421 options: Vec<CanonicalOption>,
1422 types: &mut TypeAlloc,
1423 offset: usize,
1424 features: &WasmFeatures,
1425 ) -> Result<()> {
1426 if !features.component_model_async() {
1427 bail!(
1428 offset,
1429 "`future.read` requires the component model async feature"
1430 )
1431 }
1432
1433 let ty = self.defined_type_at(ty, offset)?;
1434 let ComponentDefinedType::Future(payload_type) = &types[ty] else {
1435 bail!(offset, "`future.read` requires a future type")
1436 };
1437
1438 let mut info = LoweringInfo::default();
1439 info.requires_memory = true;
1440 info.requires_realloc = payload_type
1441 .map(|ty| ty.contains_ptr(types))
1442 .unwrap_or(false);
1443 self.check_options(None, &info, &options, types, offset, features, true)?;
1444
1445 self.core_funcs
1446 .push(types.intern_func_type(FuncType::new([ValType::I32; 2], [ValType::I32]), offset));
1447 Ok(())
1448 }
1449
1450 pub fn future_write(
1451 &mut self,
1452 ty: u32,
1453 options: Vec<CanonicalOption>,
1454 types: &mut TypeAlloc,
1455 offset: usize,
1456 features: &WasmFeatures,
1457 ) -> Result<()> {
1458 if !features.component_model_async() {
1459 bail!(
1460 offset,
1461 "`future.write` requires the component model async feature"
1462 )
1463 }
1464
1465 let ty = self.defined_type_at(ty, offset)?;
1466 let ComponentDefinedType::Future(_) = &types[ty] else {
1467 bail!(offset, "`future.write` requires a future type")
1468 };
1469
1470 let mut info = LoweringInfo::default();
1471 info.requires_memory = true;
1472 info.requires_realloc = false;
1473 self.check_options(None, &info, &options, types, offset, features, true)?;
1474
1475 self.core_funcs
1476 .push(types.intern_func_type(FuncType::new([ValType::I32; 2], [ValType::I32]), offset));
1477 Ok(())
1478 }
1479
1480 pub fn future_cancel_read(
1481 &mut self,
1482 ty: u32,
1483 _async_: bool,
1484 types: &mut TypeAlloc,
1485 offset: usize,
1486 features: &WasmFeatures,
1487 ) -> Result<()> {
1488 if !features.component_model_async() {
1489 bail!(
1490 offset,
1491 "`future.cancel-read` requires the component model async feature"
1492 )
1493 }
1494
1495 let ty = self.defined_type_at(ty, offset)?;
1496 let ComponentDefinedType::Future(_) = &types[ty] else {
1497 bail!(offset, "`future.cancel-read` requires a future type")
1498 };
1499
1500 self.core_funcs
1501 .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
1502 Ok(())
1503 }
1504
1505 pub fn future_cancel_write(
1506 &mut self,
1507 ty: u32,
1508 _async_: bool,
1509 types: &mut TypeAlloc,
1510 offset: usize,
1511 features: &WasmFeatures,
1512 ) -> Result<()> {
1513 if !features.component_model_async() {
1514 bail!(
1515 offset,
1516 "`future.cancel-write` requires the component model async feature"
1517 )
1518 }
1519
1520 let ty = self.defined_type_at(ty, offset)?;
1521 let ComponentDefinedType::Future(_) = &types[ty] else {
1522 bail!(offset, "`future.cancel-write` requires a future type")
1523 };
1524
1525 self.core_funcs
1526 .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
1527 Ok(())
1528 }
1529
1530 pub fn future_close_readable(
1531 &mut self,
1532 ty: u32,
1533 types: &mut TypeAlloc,
1534 offset: usize,
1535 features: &WasmFeatures,
1536 ) -> Result<()> {
1537 if !features.component_model_async() {
1538 bail!(
1539 offset,
1540 "`future.close-readable` requires the component model async feature"
1541 )
1542 }
1543
1544 let ty = self.defined_type_at(ty, offset)?;
1545 let ComponentDefinedType::Future(_) = &types[ty] else {
1546 bail!(offset, "`future.close-readable` requires a future type")
1547 };
1548
1549 self.core_funcs
1550 .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
1551 Ok(())
1552 }
1553
1554 pub fn future_close_writable(
1555 &mut self,
1556 ty: u32,
1557 types: &mut TypeAlloc,
1558 offset: usize,
1559 features: &WasmFeatures,
1560 ) -> Result<()> {
1561 if !features.component_model_async() {
1562 bail!(
1563 offset,
1564 "`future.close-writable` requires the component model async feature"
1565 )
1566 }
1567
1568 let ty = self.defined_type_at(ty, offset)?;
1569 let ComponentDefinedType::Future(_) = &types[ty] else {
1570 bail!(offset, "`future.close-writable` requires a future type")
1571 };
1572
1573 self.core_funcs
1574 .push(types.intern_func_type(FuncType::new([ValType::I32; 2], []), offset));
1575 Ok(())
1576 }
1577
1578 pub fn error_context_new(
1579 &mut self,
1580 options: Vec<CanonicalOption>,
1581 types: &mut TypeAlloc,
1582 offset: usize,
1583 features: &WasmFeatures,
1584 ) -> Result<()> {
1585 if !features.component_model_async() {
1586 bail!(
1587 offset,
1588 "`error-context.new` requires the component model async feature"
1589 )
1590 }
1591
1592 let mut info = LoweringInfo::default();
1593 info.requires_memory = true;
1594 info.requires_realloc = false;
1595 self.check_options(None, &info, &options, types, offset, features, false)?;
1596
1597 self.core_funcs
1598 .push(types.intern_func_type(FuncType::new([ValType::I32; 2], [ValType::I32]), offset));
1599 Ok(())
1600 }
1601
1602 pub fn error_context_debug_message(
1603 &mut self,
1604 options: Vec<CanonicalOption>,
1605 types: &mut TypeAlloc,
1606 offset: usize,
1607 features: &WasmFeatures,
1608 ) -> Result<()> {
1609 if !features.component_model_async() {
1610 bail!(
1611 offset,
1612 "`error-context.debug-message` requires the component model async feature"
1613 )
1614 }
1615
1616 let mut info = LoweringInfo::default();
1617 info.requires_memory = true;
1618 info.requires_realloc = true;
1619 self.check_options(None, &info, &options, types, offset, features, false)?;
1620
1621 self.core_funcs
1622 .push(types.intern_func_type(FuncType::new([ValType::I32; 2], []), offset));
1623 Ok(())
1624 }
1625
1626 pub fn error_context_drop(
1627 &mut self,
1628 types: &mut TypeAlloc,
1629 offset: usize,
1630 features: &WasmFeatures,
1631 ) -> Result<()> {
1632 if !features.component_model_async() {
1633 bail!(
1634 offset,
1635 "`error-context.drop` requires the component model async feature"
1636 )
1637 }
1638
1639 self.core_funcs
1640 .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
1641 Ok(())
1642 }
1643
1644 fn check_local_resource(&self, idx: u32, types: &TypeList, offset: usize) -> Result<ValType> {
1645 let resource = self.resource_at(idx, types, offset)?;
1646 match self
1647 .defined_resources
1648 .get(&resource.resource())
1649 .and_then(|rep| *rep)
1650 {
1651 Some(ty) => Ok(ty),
1652 None => bail!(offset, "type {idx} is not a local resource"),
1653 }
1654 }
1655
1656 fn resource_at<'a>(
1657 &self,
1658 idx: u32,
1659 _types: &'a TypeList,
1660 offset: usize,
1661 ) -> Result<AliasableResourceId> {
1662 if let ComponentAnyTypeId::Resource(id) = self.component_type_at(idx, offset)? {
1663 return Ok(id);
1664 }
1665 bail!(offset, "type index {} is not a resource type", idx)
1666 }
1667
1668 pub fn thread_spawn(
1669 &mut self,
1670 func_ty_index: u32,
1671 types: &mut TypeAlloc,
1672 offset: usize,
1673 features: &WasmFeatures,
1674 ) -> Result<()> {
1675 if !features.shared_everything_threads() {
1676 bail!(
1677 offset,
1678 "`thread.spawn` requires the shared-everything-threads proposal"
1679 )
1680 }
1681
1682 // Validate the type accepted by `thread.spawn`.
1683 let core_type_id = match self.core_type_at(func_ty_index, offset)? {
1684 ComponentCoreTypeId::Sub(c) => c,
1685 ComponentCoreTypeId::Module(_) => bail!(offset, "expected a core function type"),
1686 };
1687 let sub_ty = &types[core_type_id];
1688 if !sub_ty.composite_type.shared {
1689 bail!(offset, "spawn type must be shared");
1690 }
1691 match &sub_ty.composite_type.inner {
1692 CompositeInnerType::Func(func_ty) => {
1693 if func_ty.params() != [ValType::I32] {
1694 bail!(
1695 offset,
1696 "spawn function must take a single `i32` argument (currently)"
1697 );
1698 }
1699 if func_ty.results() != [] {
1700 bail!(offset, "spawn function must not return any values");
1701 }
1702 }
1703 _ => bail!(offset, "spawn type must be a function"),
1704 }
1705
1706 // Insert the core function.
1707 let packed_index = PackedIndex::from_id(core_type_id).ok_or_else(|| {
1708 format_err!(offset, "implementation limit: too many types in `TypeList`")
1709 })?;
1710 let start_func_ref = RefType::concrete(true, packed_index);
1711 let func_ty = FuncType::new([ValType::Ref(start_func_ref), ValType::I32], [ValType::I32]);
1712 let core_ty = SubType::func(func_ty, true);
1713 let id = types.intern_sub_type(core_ty, offset);
1714 self.core_funcs.push(id);
1715
1716 Ok(())
1717 }
1718
1719 pub fn thread_hw_concurrency(
1720 &mut self,
1721 types: &mut TypeAlloc,
1722 offset: usize,
1723 features: &WasmFeatures,
1724 ) -> Result<()> {
1725 if !features.shared_everything_threads() {
1726 bail!(
1727 offset,
1728 "`thread.hw_concurrency` requires the shared-everything-threads proposal"
1729 )
1730 }
1731
1732 let func_ty = FuncType::new([], [ValType::I32]);
1733 let core_ty = SubType::func(func_ty, true);
1734 let id = types.intern_sub_type(core_ty, offset);
1735 self.core_funcs.push(id);
1736
1737 Ok(())
1738 }
1739
1740 pub fn add_component(&mut self, component: ComponentType, types: &mut TypeAlloc) -> Result<()> {
1741 let id = types.push_ty(component);
1742 self.components.push(id);
1743 Ok(())
1744 }
1745
1746 pub fn add_instance(
1747 &mut self,
1748 instance: crate::ComponentInstance,
1749 features: &WasmFeatures,
1750 types: &mut TypeAlloc,
1751 offset: usize,
1752 ) -> Result<()> {
1753 let instance = match instance {
1754 crate::ComponentInstance::Instantiate {
1755 component_index,
1756 args,
1757 } => self.instantiate_component(
1758 component_index,
1759 args.into_vec(),
1760 features,
1761 types,
1762 offset,
1763 )?,
1764 crate::ComponentInstance::FromExports(exports) => {
1765 self.instantiate_component_exports(exports.into_vec(), features, types, offset)?
1766 }
1767 };
1768
1769 self.instances.push(instance);
1770
1771 Ok(())
1772 }
1773
1774 pub fn add_alias(
1775 components: &mut [Self],
1776 alias: crate::ComponentAlias,
1777 features: &WasmFeatures,
1778 types: &mut TypeAlloc,
1779 offset: usize,
1780 ) -> Result<()> {
1781 match alias {
1782 crate::ComponentAlias::InstanceExport {
1783 instance_index,
1784 kind,
1785 name,
1786 } => components.last_mut().unwrap().alias_instance_export(
1787 instance_index,
1788 kind,
1789 name,
1790 features,
1791 types,
1792 offset,
1793 ),
1794 crate::ComponentAlias::CoreInstanceExport {
1795 instance_index,
1796 kind,
1797 name,
1798 } => components.last_mut().unwrap().alias_core_instance_export(
1799 instance_index,
1800 kind,
1801 name,
1802 types,
1803 offset,
1804 ),
1805 crate::ComponentAlias::Outer { kind, count, index } => match kind {
1806 ComponentOuterAliasKind::CoreModule => {
1807 Self::alias_module(components, count, index, offset)
1808 }
1809 ComponentOuterAliasKind::CoreType => {
1810 Self::alias_core_type(components, count, index, offset)
1811 }
1812 ComponentOuterAliasKind::Type => {
1813 Self::alias_type(components, count, index, types, offset)
1814 }
1815 ComponentOuterAliasKind::Component => {
1816 Self::alias_component(components, count, index, offset)
1817 }
1818 },
1819 }
1820 }
1821
1822 pub fn add_start(
1823 &mut self,
1824 func_index: u32,
1825 args: &[u32],
1826 results: u32,
1827 features: &WasmFeatures,
1828 types: &mut TypeList,
1829 offset: usize,
1830 ) -> Result<()> {
1831 if !features.component_model_values() {
1832 bail!(
1833 offset,
1834 "support for component model `value`s is not enabled"
1835 );
1836 }
1837 if self.has_start {
1838 return Err(BinaryReaderError::new(
1839 "component cannot have more than one start function",
1840 offset,
1841 ));
1842 }
1843
1844 let ft = &types[self.function_at(func_index, offset)?];
1845
1846 if ft.params.len() != args.len() {
1847 bail!(
1848 offset,
1849 "component start function requires {} arguments but was given {}",
1850 ft.params.len(),
1851 args.len()
1852 );
1853 }
1854
1855 if ft.results.len() as u32 != results {
1856 bail!(
1857 offset,
1858 "component start function has a result count of {results} \
1859 but the function type has a result count of {type_results}",
1860 type_results = ft.results.len(),
1861 );
1862 }
1863
1864 let cx = SubtypeCx::new(types, types);
1865 for (i, ((_, ty), arg)) in ft.params.iter().zip(args).enumerate() {
1866 // Ensure the value's type is a subtype of the parameter type
1867 cx.component_val_type(self.value_at(*arg, offset)?, ty, offset)
1868 .with_context(|| {
1869 format!("value type mismatch for component start function argument {i}")
1870 })?;
1871 }
1872
1873 for (_, ty) in ft.results.iter() {
1874 self.values.push((*ty, false));
1875 }
1876
1877 self.has_start = true;
1878
1879 Ok(())
1880 }
1881
1882 fn check_options(
1883 &self,
1884 core_ty: Option<&FuncType>,
1885 info: &LoweringInfo,
1886 options: &[CanonicalOption],
1887 types: &TypeList,
1888 offset: usize,
1889 features: &WasmFeatures,
1890 allow_async: bool,
1891 ) -> Result<()> {
1892 fn display(option: CanonicalOption) -> &'static str {
1893 match option {
1894 CanonicalOption::UTF8 => "utf8",
1895 CanonicalOption::UTF16 => "utf16",
1896 CanonicalOption::CompactUTF16 => "latin1-utf16",
1897 CanonicalOption::Memory(_) => "memory",
1898 CanonicalOption::Realloc(_) => "realloc",
1899 CanonicalOption::PostReturn(_) => "post-return",
1900 CanonicalOption::Async => "async",
1901 CanonicalOption::Callback(_) => "callback",
1902 }
1903 }
1904
1905 let mut encoding = None;
1906 let mut memory = None;
1907 let mut realloc = None;
1908 let mut post_return = None;
1909 let mut async_ = false;
1910 let mut callback = None;
1911
1912 for option in options {
1913 match option {
1914 CanonicalOption::UTF8 | CanonicalOption::UTF16 | CanonicalOption::CompactUTF16 => {
1915 match encoding {
1916 Some(existing) => {
1917 bail!(
1918 offset,
1919 "canonical encoding option `{}` conflicts with option `{}`",
1920 display(existing),
1921 display(*option),
1922 )
1923 }
1924 None => encoding = Some(*option),
1925 }
1926 }
1927 CanonicalOption::Memory(idx) => {
1928 memory = match memory {
1929 None => {
1930 self.memory_at(*idx, offset)?;
1931 Some(*idx)
1932 }
1933 Some(_) => {
1934 return Err(BinaryReaderError::new(
1935 "canonical option `memory` is specified more than once",
1936 offset,
1937 ))
1938 }
1939 }
1940 }
1941 CanonicalOption::Realloc(idx) => {
1942 realloc = match realloc {
1943 None => {
1944 let ty = types[self.core_function_at(*idx, offset)?].unwrap_func();
1945 if ty.params()
1946 != [ValType::I32, ValType::I32, ValType::I32, ValType::I32]
1947 || ty.results() != [ValType::I32]
1948 {
1949 return Err(BinaryReaderError::new(
1950 "canonical option `realloc` uses a core function with an incorrect signature",
1951 offset,
1952 ));
1953 }
1954 Some(*idx)
1955 }
1956 Some(_) => {
1957 return Err(BinaryReaderError::new(
1958 "canonical option `realloc` is specified more than once",
1959 offset,
1960 ))
1961 }
1962 }
1963 }
1964 CanonicalOption::PostReturn(idx) => {
1965 post_return = match post_return {
1966 None => {
1967 let core_ty = core_ty.ok_or_else(|| {
1968 BinaryReaderError::new(
1969 "canonical option `post-return` cannot be specified for lowerings",
1970 offset,
1971 )
1972 })?;
1973
1974 let ty = types[self.core_function_at(*idx, offset)?].unwrap_func();
1975
1976 if ty.params() != core_ty.results() || !ty.results().is_empty() {
1977 return Err(BinaryReaderError::new(
1978 "canonical option `post-return` uses a core function with an incorrect signature",
1979 offset,
1980 ));
1981 }
1982 Some(*idx)
1983 }
1984 Some(_) => {
1985 return Err(BinaryReaderError::new(
1986 "canonical option `post-return` is specified more than once",
1987 offset,
1988 ))
1989 }
1990 }
1991 }
1992 CanonicalOption::Async => {
1993 if async_ {
1994 return Err(BinaryReaderError::new(
1995 "canonical option `async` is specified more than once",
1996 offset,
1997 ));
1998 } else {
1999 if !features.component_model_async() {
2000 bail!(
2001 offset,
2002 "canonical option `async` requires the component model async feature"
2003 );
2004 }
2005
2006 async_ = true;
2007 }
2008 }
2009 CanonicalOption::Callback(idx) => {
2010 callback = match callback {
2011 None => {
2012 if core_ty.is_none() {
2013 return Err(BinaryReaderError::new(
2014 "canonical option `callback` cannot be specified for lowerings",
2015 offset,
2016 ));
2017 }
2018
2019 let ty = types[self.core_function_at(*idx, offset)?].unwrap_func();
2020
2021 if ty.params() != [ValType::I32; 4] && ty.params() != [ValType::I32] {
2022 return Err(BinaryReaderError::new(
2023 "canonical option `callback` uses a core function with an incorrect signature",
2024 offset,
2025 ));
2026 }
2027 Some(*idx)
2028 }
2029 Some(_) => {
2030 return Err(BinaryReaderError::new(
2031 "canonical option `callback` is specified more than once",
2032 offset,
2033 ))
2034 }
2035 }
2036 }
2037 }
2038 }
2039
2040 if async_ && !allow_async {
2041 bail!(offset, "async option not allowed here")
2042 }
2043
2044 if callback.is_some() && !async_ {
2045 bail!(offset, "cannot specify callback without lifting async")
2046 }
2047
2048 if info.requires_memory && memory.is_none() {
2049 return Err(BinaryReaderError::new(
2050 "canonical option `memory` is required",
2051 offset,
2052 ));
2053 }
2054
2055 if info.requires_realloc && realloc.is_none() {
2056 return Err(BinaryReaderError::new(
2057 "canonical option `realloc` is required",
2058 offset,
2059 ));
2060 }
2061
2062 Ok(())
2063 }
2064
2065 fn check_type_ref(
2066 &mut self,
2067 ty: &ComponentTypeRef,
2068 features: &WasmFeatures,
2069 types: &mut TypeAlloc,
2070 offset: usize,
2071 ) -> Result<ComponentEntityType> {
2072 Ok(match ty {
2073 ComponentTypeRef::Module(index) => {
2074 let id = self.core_type_at(*index, offset)?;
2075 match id {
2076 ComponentCoreTypeId::Sub(_) => {
2077 bail!(offset, "core type index {index} is not a module type")
2078 }
2079 ComponentCoreTypeId::Module(id) => ComponentEntityType::Module(id),
2080 }
2081 }
2082 ComponentTypeRef::Func(index) => {
2083 let id = self.component_type_at(*index, offset)?;
2084 match id {
2085 ComponentAnyTypeId::Func(id) => ComponentEntityType::Func(id),
2086 _ => bail!(offset, "type index {index} is not a function type"),
2087 }
2088 }
2089 ComponentTypeRef::Value(ty) => {
2090 self.check_value_support(features, offset)?;
2091 let ty = match ty {
2092 crate::ComponentValType::Primitive(ty) => ComponentValType::Primitive(*ty),
2093 crate::ComponentValType::Type(index) => {
2094 ComponentValType::Type(self.defined_type_at(*index, offset)?)
2095 }
2096 };
2097 ComponentEntityType::Value(ty)
2098 }
2099 ComponentTypeRef::Type(TypeBounds::Eq(index)) => {
2100 let referenced = self.component_type_at(*index, offset)?;
2101 let created = types.with_unique(referenced);
2102 ComponentEntityType::Type {
2103 referenced,
2104 created,
2105 }
2106 }
2107 ComponentTypeRef::Type(TypeBounds::SubResource) => {
2108 let id = types.alloc_resource_id();
2109 ComponentEntityType::Type {
2110 referenced: id.into(),
2111 created: id.into(),
2112 }
2113 }
2114 ComponentTypeRef::Instance(index) => {
2115 let id = self.component_type_at(*index, offset)?;
2116 match id {
2117 ComponentAnyTypeId::Instance(id) => ComponentEntityType::Instance(id),
2118 _ => bail!(offset, "type index {index} is not an instance type"),
2119 }
2120 }
2121 ComponentTypeRef::Component(index) => {
2122 let id = self.component_type_at(*index, offset)?;
2123 match id {
2124 ComponentAnyTypeId::Component(id) => ComponentEntityType::Component(id),
2125 _ => bail!(offset, "type index {index} is not a component type"),
2126 }
2127 }
2128 })
2129 }
2130
2131 pub fn export_to_entity_type(
2132 &mut self,
2133 export: &crate::ComponentExport,
2134 features: &WasmFeatures,
2135 types: &mut TypeAlloc,
2136 offset: usize,
2137 ) -> Result<ComponentEntityType> {
2138 let actual = match export.kind {
2139 ComponentExternalKind::Module => {
2140 ComponentEntityType::Module(self.module_at(export.index, offset)?)
2141 }
2142 ComponentExternalKind::Func => {
2143 ComponentEntityType::Func(self.function_at(export.index, offset)?)
2144 }
2145 ComponentExternalKind::Value => {
2146 self.check_value_support(features, offset)?;
2147 ComponentEntityType::Value(*self.value_at(export.index, offset)?)
2148 }
2149 ComponentExternalKind::Type => {
2150 let referenced = self.component_type_at(export.index, offset)?;
2151 let created = types.with_unique(referenced);
2152 ComponentEntityType::Type {
2153 referenced,
2154 created,
2155 }
2156 }
2157 ComponentExternalKind::Instance => {
2158 ComponentEntityType::Instance(self.instance_at(export.index, offset)?)
2159 }
2160 ComponentExternalKind::Component => {
2161 ComponentEntityType::Component(self.component_at(export.index, offset)?)
2162 }
2163 };
2164
2165 let ascribed = match &export.ty {
2166 Some(ty) => self.check_type_ref(ty, features, types, offset)?,
2167 None => return Ok(actual),
2168 };
2169
2170 SubtypeCx::new(types, types)
2171 .component_entity_type(&actual, &ascribed, offset)
2172 .with_context(|| "ascribed type of export is not compatible with item's type")?;
2173
2174 Ok(ascribed)
2175 }
2176
2177 fn create_module_type(
2178 components: &[Self],
2179 decls: Vec<crate::ModuleTypeDeclaration>,
2180 features: &WasmFeatures,
2181 types: &mut TypeAlloc,
2182 offset: usize,
2183 ) -> Result<ModuleType> {
2184 let mut state = Module::default();
2185
2186 for decl in decls {
2187 match decl {
2188 crate::ModuleTypeDeclaration::Type(rec) => {
2189 state.add_types(rec, features, types, offset, true)?;
2190 }
2191 crate::ModuleTypeDeclaration::Export { name, mut ty } => {
2192 let ty = state.check_type_ref(&mut ty, features, types, offset)?;
2193 state.add_export(name, ty, features, offset, true, types)?;
2194 }
2195 crate::ModuleTypeDeclaration::OuterAlias { kind, count, index } => {
2196 match kind {
2197 crate::OuterAliasKind::Type => {
2198 let ty = if count == 0 {
2199 // Local alias, check the local module state
2200 ComponentCoreTypeId::Sub(state.type_id_at(index, offset)?)
2201 } else {
2202 // Otherwise, check the enclosing component state
2203 let component =
2204 Self::check_alias_count(components, count - 1, offset)?;
2205 component.core_type_at(index, offset)?
2206 };
2207
2208 check_max(state.types.len(), 1, MAX_WASM_TYPES, "types", offset)?;
2209
2210 match ty {
2211 ComponentCoreTypeId::Sub(ty) => state.types.push(ty),
2212 // TODO https://github.com/WebAssembly/component-model/issues/265
2213 ComponentCoreTypeId::Module(_) => bail!(
2214 offset,
2215 "not implemented: aliasing core module types into a core \
2216 module's types index space"
2217 ),
2218 }
2219 }
2220 }
2221 }
2222 crate::ModuleTypeDeclaration::Import(import) => {
2223 state.add_import(import, features, types, offset)?;
2224 }
2225 }
2226 }
2227
2228 let imports = state.imports_for_module_type(offset)?;
2229
2230 Ok(ModuleType {
2231 info: TypeInfo::core(state.type_size),
2232 imports,
2233 exports: state.exports,
2234 })
2235 }
2236
2237 fn create_component_type(
2238 components: &mut Vec<Self>,
2239 decls: Vec<crate::ComponentTypeDeclaration>,
2240 features: &WasmFeatures,
2241 types: &mut TypeAlloc,
2242 offset: usize,
2243 ) -> Result<ComponentType> {
2244 components.push(ComponentState::new(ComponentKind::ComponentType));
2245
2246 for decl in decls {
2247 match decl {
2248 crate::ComponentTypeDeclaration::CoreType(ty) => {
2249 Self::add_core_type(components, ty, features, types, offset, true)?;
2250 }
2251 crate::ComponentTypeDeclaration::Type(ty) => {
2252 Self::add_type(components, ty, features, types, offset, true)?;
2253 }
2254 crate::ComponentTypeDeclaration::Export { name, ty } => {
2255 let current = components.last_mut().unwrap();
2256 let ty = current.check_type_ref(&ty, features, types, offset)?;
2257 current.add_export(name, ty, features, types, offset, true)?;
2258 }
2259 crate::ComponentTypeDeclaration::Import(import) => {
2260 components
2261 .last_mut()
2262 .unwrap()
2263 .add_import(import, features, types, offset)?;
2264 }
2265 crate::ComponentTypeDeclaration::Alias(alias) => {
2266 Self::add_alias(components, alias, features, types, offset)?;
2267 }
2268 };
2269 }
2270
2271 components.pop().unwrap().finish(types, offset)
2272 }
2273
2274 fn create_instance_type(
2275 components: &mut Vec<Self>,
2276 decls: Vec<crate::InstanceTypeDeclaration>,
2277 features: &WasmFeatures,
2278 types: &mut TypeAlloc,
2279 offset: usize,
2280 ) -> Result<ComponentInstanceType> {
2281 components.push(ComponentState::new(ComponentKind::InstanceType));
2282
2283 for decl in decls {
2284 match decl {
2285 crate::InstanceTypeDeclaration::CoreType(ty) => {
2286 Self::add_core_type(components, ty, features, types, offset, true)?;
2287 }
2288 crate::InstanceTypeDeclaration::Type(ty) => {
2289 Self::add_type(components, ty, features, types, offset, true)?;
2290 }
2291 crate::InstanceTypeDeclaration::Export { name, ty } => {
2292 let current = components.last_mut().unwrap();
2293 let ty = current.check_type_ref(&ty, features, types, offset)?;
2294 current.add_export(name, ty, features, types, offset, true)?;
2295 }
2296 crate::InstanceTypeDeclaration::Alias(alias) => {
2297 Self::add_alias(components, alias, features, types, offset)?;
2298 }
2299 };
2300 }
2301
2302 let mut state = components.pop().unwrap();
2303
2304 assert!(state.imported_resources.is_empty());
2305
2306 Ok(ComponentInstanceType {
2307 info: state.type_info,
2308
2309 // The defined resources for this instance type are those listed on
2310 // the component state. The path to each defined resource is
2311 // guaranteed to live within the `explicit_resources` map since,
2312 // when in the type context, the introduction of any defined
2313 // resource must have been done with `(export "x" (type (sub
2314 // resource)))` which, in a sense, "fuses" the introduction of the
2315 // variable with the export. This means that all defined resources,
2316 // if any, should be guaranteed to have an `explicit_resources` path
2317 // listed.
2318 defined_resources: mem::take(&mut state.defined_resources)
2319 .into_iter()
2320 .map(|(id, rep)| {
2321 assert!(rep.is_none());
2322 id
2323 })
2324 .collect(),
2325
2326 // The map of what resources are explicitly exported and where
2327 // they're exported is plumbed through as-is.
2328 explicit_resources: mem::take(&mut state.explicit_resources),
2329
2330 exports: mem::take(&mut state.exports),
2331 })
2332 }
2333
2334 fn create_function_type(
2335 &self,
2336 ty: crate::ComponentFuncType,
2337 types: &TypeList,
2338 features: &WasmFeatures,
2339 offset: usize,
2340 ) -> Result<ComponentFuncType> {
2341 let mut info = TypeInfo::new();
2342
2343 if ty.results.type_count() > 1 && !features.component_model_multiple_returns() {
2344 bail!(
2345 offset,
2346 "multiple returns on a function is now a gated feature \
2347 -- https://github.com/WebAssembly/component-model/pull/368"
2348 );
2349 }
2350
2351 let mut set = Set::default();
2352 set.reserve(core::cmp::max(ty.params.len(), ty.results.type_count()));
2353
2354 let params = ty
2355 .params
2356 .iter()
2357 .map(|(name, ty)| {
2358 let name: &KebabStr = to_kebab_str(name, "function parameter", offset)?;
2359 if !set.insert(name) {
2360 bail!(
2361 offset,
2362 "function parameter name `{name}` conflicts with previous parameter name `{prev}`",
2363 prev = set.get(&name).unwrap(),
2364 );
2365 }
2366
2367 let ty = self.create_component_val_type(*ty, offset)?;
2368 info.combine(ty.info(types), offset)?;
2369 Ok((name.to_owned(), ty))
2370 })
2371 .collect::<Result<_>>()?;
2372
2373 set.clear();
2374
2375 let results = ty
2376 .results
2377 .iter()
2378 .map(|(name, ty)| {
2379 let name = name
2380 .map(|name| {
2381 let name = to_kebab_str(name, "function result", offset)?;
2382 if !set.insert(name) {
2383 bail!(
2384 offset,
2385 "function result name `{name}` conflicts with previous result name `{prev}`",
2386 prev = set.get(name).unwrap(),
2387 );
2388 }
2389
2390 Ok(name.to_owned())
2391 })
2392 .transpose()?;
2393
2394 let ty = self.create_component_val_type(*ty, offset)?;
2395 let ty_info = ty.info(types);
2396 if ty_info.contains_borrow() {
2397 bail!(offset, "function result cannot contain a `borrow` type");
2398 }
2399 info.combine(ty.info(types), offset)?;
2400 Ok((name, ty))
2401 })
2402 .collect::<Result<_>>()?;
2403
2404 Ok(ComponentFuncType {
2405 info,
2406 params,
2407 results,
2408 })
2409 }
2410
2411 fn instantiate_core_module(
2412 &self,
2413 module_index: u32,
2414 module_args: Vec<crate::InstantiationArg>,
2415 types: &mut TypeAlloc,
2416 offset: usize,
2417 ) -> Result<ComponentCoreInstanceTypeId> {
2418 fn insert_arg<'a>(
2419 name: &'a str,
2420 arg: &'a InstanceType,
2421 args: &mut IndexMap<&'a str, &'a InstanceType>,
2422 offset: usize,
2423 ) -> Result<()> {
2424 if args.insert(name, arg).is_some() {
2425 bail!(
2426 offset,
2427 "duplicate module instantiation argument named `{name}`"
2428 );
2429 }
2430
2431 Ok(())
2432 }
2433
2434 let module_type_id = self.module_at(module_index, offset)?;
2435 let mut args = IndexMap::default();
2436
2437 // Populate the arguments
2438 for module_arg in module_args {
2439 match module_arg.kind {
2440 InstantiationArgKind::Instance => {
2441 let instance_type = &types[self.core_instance_at(module_arg.index, offset)?];
2442 insert_arg(module_arg.name, instance_type, &mut args, offset)?;
2443 }
2444 }
2445 }
2446
2447 // Validate the arguments
2448 let module_type = &types[module_type_id];
2449 let cx = SubtypeCx::new(types, types);
2450 for ((module, name), expected) in module_type.imports.iter() {
2451 let instance = args.get(module.as_str()).ok_or_else(|| {
2452 format_err!(
2453 offset,
2454 "missing module instantiation argument named `{module}`"
2455 )
2456 })?;
2457
2458 let arg = instance
2459 .internal_exports(types)
2460 .get(name.as_str())
2461 .ok_or_else(|| {
2462 format_err!(
2463 offset,
2464 "module instantiation argument `{module}` does not \
2465 export an item named `{name}`",
2466 )
2467 })?;
2468
2469 cx.entity_type(arg, expected, offset).with_context(|| {
2470 format!(
2471 "type mismatch for export `{name}` of module \
2472 instantiation argument `{module}`"
2473 )
2474 })?;
2475 }
2476
2477 let mut info = TypeInfo::new();
2478 for (_, ty) in module_type.exports.iter() {
2479 info.combine(ty.info(types), offset)?;
2480 }
2481
2482 Ok(types.push_ty(InstanceType {
2483 info,
2484 kind: CoreInstanceTypeKind::Instantiated(module_type_id),
2485 }))
2486 }
2487
2488 fn instantiate_component(
2489 &mut self,
2490 component_index: u32,
2491 component_args: Vec<crate::ComponentInstantiationArg>,
2492 features: &WasmFeatures,
2493 types: &mut TypeAlloc,
2494 offset: usize,
2495 ) -> Result<ComponentInstanceTypeId> {
2496 let component_type_id = self.component_at(component_index, offset)?;
2497 let mut args = IndexMap::default();
2498
2499 // Populate the arguments
2500 for component_arg in component_args {
2501 let ty = match component_arg.kind {
2502 ComponentExternalKind::Module => {
2503 ComponentEntityType::Module(self.module_at(component_arg.index, offset)?)
2504 }
2505 ComponentExternalKind::Component => {
2506 ComponentEntityType::Component(self.component_at(component_arg.index, offset)?)
2507 }
2508 ComponentExternalKind::Instance => {
2509 ComponentEntityType::Instance(self.instance_at(component_arg.index, offset)?)
2510 }
2511 ComponentExternalKind::Func => {
2512 ComponentEntityType::Func(self.function_at(component_arg.index, offset)?)
2513 }
2514 ComponentExternalKind::Value => {
2515 self.check_value_support(features, offset)?;
2516 ComponentEntityType::Value(*self.value_at(component_arg.index, offset)?)
2517 }
2518 ComponentExternalKind::Type => {
2519 let ty = self.component_type_at(component_arg.index, offset)?;
2520 ComponentEntityType::Type {
2521 referenced: ty,
2522 created: ty,
2523 }
2524 }
2525 };
2526 match args.entry(component_arg.name.to_string()) {
2527 Entry::Occupied(e) => {
2528 bail!(
2529 offset,
2530 "instantiation argument `{name}` conflicts with previous argument `{prev}`",
2531 prev = e.key(),
2532 name = component_arg.name
2533 );
2534 }
2535 Entry::Vacant(e) => {
2536 e.insert(ty);
2537 }
2538 }
2539 }
2540
2541 // Here comes the fun part of the component model, we're instantiating
2542 // the component with type `component_type_id` with the `args`
2543 // specified. Easy enough!
2544 //
2545 // This operation, however, is one of the lynchpins of safety in the
2546 // component model. Additionally what this ends up implementing ranges
2547 // from "well just check the types are equal" to "let's have a
2548 // full-blown ML-style module type system in the component model". There
2549 // are primarily two major tricky pieces to the component model which
2550 // make this operation, instantiating components, hard:
2551 //
2552 // 1. Components can import and exports other components. This means
2553 // that arguments to instantiation are along the lines of functions
2554 // being passed to functions or similar. Effectively this means that
2555 // the term "variance" comes into play with either contravariance
2556 // or covariance depending on where you are in typechecking. This is
2557 // one of the main rationales, however, that this check below is a
2558 // check for subtyping as opposed to exact type equivalence. For
2559 // example an instance that exports something is a subtype of an
2560 // instance that exports nothing. Components get a bit trick since
2561 // they both have imports and exports. My way of thinking about it
2562 // is "who's asking for what". If you're asking for imports then
2563 // I need to at least supply those imports, but I can possibly
2564 // supply more. If you're asking for a thing which you'll give a set
2565 // of imports, then I can give you something which takes less imports
2566 // because what you give still suffices. (things like that). The
2567 // real complication with components, however, comes with...
2568 //
2569 // 2. Resources. Resources in the component model are akin to "abstract
2570 // types". They're not abstract in the sense that they have no
2571 // representation, they're always backed by a 32-bit integer right
2572 // now. Instead they're abstract in the sense that some components
2573 // aren't allowed to understand the representation of a resource.
2574 // For example if you import a resource you can't get the underlying
2575 // internals of it. Furthermore the resource is strictly tracked
2576 // within the component with `own` and `borrow` runtime semantics.
2577 // The hardest part about resources, though, is handling them as
2578 // part of instantiation and subtyping.
2579 //
2580 // For example one major aspect of resources is that if a component
2581 // exports a resource then each instantiation of the component
2582 // produces a fresh resource type. This means that the type recorded
2583 // for the instantiation here can't simply be "I instantiated
2584 // component X" since in such a situation the type of all
2585 // instantiations would be the same, which they aren't.
2586 //
2587 // This sort of subtelty comes up quite frequently for resources.
2588 // This file contains references to `imported_resources` and
2589 // `defined_resources` for example which refer to the formal
2590 // nature of components and their abstract variables. Specifically
2591 // for instantiation though we're eventually faced with the problem
2592 // of subtype checks where resource subtyping is defined as "does
2593 // your id equal mine". Naively implemented that means anything with
2594 // resources isn't subtypes of anything else since resource ids are
2595 // unique between components. Instead what actually needs to happen
2596 // is types need to be substituted.
2597 //
2598 // Much of the complexity here is not actually apparent here in this
2599 // literal one function. Instead it's spread out across validation
2600 // in this file and type-checking in the `types.rs` module. Note that
2601 // the "spread out" nature isn't because we're bad maintainers
2602 // (hopefully), but rather it's quite infectious how many parts need
2603 // to handle resources and account for defined/imported variables.
2604 //
2605 // For example only one subtyping method is called here where `args` is
2606 // passed in. This method is quite recursive in its nature though and
2607 // will internally touch all the fields that this file maintains to
2608 // end up putting into various bits and pieces of type information.
2609 //
2610 // Unfortunately there's probably not really a succinct way to read
2611 // this method and understand everything. If you've written ML module
2612 // type systems this will probably look quite familiar, but otherwise
2613 // the whole system is not really easily approachable at this time. It's
2614 // hoped in the future that there's a formalism to refer to which will
2615 // make things more clear as the code would be able to reference this
2616 // hypothetical formalism. Until that's the case, though, these
2617 // comments are hopefully enough when augmented with communication with
2618 // the authors.
2619
2620 let component_type = &types[component_type_id];
2621 let mut exports = component_type.exports.clone();
2622 let mut info = TypeInfo::new();
2623 for (_, ty) in component_type.exports.iter() {
2624 info.combine(ty.info(types), offset)?;
2625 }
2626
2627 // Perform the subtype check that `args` matches the imports of
2628 // `component_type_id`. The result of this subtype check is the
2629 // production of a mapping of resource types from the imports to the
2630 // arguments provided. This is a substitution map which is then used
2631 // below to perform a substitution into the exports of the instance
2632 // since the types of the exports are now in terms of whatever was
2633 // supplied as imports.
2634 let mut mapping = SubtypeCx::new(types, types).open_instance_type(
2635 &args,
2636 component_type_id,
2637 ExternKind::Import,
2638 offset,
2639 )?;
2640
2641 // Part of the instantiation of a component is that all of its
2642 // defined resources become "fresh" on each instantiation. This
2643 // means that each instantiation of a component gets brand new type
2644 // variables representing its defined resources, modeling that each
2645 // instantiation produces distinct types. The freshening is performed
2646 // here by allocating new ids and inserting them into `mapping`.
2647 //
2648 // Note that technically the `mapping` from subtyping should be applied
2649 // first and then the mapping for freshening should be applied
2650 // afterwards. The keys of the map from subtyping are the imported
2651 // resources from this component which are disjoint from its defined
2652 // resources. That means it should be possible to place everything
2653 // into one large map which maps from:
2654 //
2655 // * the component's imported resources go to whatever was explicitly
2656 // supplied in the import map
2657 // * the component's defined resources go to fresh new resources
2658 //
2659 // These two remapping operations can then get folded into one by
2660 // placing everything in the same `mapping` and using that for a remap
2661 // only once.
2662 let fresh_defined_resources = (0..component_type.defined_resources.len())
2663 .map(|_| types.alloc_resource_id().resource())
2664 .collect::<IndexSet<_>>();
2665 let component_type = &types[component_type_id];
2666 for ((old, _path), new) in component_type
2667 .defined_resources
2668 .iter()
2669 .zip(&fresh_defined_resources)
2670 {
2671 let prev = mapping.resources.insert(*old, *new);
2672 assert!(prev.is_none());
2673 }
2674
2675 // Perform the remapping operation over all the exports that will be
2676 // listed for the final instance type. Note that this is performed
2677 // both for all the export types in addition to the explicitly exported
2678 // resources list.
2679 //
2680 // Note that this is a crucial step of the instantiation process which
2681 // is intentionally transforming the type of a component based on the
2682 // variables provided by imports and additionally ensuring that all
2683 // references to the component's defined resources are rebound to the
2684 // fresh ones introduced just above.
2685 for entity in exports.values_mut() {
2686 types.remap_component_entity(entity, &mut mapping);
2687 }
2688 let component_type = &types[component_type_id];
2689 let explicit_resources = component_type
2690 .explicit_resources
2691 .iter()
2692 .map(|(id, path)| {
2693 (
2694 mapping.resources.get(id).copied().unwrap_or(*id),
2695 path.clone(),
2696 )
2697 })
2698 .collect::<IndexMap<_, _>>();
2699
2700 // Technically in the last formalism that was consulted in writing this
2701 // implementation there are two further steps that are part of the
2702 // instantiation process:
2703 //
2704 // 1. The set of defined resources from the instance created, which are
2705 // added to the outer component, is the subset of the instance's
2706 // original defined resources and the free variables of the exports.
2707 //
2708 // 2. Each element of this subset is required to be "explicit in" the
2709 // instance, or otherwise explicitly exported somewhere within the
2710 // instance.
2711 //
2712 // With the syntactic structure of the component model, however, neither
2713 // of these conditions should be necessary. The main reason for this is
2714 // that this function is specifically dealing with instantiation of
2715 // components which should already have these properties validated
2716 // about them. Subsequently we shouldn't have to re-check them.
2717 //
2718 // In debug mode, however, do a sanity check.
2719 if cfg!(debug_assertions) {
2720 let mut free = IndexSet::default();
2721 for ty in exports.values() {
2722 types.free_variables_component_entity(ty, &mut free);
2723 }
2724 assert!(fresh_defined_resources.is_subset(&free));
2725 for resource in fresh_defined_resources.iter() {
2726 assert!(explicit_resources.contains_key(resource));
2727 }
2728 }
2729
2730 // And as the final step of the instantiation process all of the
2731 // new defined resources from this component instantiation are moved
2732 // onto `self`. Note that concrete instances never have defined
2733 // resources (see more comments in `instantiate_exports`) so the
2734 // `defined_resources` listing in the final type is always empty. This
2735 // represents how by having a concrete instance the definitions
2736 // referred to in that instance are now problems for the outer
2737 // component rather than the inner instance since the instance is bound
2738 // to the component.
2739 //
2740 // All defined resources here have no known representation, so they're
2741 // all listed with `None`. Also note that none of the resources were
2742 // exported yet so `self.explicit_resources` is not updated yet. If
2743 // this instance is exported, however, it'll consult the type's
2744 // `explicit_resources` array and use that appropriately.
2745 for resource in fresh_defined_resources {
2746 self.defined_resources.insert(resource, None);
2747 }
2748
2749 Ok(types.push_ty(ComponentInstanceType {
2750 info,
2751 defined_resources: Default::default(),
2752 explicit_resources,
2753 exports,
2754 }))
2755 }
2756
2757 fn instantiate_component_exports(
2758 &mut self,
2759 exports: Vec<crate::ComponentExport>,
2760 features: &WasmFeatures,
2761 types: &mut TypeAlloc,
2762 offset: usize,
2763 ) -> Result<ComponentInstanceTypeId> {
2764 let mut info = TypeInfo::new();
2765 let mut inst_exports = IndexMap::default();
2766 let mut explicit_resources = IndexMap::default();
2767 let mut export_names = IndexSet::default();
2768
2769 // NB: It's intentional that this context is empty since no indices are
2770 // introduced in the bag-of-exports construct which means there's no
2771 // way syntactically to register something inside of this.
2772 let names = ComponentNameContext::default();
2773
2774 for export in exports {
2775 assert!(export.ty.is_none());
2776 let ty = match export.kind {
2777 ComponentExternalKind::Module => {
2778 ComponentEntityType::Module(self.module_at(export.index, offset)?)
2779 }
2780 ComponentExternalKind::Component => {
2781 ComponentEntityType::Component(self.component_at(export.index, offset)?)
2782 }
2783 ComponentExternalKind::Instance => {
2784 let ty = self.instance_at(export.index, offset)?;
2785
2786 // When an instance is exported from an instance then
2787 // all explicitly exported resources on the sub-instance are
2788 // now also listed as exported resources on the outer
2789 // instance, just with one more element in their path.
2790 explicit_resources.extend(types[ty].explicit_resources.iter().map(
2791 |(id, path)| {
2792 let mut new_path = vec![inst_exports.len()];
2793 new_path.extend(path);
2794 (*id, new_path)
2795 },
2796 ));
2797 ComponentEntityType::Instance(ty)
2798 }
2799 ComponentExternalKind::Func => {
2800 ComponentEntityType::Func(self.function_at(export.index, offset)?)
2801 }
2802 ComponentExternalKind::Value => {
2803 self.check_value_support(features, offset)?;
2804 ComponentEntityType::Value(*self.value_at(export.index, offset)?)
2805 }
2806 ComponentExternalKind::Type => {
2807 let ty = self.component_type_at(export.index, offset)?;
2808 // If this is an export of a resource type be sure to
2809 // record that in the explicit list with the appropriate
2810 // path because if this instance ends up getting used
2811 // it'll count towards the "explicit in" check.
2812 if let ComponentAnyTypeId::Resource(id) = ty {
2813 explicit_resources.insert(id.resource(), vec![inst_exports.len()]);
2814 }
2815 ComponentEntityType::Type {
2816 referenced: ty,
2817 // The created type index here isn't used anywhere
2818 // in index spaces because a "bag of exports"
2819 // doesn't build up its own index spaces. Just fill
2820 // in the same index here in this case as what's
2821 // referenced.
2822 created: ty,
2823 }
2824 }
2825 };
2826
2827 names.validate_extern(
2828 export.name.0,
2829 ExternKind::Export,
2830 &ty,
2831 types,
2832 offset,
2833 &mut export_names,
2834 &mut inst_exports,
2835 &mut info,
2836 features,
2837 )?;
2838 }
2839
2840 Ok(types.push_ty(ComponentInstanceType {
2841 info,
2842 explicit_resources,
2843 exports: inst_exports,
2844
2845 // NB: the list of defined resources for this instance itself
2846 // is always empty. Even if this instance exports resources,
2847 // it's empty.
2848 //
2849 // The reason for this is a bit subtle. The general idea, though, is
2850 // that the defined resources list here is only used for instance
2851 // types that are sort of "floating around" and haven't actually
2852 // been attached to something yet. For example when an instance type
2853 // is simply declared it can have defined resources introduced
2854 // through `(export "name" (type (sub resource)))`. These
2855 // definitions, however, are local to the instance itself and aren't
2856 // defined elsewhere.
2857 //
2858 // Here, though, no new definitions were introduced. The instance
2859 // created here is a "bag of exports" which could only refer to
2860 // preexisting items. This means that inherently no new resources
2861 // were created so there's nothing to put in this list. Any
2862 // resources referenced by the instance must be bound by the outer
2863 // component context or further above.
2864 //
2865 // Furthermore, however, actual instances of instances, which this
2866 // is, aren't allowed to have defined resources. Instead the
2867 // resources would have to be injected into the outer component
2868 // enclosing the instance. That means that even if bag-of-exports
2869 // could declare a new resource then the resource would be moved
2870 // from here to `self.defined_resources`. This doesn't exist at this
2871 // time, though, so this still remains empty and
2872 // `self.defined_resources` remains unperturbed.
2873 defined_resources: Default::default(),
2874 }))
2875 }
2876
2877 fn instantiate_core_exports(
2878 &mut self,
2879 exports: Vec<crate::Export>,
2880 types: &mut TypeAlloc,
2881 offset: usize,
2882 ) -> Result<ComponentCoreInstanceTypeId> {
2883 fn insert_export(
2884 types: &TypeList,
2885 name: &str,
2886 export: EntityType,
2887 exports: &mut IndexMap<String, EntityType>,
2888 info: &mut TypeInfo,
2889 offset: usize,
2890 ) -> Result<()> {
2891 info.combine(export.info(types), offset)?;
2892
2893 if exports.insert(name.to_string(), export).is_some() {
2894 bail!(
2895 offset,
2896 "duplicate instantiation export name `{name}` already defined",
2897 )
2898 }
2899
2900 Ok(())
2901 }
2902
2903 let mut info = TypeInfo::new();
2904 let mut inst_exports = IndexMap::default();
2905 for export in exports {
2906 match export.kind {
2907 ExternalKind::Func => {
2908 insert_export(
2909 types,
2910 export.name,
2911 EntityType::Func(self.core_function_at(export.index, offset)?),
2912 &mut inst_exports,
2913 &mut info,
2914 offset,
2915 )?;
2916 }
2917 ExternalKind::Table => insert_export(
2918 types,
2919 export.name,
2920 EntityType::Table(*self.table_at(export.index, offset)?),
2921 &mut inst_exports,
2922 &mut info,
2923 offset,
2924 )?,
2925 ExternalKind::Memory => insert_export(
2926 types,
2927 export.name,
2928 EntityType::Memory(*self.memory_at(export.index, offset)?),
2929 &mut inst_exports,
2930 &mut info,
2931 offset,
2932 )?,
2933 ExternalKind::Global => {
2934 insert_export(
2935 types,
2936 export.name,
2937 EntityType::Global(*self.global_at(export.index, offset)?),
2938 &mut inst_exports,
2939 &mut info,
2940 offset,
2941 )?;
2942 }
2943 ExternalKind::Tag => insert_export(
2944 types,
2945 export.name,
2946 EntityType::Tag(self.core_function_at(export.index, offset)?),
2947 &mut inst_exports,
2948 &mut info,
2949 offset,
2950 )?,
2951 }
2952 }
2953
2954 Ok(types.push_ty(InstanceType {
2955 info,
2956 kind: CoreInstanceTypeKind::Exports(inst_exports),
2957 }))
2958 }
2959
2960 fn alias_core_instance_export(
2961 &mut self,
2962 instance_index: u32,
2963 kind: ExternalKind,
2964 name: &str,
2965 types: &TypeList,
2966 offset: usize,
2967 ) -> Result<()> {
2968 macro_rules! push_module_export {
2969 ($expected:path, $collection:ident, $ty:literal) => {{
2970 match self.core_instance_export(instance_index, name, types, offset)? {
2971 $expected(ty) => {
2972 self.$collection.push(*ty);
2973 }
2974 _ => {
2975 bail!(
2976 offset,
2977 "export `{name}` for core instance {instance_index} is not a {}",
2978 $ty
2979 )
2980 }
2981 }
2982 }};
2983 }
2984
2985 match kind {
2986 ExternalKind::Func => {
2987 check_max(
2988 self.function_count(),
2989 1,
2990 MAX_WASM_FUNCTIONS,
2991 "functions",
2992 offset,
2993 )?;
2994 push_module_export!(EntityType::Func, core_funcs, "function");
2995 }
2996 ExternalKind::Table => {
2997 check_max(
2998 self.core_tables.len(),
2999 1,
3000 MAX_CORE_INDEX_SPACE_ITEMS,
3001 "tables",
3002 offset,
3003 )?;
3004 push_module_export!(EntityType::Table, core_tables, "table");
3005
3006 let ty = self.core_tables.last().unwrap();
3007 if ty.table64 {
3008 bail!(
3009 offset,
3010 "64-bit tables are not compatible with components yet"
3011 );
3012 }
3013 if ty.shared {
3014 bail!(
3015 offset,
3016 "shared tables are not compatible with components yet"
3017 );
3018 }
3019 }
3020 ExternalKind::Memory => {
3021 check_max(
3022 self.core_memories.len(),
3023 1,
3024 MAX_CORE_INDEX_SPACE_ITEMS,
3025 "memories",
3026 offset,
3027 )?;
3028 push_module_export!(EntityType::Memory, core_memories, "memory");
3029
3030 let ty = self.core_memories.last().unwrap();
3031 if ty.memory64 {
3032 bail!(
3033 offset,
3034 "64-bit linear memories are not compatible with components yet"
3035 );
3036 }
3037 if ty.shared {
3038 bail!(
3039 offset,
3040 "shared linear memories are not compatible with components yet"
3041 );
3042 }
3043 }
3044 ExternalKind::Global => {
3045 check_max(
3046 self.core_globals.len(),
3047 1,
3048 MAX_CORE_INDEX_SPACE_ITEMS,
3049 "globals",
3050 offset,
3051 )?;
3052 push_module_export!(EntityType::Global, core_globals, "global");
3053 }
3054 ExternalKind::Tag => {
3055 check_max(
3056 self.core_tags.len(),
3057 1,
3058 MAX_CORE_INDEX_SPACE_ITEMS,
3059 "tags",
3060 offset,
3061 )?;
3062 push_module_export!(EntityType::Tag, core_tags, "tag");
3063 }
3064 }
3065
3066 Ok(())
3067 }
3068
3069 fn alias_instance_export(
3070 &mut self,
3071 instance_index: u32,
3072 kind: ComponentExternalKind,
3073 name: &str,
3074 features: &WasmFeatures,
3075 types: &mut TypeAlloc,
3076 offset: usize,
3077 ) -> Result<()> {
3078 if let ComponentExternalKind::Value = kind {
3079 self.check_value_support(features, offset)?;
3080 }
3081 let mut ty = match types[self.instance_at(instance_index, offset)?]
3082 .exports
3083 .get(name)
3084 {
3085 Some(ty) => *ty,
3086 None => bail!(
3087 offset,
3088 "instance {instance_index} has no export named `{name}`"
3089 ),
3090 };
3091
3092 let ok = match (&ty, kind) {
3093 (ComponentEntityType::Module(_), ComponentExternalKind::Module) => true,
3094 (ComponentEntityType::Module(_), _) => false,
3095 (ComponentEntityType::Component(_), ComponentExternalKind::Component) => true,
3096 (ComponentEntityType::Component(_), _) => false,
3097 (ComponentEntityType::Func(_), ComponentExternalKind::Func) => true,
3098 (ComponentEntityType::Func(_), _) => false,
3099 (ComponentEntityType::Instance(_), ComponentExternalKind::Instance) => true,
3100 (ComponentEntityType::Instance(_), _) => false,
3101 (ComponentEntityType::Value(_), ComponentExternalKind::Value) => true,
3102 (ComponentEntityType::Value(_), _) => false,
3103 (ComponentEntityType::Type { .. }, ComponentExternalKind::Type) => true,
3104 (ComponentEntityType::Type { .. }, _) => false,
3105 };
3106 if !ok {
3107 bail!(
3108 offset,
3109 "export `{name}` for instance {instance_index} is not a {}",
3110 kind.desc(),
3111 );
3112 }
3113
3114 self.add_entity(&mut ty, None, features, types, offset)?;
3115 Ok(())
3116 }
3117
3118 fn alias_module(components: &mut [Self], count: u32, index: u32, offset: usize) -> Result<()> {
3119 let component = Self::check_alias_count(components, count, offset)?;
3120 let ty = component.module_at(index, offset)?;
3121
3122 let current = components.last_mut().unwrap();
3123 check_max(
3124 current.core_modules.len(),
3125 1,
3126 MAX_WASM_MODULES,
3127 "modules",
3128 offset,
3129 )?;
3130
3131 current.core_modules.push(ty);
3132 Ok(())
3133 }
3134
3135 fn alias_component(
3136 components: &mut [Self],
3137 count: u32,
3138 index: u32,
3139 offset: usize,
3140 ) -> Result<()> {
3141 let component = Self::check_alias_count(components, count, offset)?;
3142 let ty = component.component_at(index, offset)?;
3143
3144 let current = components.last_mut().unwrap();
3145 check_max(
3146 current.components.len(),
3147 1,
3148 MAX_WASM_COMPONENTS,
3149 "components",
3150 offset,
3151 )?;
3152
3153 current.components.push(ty);
3154 Ok(())
3155 }
3156
3157 fn alias_core_type(
3158 components: &mut [Self],
3159 count: u32,
3160 index: u32,
3161 offset: usize,
3162 ) -> Result<()> {
3163 let component = Self::check_alias_count(components, count, offset)?;
3164 let ty = component.core_type_at(index, offset)?;
3165
3166 let current = components.last_mut().unwrap();
3167 check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
3168
3169 current.core_types.push(ty);
3170
3171 Ok(())
3172 }
3173
3174 fn alias_type(
3175 components: &mut [Self],
3176 count: u32,
3177 index: u32,
3178 types: &mut TypeAlloc,
3179 offset: usize,
3180 ) -> Result<()> {
3181 let component = Self::check_alias_count(components, count, offset)?;
3182 let ty = component.component_type_at(index, offset)?;
3183
3184 // If `count` "crossed a component boundary", meaning that it went from
3185 // one component to another, then this must additionally verify that
3186 // `ty` has no free variables with respect to resources. This is
3187 // intended to preserve the property for components where each component
3188 // is an isolated unit that can theoretically be extracted from other
3189 // components. If resources from other components were allowed to leak
3190 // in then it would prevent that.
3191 //
3192 // This check is done by calculating the `pos` within `components` that
3193 // our target `component` above was selected at. Once this is acquired
3194 // the component to the "right" is checked, and if that's a component
3195 // then it's considered as crossing a component boundary meaning the
3196 // free variables check runs.
3197 //
3198 // The reason this works is that in the list of `ComponentState` types
3199 // it's guaranteed that any `is_type` components are contiguous at the
3200 // end of the array. This means that if state one level deeper than the
3201 // target of this alias is a `!is_type` component, then the target must
3202 // be a component as well. If the one-level deeper state `is_type` then
3203 // the target is either a type or a component, both of which are valid
3204 // (as aliases can reach the enclosing component and have as many free
3205 // variables as they want).
3206 let pos_after_component = components.len() - (count as usize);
3207 if let Some(component) = components.get(pos_after_component) {
3208 if component.kind == ComponentKind::Component {
3209 let mut free = IndexSet::default();
3210 types.free_variables_any_type_id(ty, &mut free);
3211 if !free.is_empty() {
3212 bail!(
3213 offset,
3214 "cannot alias outer type which transitively refers \
3215 to resources not defined in the current component"
3216 );
3217 }
3218 }
3219 }
3220
3221 let current = components.last_mut().unwrap();
3222 check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
3223
3224 current.types.push(ty);
3225
3226 Ok(())
3227 }
3228
3229 fn check_alias_count(components: &[Self], count: u32, offset: usize) -> Result<&Self> {
3230 let count = count as usize;
3231 if count >= components.len() {
3232 bail!(offset, "invalid outer alias count of {count}");
3233 }
3234
3235 Ok(&components[components.len() - count - 1])
3236 }
3237
3238 fn create_defined_type(
3239 &self,
3240 ty: crate::ComponentDefinedType,
3241 types: &TypeList,
3242 features: &WasmFeatures,
3243 offset: usize,
3244 ) -> Result<ComponentDefinedType> {
3245 match ty {
3246 crate::ComponentDefinedType::Primitive(ty) => Ok(ComponentDefinedType::Primitive(ty)),
3247 crate::ComponentDefinedType::Record(fields) => {
3248 self.create_record_type(fields.as_ref(), types, offset)
3249 }
3250 crate::ComponentDefinedType::Variant(cases) => {
3251 self.create_variant_type(cases.as_ref(), types, offset)
3252 }
3253 crate::ComponentDefinedType::List(ty) => Ok(ComponentDefinedType::List(
3254 self.create_component_val_type(ty, offset)?,
3255 )),
3256 crate::ComponentDefinedType::Tuple(tys) => {
3257 self.create_tuple_type(tys.as_ref(), types, offset)
3258 }
3259 crate::ComponentDefinedType::Flags(names) => {
3260 self.create_flags_type(names.as_ref(), features, offset)
3261 }
3262 crate::ComponentDefinedType::Enum(cases) => {
3263 self.create_enum_type(cases.as_ref(), offset)
3264 }
3265 crate::ComponentDefinedType::Option(ty) => Ok(ComponentDefinedType::Option(
3266 self.create_component_val_type(ty, offset)?,
3267 )),
3268 crate::ComponentDefinedType::Result { ok, err } => Ok(ComponentDefinedType::Result {
3269 ok: ok
3270 .map(|ty| self.create_component_val_type(ty, offset))
3271 .transpose()?,
3272 err: err
3273 .map(|ty| self.create_component_val_type(ty, offset))
3274 .transpose()?,
3275 }),
3276 crate::ComponentDefinedType::Own(idx) => Ok(ComponentDefinedType::Own(
3277 self.resource_at(idx, types, offset)?,
3278 )),
3279 crate::ComponentDefinedType::Borrow(idx) => Ok(ComponentDefinedType::Borrow(
3280 self.resource_at(idx, types, offset)?,
3281 )),
3282 crate::ComponentDefinedType::Future(ty) => Ok(ComponentDefinedType::Future(
3283 ty.map(|ty| self.create_component_val_type(ty, offset))
3284 .transpose()?,
3285 )),
3286 crate::ComponentDefinedType::Stream(ty) => Ok(ComponentDefinedType::Stream(
3287 self.create_component_val_type(ty, offset)?,
3288 )),
3289 crate::ComponentDefinedType::ErrorContext => Ok(ComponentDefinedType::ErrorContext),
3290 }
3291 }
3292
3293 fn create_record_type(
3294 &self,
3295 fields: &[(&str, crate::ComponentValType)],
3296 types: &TypeList,
3297 offset: usize,
3298 ) -> Result<ComponentDefinedType> {
3299 let mut info = TypeInfo::new();
3300 let mut field_map = IndexMap::default();
3301 field_map.reserve(fields.len());
3302
3303 if fields.is_empty() {
3304 bail!(offset, "record type must have at least one field");
3305 }
3306
3307 for (name, ty) in fields {
3308 let name = to_kebab_str(name, "record field", offset)?;
3309 let ty = self.create_component_val_type(*ty, offset)?;
3310
3311 match field_map.entry(name.to_owned()) {
3312 Entry::Occupied(e) => bail!(
3313 offset,
3314 "record field name `{name}` conflicts with previous field name `{prev}`",
3315 prev = e.key()
3316 ),
3317 Entry::Vacant(e) => {
3318 info.combine(ty.info(types), offset)?;
3319 e.insert(ty);
3320 }
3321 }
3322 }
3323
3324 Ok(ComponentDefinedType::Record(RecordType {
3325 info,
3326 fields: field_map,
3327 }))
3328 }
3329
3330 fn create_variant_type(
3331 &self,
3332 cases: &[crate::VariantCase],
3333 types: &TypeList,
3334 offset: usize,
3335 ) -> Result<ComponentDefinedType> {
3336 let mut info = TypeInfo::new();
3337 let mut case_map: IndexMap<KebabString, VariantCase> = IndexMap::default();
3338 case_map.reserve(cases.len());
3339
3340 if cases.is_empty() {
3341 bail!(offset, "variant type must have at least one case");
3342 }
3343
3344 if cases.len() > u32::MAX as usize {
3345 return Err(BinaryReaderError::new(
3346 "variant type cannot be represented with a 32-bit discriminant value",
3347 offset,
3348 ));
3349 }
3350
3351 for (i, case) in cases.iter().enumerate() {
3352 if let Some(refines) = case.refines {
3353 if refines >= i as u32 {
3354 return Err(BinaryReaderError::new(
3355 "variant case can only refine a previously defined case",
3356 offset,
3357 ));
3358 }
3359 }
3360
3361 let name = to_kebab_str(case.name, "variant case", offset)?;
3362
3363 let ty = case
3364 .ty
3365 .map(|ty| self.create_component_val_type(ty, offset))
3366 .transpose()?;
3367
3368 match case_map.entry(name.to_owned()) {
3369 Entry::Occupied(e) => bail!(
3370 offset,
3371 "variant case name `{name}` conflicts with previous case name `{prev}`",
3372 name = case.name,
3373 prev = e.key()
3374 ),
3375 Entry::Vacant(e) => {
3376 if let Some(ty) = ty {
3377 info.combine(ty.info(types), offset)?;
3378 }
3379
3380 // Safety: the use of `KebabStr::new_unchecked` here is safe because the string
3381 // was already verified to be kebab case.
3382 e.insert(VariantCase {
3383 ty,
3384 refines: case
3385 .refines
3386 .map(|i| KebabStr::new_unchecked(cases[i as usize].name).to_owned()),
3387 });
3388 }
3389 }
3390 }
3391
3392 Ok(ComponentDefinedType::Variant(VariantType {
3393 info,
3394 cases: case_map,
3395 }))
3396 }
3397
3398 fn create_tuple_type(
3399 &self,
3400 tys: &[crate::ComponentValType],
3401 types: &TypeList,
3402 offset: usize,
3403 ) -> Result<ComponentDefinedType> {
3404 let mut info = TypeInfo::new();
3405 if tys.is_empty() {
3406 bail!(offset, "tuple type must have at least one type");
3407 }
3408 let types = tys
3409 .iter()
3410 .map(|ty| {
3411 let ty = self.create_component_val_type(*ty, offset)?;
3412 info.combine(ty.info(types), offset)?;
3413 Ok(ty)
3414 })
3415 .collect::<Result<_>>()?;
3416
3417 Ok(ComponentDefinedType::Tuple(TupleType { info, types }))
3418 }
3419
3420 fn create_flags_type(
3421 &self,
3422 names: &[&str],
3423 features: &WasmFeatures,
3424 offset: usize,
3425 ) -> Result<ComponentDefinedType> {
3426 let mut names_set = IndexSet::default();
3427 names_set.reserve(names.len());
3428
3429 if names.is_empty() {
3430 bail!(offset, "flags must have at least one entry");
3431 }
3432
3433 if names.len() > 32 && !features.component_model_more_flags() {
3434 bail!(
3435 offset,
3436 "cannot have more than 32 flags; this was previously \
3437 accepted and if this is required for your project please \
3438 leave a comment on \
3439 https://github.com/WebAssembly/component-model/issues/370"
3440 );
3441 }
3442
3443 for name in names {
3444 let name = to_kebab_str(name, "flag", offset)?;
3445 if !names_set.insert(name.to_owned()) {
3446 bail!(
3447 offset,
3448 "flag name `{name}` conflicts with previous flag name `{prev}`",
3449 prev = names_set.get(name).unwrap()
3450 );
3451 }
3452 }
3453
3454 Ok(ComponentDefinedType::Flags(names_set))
3455 }
3456
3457 fn create_enum_type(&self, cases: &[&str], offset: usize) -> Result<ComponentDefinedType> {
3458 if cases.len() > u32::MAX as usize {
3459 return Err(BinaryReaderError::new(
3460 "enumeration type cannot be represented with a 32-bit discriminant value",
3461 offset,
3462 ));
3463 }
3464
3465 if cases.is_empty() {
3466 bail!(offset, "enum type must have at least one variant");
3467 }
3468
3469 let mut tags = IndexSet::default();
3470 tags.reserve(cases.len());
3471
3472 for tag in cases {
3473 let tag = to_kebab_str(tag, "enum tag", offset)?;
3474 if !tags.insert(tag.to_owned()) {
3475 bail!(
3476 offset,
3477 "enum tag name `{tag}` conflicts with previous tag name `{prev}`",
3478 prev = tags.get(tag).unwrap()
3479 );
3480 }
3481 }
3482
3483 Ok(ComponentDefinedType::Enum(tags))
3484 }
3485
3486 fn create_component_val_type(
3487 &self,
3488 ty: crate::ComponentValType,
3489 offset: usize,
3490 ) -> Result<ComponentValType> {
3491 Ok(match ty {
3492 crate::ComponentValType::Primitive(pt) => ComponentValType::Primitive(pt),
3493 crate::ComponentValType::Type(idx) => {
3494 ComponentValType::Type(self.defined_type_at(idx, offset)?)
3495 }
3496 })
3497 }
3498
3499 pub fn core_type_at(&self, idx: u32, offset: usize) -> Result<ComponentCoreTypeId> {
3500 self.core_types
3501 .get(idx as usize)
3502 .copied()
3503 .ok_or_else(|| format_err!(offset, "unknown type {idx}: type index out of bounds"))
3504 }
3505
3506 pub fn component_type_at(&self, idx: u32, offset: usize) -> Result<ComponentAnyTypeId> {
3507 self.types
3508 .get(idx as usize)
3509 .copied()
3510 .ok_or_else(|| format_err!(offset, "unknown type {idx}: type index out of bounds"))
3511 }
3512
3513 fn function_type_at<'a>(
3514 &self,
3515 idx: u32,
3516 types: &'a TypeList,
3517 offset: usize,
3518 ) -> Result<&'a ComponentFuncType> {
3519 let id = self.component_type_at(idx, offset)?;
3520 match id {
3521 ComponentAnyTypeId::Func(id) => Ok(&types[id]),
3522 _ => bail!(offset, "type index {idx} is not a function type"),
3523 }
3524 }
3525
3526 fn function_at(&self, idx: u32, offset: usize) -> Result<ComponentFuncTypeId> {
3527 self.funcs.get(idx as usize).copied().ok_or_else(|| {
3528 format_err!(
3529 offset,
3530 "unknown function {idx}: function index out of bounds"
3531 )
3532 })
3533 }
3534
3535 fn component_at(&self, idx: u32, offset: usize) -> Result<ComponentTypeId> {
3536 self.components.get(idx as usize).copied().ok_or_else(|| {
3537 format_err!(
3538 offset,
3539 "unknown component {idx}: component index out of bounds"
3540 )
3541 })
3542 }
3543
3544 fn instance_at(&self, idx: u32, offset: usize) -> Result<ComponentInstanceTypeId> {
3545 self.instances.get(idx as usize).copied().ok_or_else(|| {
3546 format_err!(
3547 offset,
3548 "unknown instance {idx}: instance index out of bounds"
3549 )
3550 })
3551 }
3552
3553 fn value_at(&mut self, idx: u32, offset: usize) -> Result<&ComponentValType> {
3554 match self.values.get_mut(idx as usize) {
3555 Some((ty, used)) if !*used => {
3556 *used = true;
3557 Ok(ty)
3558 }
3559 Some(_) => bail!(offset, "value {idx} cannot be used more than once"),
3560 None => bail!(offset, "unknown value {idx}: value index out of bounds"),
3561 }
3562 }
3563
3564 fn defined_type_at(&self, idx: u32, offset: usize) -> Result<ComponentDefinedTypeId> {
3565 match self.component_type_at(idx, offset)? {
3566 ComponentAnyTypeId::Defined(id) => Ok(id),
3567 _ => bail!(offset, "type index {idx} is not a defined type"),
3568 }
3569 }
3570
3571 fn core_function_at(&self, idx: u32, offset: usize) -> Result<CoreTypeId> {
3572 match self.core_funcs.get(idx as usize) {
3573 Some(id) => Ok(*id),
3574 None => bail!(
3575 offset,
3576 "unknown core function {idx}: function index out of bounds"
3577 ),
3578 }
3579 }
3580
3581 fn module_at(&self, idx: u32, offset: usize) -> Result<ComponentCoreModuleTypeId> {
3582 match self.core_modules.get(idx as usize) {
3583 Some(id) => Ok(*id),
3584 None => bail!(offset, "unknown module {idx}: module index out of bounds"),
3585 }
3586 }
3587
3588 fn core_instance_at(&self, idx: u32, offset: usize) -> Result<ComponentCoreInstanceTypeId> {
3589 match self.core_instances.get(idx as usize) {
3590 Some(id) => Ok(*id),
3591 None => bail!(
3592 offset,
3593 "unknown core instance {idx}: instance index out of bounds"
3594 ),
3595 }
3596 }
3597
3598 fn core_instance_export<'a>(
3599 &self,
3600 instance_index: u32,
3601 name: &str,
3602 types: &'a TypeList,
3603 offset: usize,
3604 ) -> Result<&'a EntityType> {
3605 match types[self.core_instance_at(instance_index, offset)?]
3606 .internal_exports(types)
3607 .get(name)
3608 {
3609 Some(export) => Ok(export),
3610 None => bail!(
3611 offset,
3612 "core instance {instance_index} has no export named `{name}`"
3613 ),
3614 }
3615 }
3616
3617 fn global_at(&self, idx: u32, offset: usize) -> Result<&GlobalType> {
3618 match self.core_globals.get(idx as usize) {
3619 Some(t) => Ok(t),
3620 None => bail!(offset, "unknown global {idx}: global index out of bounds"),
3621 }
3622 }
3623
3624 fn table_at(&self, idx: u32, offset: usize) -> Result<&TableType> {
3625 match self.core_tables.get(idx as usize) {
3626 Some(t) => Ok(t),
3627 None => bail!(offset, "unknown table {idx}: table index out of bounds"),
3628 }
3629 }
3630
3631 fn memory_at(&self, idx: u32, offset: usize) -> Result<&MemoryType> {
3632 match self.core_memories.get(idx as usize) {
3633 Some(t) => Ok(t),
3634 None => bail!(offset, "unknown memory {idx}: memory index out of bounds"),
3635 }
3636 }
3637
3638 /// Completes the translation of this component, performing final
3639 /// validation of its structure.
3640 ///
3641 /// This method is required to be called for translating all components.
3642 /// Internally this will convert local data structures into a
3643 /// `ComponentType` which is suitable to use to describe the type of this
3644 /// component.
3645 pub fn finish(&mut self, types: &TypeAlloc, offset: usize) -> Result<ComponentType> {
3646 let mut ty = ComponentType {
3647 // Inherit some fields based on translation of the component.
3648 info: self.type_info,
3649 imports: self.imports.clone(),
3650 exports: self.exports.clone(),
3651
3652 // This is filled in as a subset of `self.defined_resources`
3653 // depending on what's actually used by the exports. See the
3654 // bottom of this function.
3655 defined_resources: Default::default(),
3656
3657 // These are inherited directly from what was calculated for this
3658 // component.
3659 imported_resources: mem::take(&mut self.imported_resources)
3660 .into_iter()
3661 .collect(),
3662 explicit_resources: mem::take(&mut self.explicit_resources),
3663 };
3664
3665 // Collect all "free variables", or resources, from the imports of this
3666 // component. None of the resources defined within this component can
3667 // be used as part of the exports. This set is then used to reject any
3668 // of `self.defined_resources` which show up.
3669 let mut free = IndexSet::default();
3670 for ty in ty.imports.values() {
3671 types.free_variables_component_entity(ty, &mut free);
3672 }
3673 for (resource, _path) in self.defined_resources.iter() {
3674 // FIXME: this error message is quite opaque and doesn't indicate
3675 // more contextual information such as:
3676 //
3677 // * what was the exported resource found in the imports
3678 // * which import was the resource found within
3679 //
3680 // These are possible to calculate here if necessary, however.
3681 if free.contains(resource) {
3682 bail!(offset, "local resource type found in imports");
3683 }
3684 }
3685
3686 // The next step in validation a component, with respect to resources,
3687 // is to minimize the set of defined resources to only those that
3688 // are actually used by the exports. This weeds out resources that are
3689 // defined, used within a component, and never exported, for example.
3690 //
3691 // The free variables of all exports are inserted into the `free` set
3692 // (which is reused from the imports after clearing it). The defined
3693 // resources calculated for this component are then inserted into this
3694 // type's list of defined resources if it's contained somewhere in
3695 // the free variables.
3696 //
3697 // Note that at the same time all defined resources must be exported,
3698 // somehow, transitively from this component. The `explicit_resources`
3699 // map is consulted for this purpose which lists all explicitly
3700 // exported resources in the component, regardless from whence they
3701 // came. If not present in this map then it's not exported and an error
3702 // is returned.
3703 //
3704 // NB: the "types are exported" check is probably sufficient nowadays
3705 // that the check of the `explicit_resources` map is probably not
3706 // necessary, but it's left here for completeness and out of an
3707 // abundance of caution.
3708 free.clear();
3709 for ty in ty.exports.values() {
3710 types.free_variables_component_entity(ty, &mut free);
3711 }
3712 for (id, _rep) in mem::take(&mut self.defined_resources) {
3713 if !free.contains(&id) {
3714 continue;
3715 }
3716
3717 let path = match ty.explicit_resources.get(&id).cloned() {
3718 Some(path) => path,
3719 // FIXME: this error message is quite opaque and doesn't
3720 // indicate more contextual information such as:
3721 //
3722 // * which resource wasn't found in an export
3723 // * which export has a reference to the resource
3724 //
3725 // These are possible to calculate here if necessary, however.
3726 None => bail!(
3727 offset,
3728 "local resource type found in export but not exported itself"
3729 ),
3730 };
3731
3732 ty.defined_resources.push((id, path));
3733 }
3734
3735 Ok(ty)
3736 }
3737
3738 fn check_value_support(&self, features: &WasmFeatures, offset: usize) -> Result<()> {
3739 if !features.component_model_values() {
3740 bail!(
3741 offset,
3742 "support for component model `value`s is not enabled"
3743 );
3744 }
3745 Ok(())
3746 }
3747}
3748
3749impl InternRecGroup for ComponentState {
3750 fn add_type_id(&mut self, id: CoreTypeId) {
3751 self.core_types.push(ComponentCoreTypeId::Sub(id));
3752 }
3753
3754 fn type_id_at(&self, idx: u32, offset: usize) -> Result<CoreTypeId> {
3755 match self.core_type_at(idx, offset)? {
3756 ComponentCoreTypeId::Sub(id: CoreTypeId) => Ok(id),
3757 ComponentCoreTypeId::Module(_) => {
3758 bail!(offset, "type index {idx} is a module type, not a sub type");
3759 }
3760 }
3761 }
3762
3763 fn types_len(&self) -> u32 {
3764 u32::try_from(self.core_types.len()).unwrap()
3765 }
3766}
3767
3768impl ComponentNameContext {
3769 /// Registers that the resource `id` is named `name` within this context.
3770 fn register(&mut self, name: &str, id: AliasableResourceId) {
3771 let idx = self.all_resource_names.len();
3772 let prev = self.resource_name_map.insert(id, idx);
3773 assert!(
3774 prev.is_none(),
3775 "for {id:?}, inserted {idx:?} but already had {prev:?}"
3776 );
3777 self.all_resource_names.insert(name.to_string());
3778 }
3779
3780 fn validate_extern(
3781 &self,
3782 name: &str,
3783 kind: ExternKind,
3784 ty: &ComponentEntityType,
3785 types: &TypeAlloc,
3786 offset: usize,
3787 kind_names: &mut IndexSet<ComponentName>,
3788 items: &mut IndexMap<String, ComponentEntityType>,
3789 info: &mut TypeInfo,
3790 features: &WasmFeatures,
3791 ) -> Result<()> {
3792 // First validate that `name` is even a valid kebab name, meaning it's
3793 // in kebab-case, is an ID, etc.
3794 let kebab = ComponentName::new_with_features(name, offset, *features)
3795 .with_context(|| format!("{} name `{name}` is not a valid extern name", kind.desc()))?;
3796
3797 if let ExternKind::Export = kind {
3798 match kebab.kind() {
3799 ComponentNameKind::Label(_)
3800 | ComponentNameKind::Method(_)
3801 | ComponentNameKind::Static(_)
3802 | ComponentNameKind::Constructor(_)
3803 | ComponentNameKind::Interface(_) => {}
3804
3805 ComponentNameKind::Hash(_)
3806 | ComponentNameKind::Url(_)
3807 | ComponentNameKind::Dependency(_) => {
3808 bail!(offset, "name `{name}` is not a valid export name")
3809 }
3810 }
3811 }
3812
3813 // Validate that the kebab name, if it has structure such as
3814 // `[method]a.b`, is indeed valid with respect to known resources.
3815 self.validate(&kebab, ty, types, offset)
3816 .with_context(|| format!("{} name `{kebab}` is not valid", kind.desc()))?;
3817
3818 // Top-level kebab-names must all be unique, even between both imports
3819 // and exports ot a component. For those names consult the `kebab_names`
3820 // set.
3821 if let Some(prev) = kind_names.replace(kebab.clone()) {
3822 bail!(
3823 offset,
3824 "{} name `{kebab}` conflicts with previous name `{prev}`",
3825 kind.desc()
3826 );
3827 }
3828
3829 // Otherwise all strings must be unique, regardless of their name, so
3830 // consult the `items` set to ensure that we're not for example
3831 // importing the same interface ID twice.
3832 match items.entry(name.to_string()) {
3833 Entry::Occupied(e) => {
3834 bail!(
3835 offset,
3836 "{kind} name `{name}` conflicts with previous name `{prev}`",
3837 kind = kind.desc(),
3838 prev = e.key(),
3839 );
3840 }
3841 Entry::Vacant(e) => {
3842 e.insert(*ty);
3843 info.combine(ty.info(types), offset)?;
3844 }
3845 }
3846 Ok(())
3847 }
3848
3849 /// Validates that the `name` provided is allowed to have the type `ty`.
3850 fn validate(
3851 &self,
3852 name: &ComponentName,
3853 ty: &ComponentEntityType,
3854 types: &TypeAlloc,
3855 offset: usize,
3856 ) -> Result<()> {
3857 let func = || {
3858 let id = match ty {
3859 ComponentEntityType::Func(id) => *id,
3860 _ => bail!(offset, "item is not a func"),
3861 };
3862 Ok(&types[id])
3863 };
3864 match name.kind() {
3865 // No validation necessary for these styles of names
3866 ComponentNameKind::Label(_)
3867 | ComponentNameKind::Interface(_)
3868 | ComponentNameKind::Url(_)
3869 | ComponentNameKind::Dependency(_)
3870 | ComponentNameKind::Hash(_) => {}
3871
3872 // Constructors must return `(own $resource)` and the `$resource`
3873 // must be named within this context to match `rname`
3874 ComponentNameKind::Constructor(rname) => {
3875 let ty = func()?;
3876 if ty.results.len() != 1 {
3877 bail!(offset, "function should return one value");
3878 }
3879 let ty = ty.results[0].1;
3880 let resource = match ty {
3881 ComponentValType::Primitive(_) => None,
3882 ComponentValType::Type(ty) => match &types[ty] {
3883 ComponentDefinedType::Own(id) => Some(id),
3884 _ => None,
3885 },
3886 };
3887 let resource = match resource {
3888 Some(id) => id,
3889 None => bail!(offset, "function should return `(own $T)`"),
3890 };
3891 self.validate_resource_name(*resource, rname, offset)?;
3892 }
3893
3894 // Methods must take `(param "self" (borrow $resource))` as the
3895 // first argument where `$resources` matches the name `resource` as
3896 // named in this context.
3897 ComponentNameKind::Method(name) => {
3898 let ty = func()?;
3899 if ty.params.len() == 0 {
3900 bail!(offset, "function should have at least one argument");
3901 }
3902 let (pname, pty) = &ty.params[0];
3903 if pname.as_str() != "self" {
3904 bail!(
3905 offset,
3906 "function should have a first argument called `self`",
3907 );
3908 }
3909 let id = match pty {
3910 ComponentValType::Primitive(_) => None,
3911 ComponentValType::Type(ty) => match &types[*ty] {
3912 ComponentDefinedType::Borrow(id) => Some(id),
3913 _ => None,
3914 },
3915 };
3916 let id = match id {
3917 Some(id) => id,
3918 None => bail!(
3919 offset,
3920 "function should take a first argument of `(borrow $T)`"
3921 ),
3922 };
3923 self.validate_resource_name(*id, name.resource(), offset)?;
3924 }
3925
3926 // Static methods don't have much validation beyond that they must
3927 // be a function and the resource name referred to must already be
3928 // in this context.
3929 ComponentNameKind::Static(name) => {
3930 func()?;
3931 if !self.all_resource_names.contains(name.resource().as_str()) {
3932 bail!(offset, "static resource name is not known in this context");
3933 }
3934 }
3935 }
3936
3937 Ok(())
3938 }
3939
3940 fn validate_resource_name(
3941 &self,
3942 id: AliasableResourceId,
3943 name: &KebabStr,
3944 offset: usize,
3945 ) -> Result<()> {
3946 let expected_name_idx = match self.resource_name_map.get(&id) {
3947 Some(idx) => *idx,
3948 None => {
3949 bail!(
3950 offset,
3951 "resource used in function does not have a name in this context"
3952 )
3953 }
3954 };
3955 let expected_name = &self.all_resource_names[expected_name_idx];
3956 if name.as_str() != expected_name {
3957 bail!(
3958 offset,
3959 "function does not match expected \
3960 resource name `{expected_name}`"
3961 );
3962 }
3963 Ok(())
3964 }
3965}
3966
3967use self::append_only::*;
3968
3969mod append_only {
3970 use crate::prelude::IndexMap;
3971 use core::hash::Hash;
3972 use core::ops::Deref;
3973
3974 pub struct IndexMapAppendOnly<K, V>(IndexMap<K, V>);
3975
3976 impl<K, V> IndexMapAppendOnly<K, V>
3977 where
3978 K: Hash + Eq + Ord + PartialEq + Clone,
3979 {
3980 pub fn insert(&mut self, key: K, value: V) {
3981 let prev = self.0.insert(key, value);
3982 assert!(prev.is_none());
3983 }
3984 }
3985
3986 impl<K, V> Deref for IndexMapAppendOnly<K, V> {
3987 type Target = IndexMap<K, V>;
3988 fn deref(&self) -> &IndexMap<K, V> {
3989 &self.0
3990 }
3991 }
3992
3993 impl<K, V> Default for IndexMapAppendOnly<K, V> {
3994 fn default() -> Self {
3995 Self(Default::default())
3996 }
3997 }
3998
3999 impl<K, V> IntoIterator for IndexMapAppendOnly<K, V> {
4000 type IntoIter = <IndexMap<K, V> as IntoIterator>::IntoIter;
4001 type Item = <IndexMap<K, V> as IntoIterator>::Item;
4002 fn into_iter(self) -> Self::IntoIter {
4003 self.0.into_iter()
4004 }
4005 }
4006}
4007