wasmparser/validator/
component.rs

1//! State relating to validating a WebAssembly component.
2
3use super::{
4    check_max, combine_type_sizes,
5    core::Module,
6    types::{
7        ComponentFuncType, ComponentInstanceType, ComponentInstanceTypeKind, ComponentType,
8        ComponentValType, EntityType, InstanceType, KebabString, ModuleType, RecordType, Type,
9        TypeAlloc, TypeId, TypeList, VariantCase,
10    },
11};
12use crate::{
13    limits::*,
14    types::{
15        ComponentDefinedType, ComponentEntityType, InstanceTypeKind, KebabStr, LoweringInfo,
16        TupleType, UnionType, VariantType,
17    },
18    BinaryReaderError, CanonicalOption, ComponentExternalKind, ComponentOuterAliasKind,
19    ComponentTypeRef, ExternalKind, FuncType, GlobalType, InstantiationArgKind, MemoryType, Result,
20    TableType, TypeBounds, ValType, WasmFeatures,
21};
22use indexmap::{map::Entry, IndexMap, IndexSet};
23use std::{collections::HashSet, mem};
24use url::Url;
25
26fn to_kebab_str<'a>(s: &'a str, desc: &str, offset: usize) -> Result<&'a KebabStr> {
27    match KebabStr::new(s) {
28        Some(s) => Ok(s),
29        None => {
30            if s.is_empty() {
31                bail!(offset, "{desc} name cannot be empty");
32            }
33
34            bail!(offset, "{desc} name `{s}` is not in kebab case");
35        }
36    }
37}
38
39fn parse_url(url: &str, offset: usize) -> Result<Option<Url>> {
40    if url.is_empty() {
41        return Ok(None);
42    }
43
44    Url::parse(url)
45        .map(Some)
46        .map_err(|e| BinaryReaderError::new(e.to_string(), offset))
47}
48
49pub(crate) struct ComponentState {
50    // Core index spaces
51    pub core_types: Vec<TypeId>,
52    pub core_modules: Vec<TypeId>,
53    pub core_instances: Vec<TypeId>,
54    pub core_funcs: Vec<TypeId>,
55    pub core_memories: Vec<MemoryType>,
56    pub core_tables: Vec<TableType>,
57    pub core_globals: Vec<GlobalType>,
58    pub core_tags: Vec<TypeId>,
59
60    // Component index spaces
61    pub types: Vec<TypeId>,
62    pub funcs: Vec<TypeId>,
63    pub values: Vec<(ComponentValType, bool)>,
64    pub instances: Vec<TypeId>,
65    pub components: Vec<TypeId>,
66
67    /// A set of all imports and exports since they share the same namespace.
68    pub externs: IndexMap<KebabString, (Option<Url>, ComponentEntityType, ExternKind)>,
69
70    // Note: URL validation requires unique URLs by byte comparison, so
71    // strings are used here and the URLs are not normalized.
72    import_urls: HashSet<String>,
73    export_urls: HashSet<String>,
74
75    has_start: bool,
76    type_size: u32,
77}
78
79pub enum ExternKind {
80    Import,
81    Export,
82}
83
84impl ExternKind {
85    fn desc(&self) -> &'static str {
86        match self {
87            ExternKind::Import => "import",
88            ExternKind::Export => "export",
89        }
90    }
91}
92
93impl ComponentState {
94    pub fn type_count(&self) -> usize {
95        self.core_types.len() + self.types.len()
96    }
97
98    pub fn instance_count(&self) -> usize {
99        self.core_instances.len() + self.instances.len()
100    }
101
102    pub fn function_count(&self) -> usize {
103        self.core_funcs.len() + self.funcs.len()
104    }
105
106    pub fn add_core_type(
107        components: &mut [Self],
108        ty: crate::CoreType,
109        features: &WasmFeatures,
110        types: &mut TypeAlloc,
111        offset: usize,
112        check_limit: bool,
113    ) -> Result<()> {
114        let ty = match ty {
115            crate::CoreType::Func(ty) => Type::Func(ty),
116            crate::CoreType::Module(decls) => Type::Module(Self::create_module_type(
117                components,
118                decls.into_vec(),
119                features,
120                types,
121                offset,
122            )?),
123        };
124
125        let current = components.last_mut().unwrap();
126
127        if check_limit {
128            check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
129        }
130
131        let id = types.push_defined(ty);
132        current.core_types.push(id);
133
134        Ok(())
135    }
136
137    pub fn add_core_module(
138        &mut self,
139        module: &Module,
140        types: &mut TypeAlloc,
141        offset: usize,
142    ) -> Result<()> {
143        let imports = module.imports_for_module_type(offset)?;
144
145        // We have to clone the module's imports and exports here
146        // because we cannot take the data out of the `MaybeOwned`
147        // as it might be shared with a function validator.
148        let ty = Type::Module(ModuleType {
149            type_size: module.type_size,
150            imports,
151            exports: module.exports.clone(),
152        });
153
154        let id = types.push_anon(ty);
155        self.core_modules.push(id);
156
157        Ok(())
158    }
159
160    pub fn add_core_instance(
161        &mut self,
162        instance: crate::Instance,
163        types: &mut TypeAlloc,
164        offset: usize,
165    ) -> Result<()> {
166        let instance = match instance {
167            crate::Instance::Instantiate { module_index, args } => {
168                self.instantiate_module(module_index, args.into_vec(), types, offset)?
169            }
170            crate::Instance::FromExports(exports) => {
171                self.instantiate_core_exports(exports.into_vec(), types, offset)?
172            }
173        };
174
175        self.core_instances.push(instance);
176
177        Ok(())
178    }
179
180    pub fn add_type(
181        components: &mut Vec<Self>,
182        ty: crate::ComponentType,
183        features: &WasmFeatures,
184        types: &mut TypeAlloc,
185        offset: usize,
186        check_limit: bool,
187    ) -> Result<()> {
188        assert!(!components.is_empty());
189        let ty = match ty {
190            crate::ComponentType::Defined(ty) => Type::Defined(
191                components
192                    .last_mut()
193                    .unwrap()
194                    .create_defined_type(ty, types, offset)?,
195            ),
196            crate::ComponentType::Func(ty) => Type::ComponentFunc(
197                components
198                    .last_mut()
199                    .unwrap()
200                    .create_function_type(ty, types, offset)?,
201            ),
202            crate::ComponentType::Component(decls) => Type::Component(Self::create_component_type(
203                components,
204                decls.into_vec(),
205                features,
206                types,
207                offset,
208            )?),
209            crate::ComponentType::Instance(decls) => Type::ComponentInstance(
210                Self::create_instance_type(components, decls.into_vec(), features, types, offset)?,
211            ),
212        };
213
214        let current = components.last_mut().unwrap();
215        if check_limit {
216            check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
217        }
218
219        let id = types.push_defined(ty);
220        current.types.push(id);
221
222        Ok(())
223    }
224
225    pub fn add_import(
226        &mut self,
227        import: crate::ComponentImport,
228        types: &mut TypeAlloc,
229        offset: usize,
230    ) -> Result<()> {
231        let entity = self.check_type_ref(&import.ty, types, offset)?;
232        self.add_entity(entity, false, offset)?;
233        let name = to_kebab_str(import.name, "import", offset)?;
234
235        match self.externs.entry(name.to_owned()) {
236            Entry::Occupied(e) => {
237                bail!(
238                    offset,
239                    "import name `{name}` conflicts with previous {desc} name `{prev}`",
240                    name = import.name,
241                    prev = e.key(),
242                    desc = e.get().2.desc(),
243                );
244            }
245            Entry::Vacant(e) => {
246                let url = parse_url(import.url, offset)?;
247                if let Some(url) = url.as_ref() {
248                    if !self.import_urls.insert(url.to_string()) {
249                        bail!(offset, "duplicate import URL `{url}`");
250                    }
251                }
252
253                self.type_size = combine_type_sizes(self.type_size, entity.type_size(), offset)?;
254                e.insert((url, entity, ExternKind::Import));
255            }
256        }
257
258        Ok(())
259    }
260
261    fn add_entity(
262        &mut self,
263        ty: ComponentEntityType,
264        value_used: bool,
265        offset: usize,
266    ) -> Result<()> {
267        let (len, max, desc) = match ty {
268            ComponentEntityType::Module(id) => {
269                self.core_modules.push(id);
270                (self.core_modules.len(), MAX_WASM_MODULES, "modules")
271            }
272            ComponentEntityType::Component(id) => {
273                self.components.push(id);
274                (self.components.len(), MAX_WASM_COMPONENTS, "components")
275            }
276            ComponentEntityType::Instance(id) => {
277                self.instances.push(id);
278                (self.instance_count(), MAX_WASM_INSTANCES, "instances")
279            }
280            ComponentEntityType::Func(id) => {
281                self.funcs.push(id);
282                (self.function_count(), MAX_WASM_FUNCTIONS, "functions")
283            }
284            ComponentEntityType::Value(ty) => {
285                self.values.push((ty, value_used));
286                (self.values.len(), MAX_WASM_VALUES, "values")
287            }
288            ComponentEntityType::Type { created, .. } => {
289                self.types.push(created);
290                (self.types.len(), MAX_WASM_TYPES, "types")
291            }
292        };
293
294        check_max(len, 0, max, desc, offset)?;
295        Ok(())
296    }
297
298    pub fn add_export(
299        &mut self,
300        name: &str,
301        url: &str,
302        ty: ComponentEntityType,
303        offset: usize,
304        check_limit: bool,
305    ) -> Result<()> {
306        if check_limit {
307            check_max(
308                self.externs.len(),
309                1,
310                MAX_WASM_EXPORTS,
311                "imports and exports",
312                offset,
313            )?;
314        }
315        self.add_entity(ty, true, offset)?;
316
317        let name = to_kebab_str(name, "export", offset)?;
318
319        match self.externs.entry(name.to_owned()) {
320            Entry::Occupied(e) => {
321                bail!(
322                    offset,
323                    "export name `{name}` conflicts with previous {desc} name `{prev}`",
324                    prev = e.key(),
325                    desc = e.get().2.desc(),
326                );
327            }
328            Entry::Vacant(e) => {
329                let url = parse_url(url, offset)?;
330                if let Some(url) = url.as_ref() {
331                    if !self.export_urls.insert(url.to_string()) {
332                        bail!(offset, "duplicate export URL `{url}`");
333                    }
334                }
335
336                self.type_size = combine_type_sizes(self.type_size, ty.type_size(), offset)?;
337                e.insert((url, ty, ExternKind::Export));
338            }
339        }
340
341        Ok(())
342    }
343
344    pub fn lift_function(
345        &mut self,
346        core_func_index: u32,
347        type_index: u32,
348        options: Vec<CanonicalOption>,
349        types: &TypeList,
350        offset: usize,
351    ) -> Result<()> {
352        let ty = self.function_type_at(type_index, types, offset)?;
353        let core_ty = types[self.core_function_at(core_func_index, offset)?]
354            .as_func_type()
355            .unwrap();
356
357        // Lifting a function is for an export, so match the expected canonical ABI
358        // export signature
359        let info = ty.lower(types, false);
360        self.check_options(Some(core_ty), &info, &options, types, offset)?;
361
362        if core_ty.params() != info.params.as_slice() {
363            bail!(
364                offset,
365                "lowered parameter types `{:?}` do not match parameter types \
366                 `{:?}` of core function {core_func_index}",
367                info.params.as_slice(),
368                core_ty.params(),
369            );
370        }
371
372        if core_ty.results() != info.results.as_slice() {
373            bail!(
374                offset,
375                "lowered result types `{:?}` do not match result types \
376                 `{:?}` of core function {core_func_index}",
377                info.results.as_slice(),
378                core_ty.results()
379            );
380        }
381
382        self.funcs.push(self.types[type_index as usize]);
383
384        Ok(())
385    }
386
387    pub fn lower_function(
388        &mut self,
389        func_index: u32,
390        options: Vec<CanonicalOption>,
391        types: &mut TypeAlloc,
392        offset: usize,
393    ) -> Result<()> {
394        let ty = types[self.function_at(func_index, offset)?]
395            .as_component_func_type()
396            .unwrap();
397
398        // Lowering a function is for an import, so use a function type that matches
399        // the expected canonical ABI import signature.
400        let info = ty.lower(types, true);
401
402        self.check_options(None, &info, &options, types, offset)?;
403
404        let lowered_ty = Type::Func(info.into_func_type());
405
406        let id = types.push_anon(lowered_ty);
407        self.core_funcs.push(id);
408
409        Ok(())
410    }
411
412    pub fn add_component(&mut self, component: &mut Self, types: &mut TypeAlloc) {
413        let ty = Type::Component(component.take_component_type());
414        let id = types.push_anon(ty);
415        self.components.push(id);
416    }
417
418    pub fn add_instance(
419        &mut self,
420        instance: crate::ComponentInstance,
421        types: &mut TypeAlloc,
422        offset: usize,
423    ) -> Result<()> {
424        let instance = match instance {
425            crate::ComponentInstance::Instantiate {
426                component_index,
427                args,
428            } => self.instantiate_component(component_index, args.into_vec(), types, offset)?,
429            crate::ComponentInstance::FromExports(exports) => {
430                self.instantiate_exports(exports.into_vec(), types, offset)?
431            }
432        };
433
434        self.instances.push(instance);
435
436        Ok(())
437    }
438
439    pub fn add_alias(
440        components: &mut [Self],
441        alias: crate::ComponentAlias,
442        types: &mut TypeAlloc,
443        offset: usize,
444    ) -> Result<()> {
445        match alias {
446            crate::ComponentAlias::InstanceExport {
447                instance_index,
448                kind,
449                name,
450            } => components.last_mut().unwrap().alias_instance_export(
451                instance_index,
452                kind,
453                name,
454                types,
455                offset,
456            ),
457            crate::ComponentAlias::CoreInstanceExport {
458                instance_index,
459                kind,
460                name,
461            } => components.last_mut().unwrap().alias_core_instance_export(
462                instance_index,
463                kind,
464                name,
465                types,
466                offset,
467            ),
468            crate::ComponentAlias::Outer { kind, count, index } => match kind {
469                ComponentOuterAliasKind::CoreModule => {
470                    Self::alias_module(components, count, index, offset)
471                }
472                ComponentOuterAliasKind::CoreType => {
473                    Self::alias_core_type(components, count, index, types, offset)
474                }
475                ComponentOuterAliasKind::Type => {
476                    Self::alias_type(components, count, index, types, offset)
477                }
478                ComponentOuterAliasKind::Component => {
479                    Self::alias_component(components, count, index, offset)
480                }
481            },
482        }
483    }
484
485    pub fn add_start(
486        &mut self,
487        func_index: u32,
488        args: &[u32],
489        results: u32,
490        types: &TypeList,
491        offset: usize,
492    ) -> Result<()> {
493        if self.has_start {
494            return Err(BinaryReaderError::new(
495                "component cannot have more than one start function",
496                offset,
497            ));
498        }
499
500        let ft = types[self.function_at(func_index, offset)?]
501            .as_component_func_type()
502            .unwrap();
503
504        if ft.params.len() != args.len() {
505            bail!(
506                offset,
507                "component start function requires {} arguments but was given {}",
508                ft.params.len(),
509                args.len()
510            );
511        }
512
513        if ft.results.len() as u32 != results {
514            bail!(
515                offset,
516                "component start function has a result count of {results} \
517                 but the function type has a result count of {type_results}",
518                type_results = ft.results.len(),
519            );
520        }
521
522        for (i, ((_, ty), arg)) in ft.params.iter().zip(args).enumerate() {
523            // Ensure the value's type is a subtype of the parameter type
524            if !ComponentValType::internal_is_subtype_of(
525                self.value_at(*arg, offset)?,
526                types,
527                ty,
528                types,
529            ) {
530                bail!(
531                    offset,
532                    "value type mismatch for component start function argument {i}"
533                );
534            }
535        }
536
537        for (_, ty) in ft.results.iter() {
538            self.values.push((*ty, false));
539        }
540
541        self.has_start = true;
542
543        Ok(())
544    }
545
546    fn check_options(
547        &self,
548        core_ty: Option<&FuncType>,
549        info: &LoweringInfo,
550        options: &[CanonicalOption],
551        types: &TypeList,
552        offset: usize,
553    ) -> Result<()> {
554        fn display(option: CanonicalOption) -> &'static str {
555            match option {
556                CanonicalOption::UTF8 => "utf8",
557                CanonicalOption::UTF16 => "utf16",
558                CanonicalOption::CompactUTF16 => "latin1-utf16",
559                CanonicalOption::Memory(_) => "memory",
560                CanonicalOption::Realloc(_) => "realloc",
561                CanonicalOption::PostReturn(_) => "post-return",
562            }
563        }
564
565        let mut encoding = None;
566        let mut memory = None;
567        let mut realloc = None;
568        let mut post_return = None;
569
570        for option in options {
571            match option {
572                CanonicalOption::UTF8 | CanonicalOption::UTF16 | CanonicalOption::CompactUTF16 => {
573                    match encoding {
574                        Some(existing) => {
575                            bail!(
576                                offset,
577                                "canonical encoding option `{}` conflicts with option `{}`",
578                                display(existing),
579                                display(*option),
580                            )
581                        }
582                        None => encoding = Some(*option),
583                    }
584                }
585                CanonicalOption::Memory(idx) => {
586                    memory = match memory {
587                        None => {
588                            self.memory_at(*idx, offset)?;
589                            Some(*idx)
590                        }
591                        Some(_) => {
592                            return Err(BinaryReaderError::new(
593                                "canonical option `memory` is specified more than once",
594                                offset,
595                            ))
596                        }
597                    }
598                }
599                CanonicalOption::Realloc(idx) => {
600                    realloc = match realloc {
601                        None => {
602                            let ty = types[self.core_function_at(*idx, offset)?]
603                                .as_func_type()
604                                .unwrap();
605                            if ty.params()
606                                != [ValType::I32, ValType::I32, ValType::I32, ValType::I32]
607                                || ty.results() != [ValType::I32]
608                            {
609                                return Err(BinaryReaderError::new(
610                                    "canonical option `realloc` uses a core function with an incorrect signature",
611                                    offset,
612                                ));
613                            }
614                            Some(*idx)
615                        }
616                        Some(_) => {
617                            return Err(BinaryReaderError::new(
618                                "canonical option `realloc` is specified more than once",
619                                offset,
620                            ))
621                        }
622                    }
623                }
624                CanonicalOption::PostReturn(idx) => {
625                    post_return = match post_return {
626                        None => {
627                            let core_ty = core_ty.ok_or_else(|| {
628                                BinaryReaderError::new(
629                                    "canonical option `post-return` cannot be specified for lowerings",
630                                    offset,
631                                )
632                            })?;
633
634                            let ty = types[self.core_function_at(*idx, offset)?]
635                                .as_func_type()
636                                .unwrap();
637
638                            if ty.params() != core_ty.results() || !ty.results().is_empty() {
639                                return Err(BinaryReaderError::new(
640                                    "canonical option `post-return` uses a core function with an incorrect signature",
641                                    offset,
642                                ));
643                            }
644                            Some(*idx)
645                        }
646                        Some(_) => {
647                            return Err(BinaryReaderError::new(
648                                "canonical option `post-return` is specified more than once",
649                                offset,
650                            ))
651                        }
652                    }
653                }
654            }
655        }
656
657        if info.requires_memory && memory.is_none() {
658            return Err(BinaryReaderError::new(
659                "canonical option `memory` is required",
660                offset,
661            ));
662        }
663
664        if info.requires_realloc && realloc.is_none() {
665            return Err(BinaryReaderError::new(
666                "canonical option `realloc` is required",
667                offset,
668            ));
669        }
670
671        Ok(())
672    }
673
674    fn check_type_ref(
675        &self,
676        ty: &ComponentTypeRef,
677        types: &mut TypeAlloc,
678        offset: usize,
679    ) -> Result<ComponentEntityType> {
680        Ok(match ty {
681            ComponentTypeRef::Module(index) => {
682                let id = self.type_at(*index, true, offset)?;
683                types[id].as_module_type().ok_or_else(|| {
684                    format_err!(offset, "core type index {index} is not a module type")
685                })?;
686                ComponentEntityType::Module(id)
687            }
688            ComponentTypeRef::Func(index) => {
689                let id = self.type_at(*index, false, offset)?;
690                types[id].as_component_func_type().ok_or_else(|| {
691                    format_err!(offset, "type index {index} is not a function type")
692                })?;
693                ComponentEntityType::Func(id)
694            }
695            ComponentTypeRef::Value(ty) => {
696                let ty = match ty {
697                    crate::ComponentValType::Primitive(ty) => ComponentValType::Primitive(*ty),
698                    crate::ComponentValType::Type(index) => {
699                        ComponentValType::Type(self.defined_type_at(*index, types, offset)?)
700                    }
701                };
702                ComponentEntityType::Value(ty)
703            }
704            ComponentTypeRef::Type(TypeBounds::Eq, index) => {
705                let referenced = self.type_at(*index, false, offset)?;
706                let created = types.with_unique(referenced);
707                ComponentEntityType::Type {
708                    referenced,
709                    created,
710                }
711            }
712            ComponentTypeRef::Instance(index) => {
713                let id = self.type_at(*index, false, offset)?;
714                types[id].as_component_instance_type().ok_or_else(|| {
715                    format_err!(offset, "type index {index} is not an instance type")
716                })?;
717                ComponentEntityType::Instance(id)
718            }
719            ComponentTypeRef::Component(index) => {
720                let id = self.type_at(*index, false, offset)?;
721                types[id].as_component_type().ok_or_else(|| {
722                    format_err!(offset, "type index {index} is not a component type")
723                })?;
724                ComponentEntityType::Component(id)
725            }
726        })
727    }
728
729    pub fn export_to_entity_type(
730        &mut self,
731        export: &crate::ComponentExport,
732        types: &mut TypeAlloc,
733        offset: usize,
734    ) -> Result<ComponentEntityType> {
735        let actual = match export.kind {
736            ComponentExternalKind::Module => {
737                ComponentEntityType::Module(self.module_at(export.index, offset)?)
738            }
739            ComponentExternalKind::Func => {
740                ComponentEntityType::Func(self.function_at(export.index, offset)?)
741            }
742            ComponentExternalKind::Value => {
743                ComponentEntityType::Value(*self.value_at(export.index, offset)?)
744            }
745            ComponentExternalKind::Type => {
746                let referenced = self.type_at(export.index, false, offset)?;
747                let created = types.with_unique(referenced);
748                ComponentEntityType::Type {
749                    referenced,
750                    created,
751                }
752            }
753            ComponentExternalKind::Instance => {
754                ComponentEntityType::Instance(self.instance_at(export.index, offset)?)
755            }
756            ComponentExternalKind::Component => {
757                ComponentEntityType::Component(self.component_at(export.index, offset)?)
758            }
759        };
760
761        let ascribed = match &export.ty {
762            Some(ty) => self.check_type_ref(ty, types, offset)?,
763            None => return Ok(actual),
764        };
765
766        if !ComponentEntityType::internal_is_subtype_of(&actual, types, &ascribed, types) {
767            bail!(
768                offset,
769                "ascribed type of export is not compatible with item's type"
770            );
771        }
772
773        Ok(ascribed)
774    }
775
776    fn create_module_type(
777        components: &[Self],
778        decls: Vec<crate::ModuleTypeDeclaration>,
779        features: &WasmFeatures,
780        types: &mut TypeAlloc,
781        offset: usize,
782    ) -> Result<ModuleType> {
783        let mut state = Module::default();
784
785        for decl in decls {
786            match decl {
787                crate::ModuleTypeDeclaration::Type(ty) => {
788                    state.add_type(ty, features, types, offset, true)?;
789                }
790                crate::ModuleTypeDeclaration::Export { name, ty } => {
791                    let ty = state.check_type_ref(&ty, features, types, offset)?;
792                    state.add_export(name, ty, features, offset, true)?;
793                }
794                crate::ModuleTypeDeclaration::OuterAlias { kind, count, index } => {
795                    if count > 1 {
796                        return Err(BinaryReaderError::new(
797                                    "outer type aliases in module type declarations are limited to a maximum count of 1",
798                                    offset,
799                                ));
800                    }
801                    match kind {
802                        crate::OuterAliasKind::Type => {
803                            let ty = if count == 0 {
804                                // Local alias, check the local module state
805                                state.type_at(index, offset)?
806                            } else {
807                                // Otherwise, check the enclosing component state
808                                let component =
809                                    Self::check_alias_count(components, count - 1, offset)?;
810                                component.type_at(index, true, offset)?
811                            };
812
813                            check_max(state.types.len(), 1, MAX_WASM_TYPES, "types", offset)?;
814
815                            state.types.push(ty);
816                        }
817                    }
818                }
819                crate::ModuleTypeDeclaration::Import(import) => {
820                    state.add_import(import, features, types, offset)?;
821                }
822            }
823        }
824
825        let imports = state.imports_for_module_type(offset)?;
826
827        Ok(ModuleType {
828            type_size: state.type_size,
829            imports,
830            exports: state.exports,
831        })
832    }
833
834    fn create_component_type(
835        components: &mut Vec<Self>,
836        decls: Vec<crate::ComponentTypeDeclaration>,
837        features: &WasmFeatures,
838        types: &mut TypeAlloc,
839        offset: usize,
840    ) -> Result<ComponentType> {
841        components.push(ComponentState::default());
842
843        for decl in decls {
844            match decl {
845                crate::ComponentTypeDeclaration::CoreType(ty) => {
846                    Self::add_core_type(components, ty, features, types, offset, true)?;
847                }
848                crate::ComponentTypeDeclaration::Type(ty) => {
849                    Self::add_type(components, ty, features, types, offset, true)?;
850                }
851                crate::ComponentTypeDeclaration::Export { name, url, ty } => {
852                    let current = components.last_mut().unwrap();
853                    let ty = current.check_type_ref(&ty, types, offset)?;
854                    current.add_export(name, url, ty, offset, true)?;
855                }
856                crate::ComponentTypeDeclaration::Import(import) => {
857                    components
858                        .last_mut()
859                        .unwrap()
860                        .add_import(import, types, offset)?;
861                }
862                crate::ComponentTypeDeclaration::Alias(alias) => {
863                    Self::add_alias(components, alias, types, offset)?;
864                }
865            };
866        }
867
868        let mut state = components.pop().unwrap();
869
870        Ok(state.take_component_type())
871    }
872
873    fn create_instance_type(
874        components: &mut Vec<Self>,
875        decls: Vec<crate::InstanceTypeDeclaration>,
876        features: &WasmFeatures,
877        types: &mut TypeAlloc,
878        offset: usize,
879    ) -> Result<ComponentInstanceType> {
880        components.push(ComponentState::default());
881
882        for decl in decls {
883            match decl {
884                crate::InstanceTypeDeclaration::CoreType(ty) => {
885                    Self::add_core_type(components, ty, features, types, offset, true)?;
886                }
887                crate::InstanceTypeDeclaration::Type(ty) => {
888                    Self::add_type(components, ty, features, types, offset, true)?;
889                }
890                crate::InstanceTypeDeclaration::Export { name, url, ty } => {
891                    let current = components.last_mut().unwrap();
892                    let ty = current.check_type_ref(&ty, types, offset)?;
893                    current.add_export(name, url, ty, offset, true)?;
894                }
895                crate::InstanceTypeDeclaration::Alias(alias) => {
896                    Self::add_alias(components, alias, types, offset)?;
897                }
898            };
899        }
900
901        let state = components.pop().unwrap();
902
903        Ok(ComponentInstanceType {
904            type_size: state.type_size,
905            kind: ComponentInstanceTypeKind::Defined(
906                state
907                    .externs
908                    .into_iter()
909                    .filter_map(|(name, (url, ty, kind))| match kind {
910                        ExternKind::Export => Some((name, (url, ty))),
911                        ExternKind::Import => None,
912                    })
913                    .collect(),
914            ),
915        })
916    }
917
918    fn create_function_type(
919        &self,
920        ty: crate::ComponentFuncType,
921        types: &TypeList,
922        offset: usize,
923    ) -> Result<ComponentFuncType> {
924        let mut type_size = 1;
925
926        let mut set =
927            HashSet::with_capacity(std::cmp::max(ty.params.len(), ty.results.type_count()));
928
929        let params = ty
930            .params
931            .iter()
932            .map(|(name, ty)| {
933                let name = to_kebab_str(name, "function parameter", offset)?;
934                if !set.insert(name) {
935                    bail!(
936                        offset,
937                        "function parameter name `{name}` conflicts with previous parameter name `{prev}`",
938                        prev = set.get(&name).unwrap(),
939                    );
940                }
941
942                let ty = self.create_component_val_type(*ty, types, offset)?;
943                type_size = combine_type_sizes(type_size, ty.type_size(), offset)?;
944                Ok((name.to_owned(), ty))
945            })
946            .collect::<Result<_>>()?;
947
948        set.clear();
949
950        let results = ty
951            .results
952            .iter()
953            .map(|(name, ty)| {
954                let name = name
955                    .map(|name| {
956                        let name = to_kebab_str(name, "function result", offset)?;
957                        if !set.insert(name) {
958                            bail!(
959                                offset,
960                                "function result name `{name}` conflicts with previous result name `{prev}`",
961                                prev = set.get(name).unwrap(),
962                            );
963                        }
964
965                        Ok(name.to_owned())
966                    })
967                    .transpose()?;
968
969                let ty = self.create_component_val_type(*ty, types, offset)?;
970                type_size = combine_type_sizes(type_size, ty.type_size(), offset)?;
971                Ok((name, ty))
972            })
973            .collect::<Result<_>>()?;
974
975        Ok(ComponentFuncType {
976            type_size,
977            params,
978            results,
979        })
980    }
981
982    fn instantiate_module(
983        &self,
984        module_index: u32,
985        module_args: Vec<crate::InstantiationArg>,
986        types: &mut TypeAlloc,
987        offset: usize,
988    ) -> Result<TypeId> {
989        fn insert_arg<'a>(
990            name: &'a str,
991            arg: &'a InstanceType,
992            args: &mut IndexMap<&'a str, &'a InstanceType>,
993            offset: usize,
994        ) -> Result<()> {
995            if args.insert(name, arg).is_some() {
996                bail!(
997                    offset,
998                    "duplicate module instantiation argument named `{name}`"
999                );
1000            }
1001
1002            Ok(())
1003        }
1004
1005        let module_type_id = self.module_at(module_index, offset)?;
1006        let mut args = IndexMap::new();
1007
1008        // Populate the arguments
1009        for module_arg in module_args {
1010            match module_arg.kind {
1011                InstantiationArgKind::Instance => {
1012                    let instance_type = types[self.core_instance_at(module_arg.index, offset)?]
1013                        .as_instance_type()
1014                        .unwrap();
1015                    insert_arg(module_arg.name, instance_type, &mut args, offset)?;
1016                }
1017            }
1018        }
1019
1020        // Validate the arguments
1021        let module_type = types[module_type_id].as_module_type().unwrap();
1022        for ((module, name), expected) in module_type.imports.iter() {
1023            let instance = args.get(module.as_str()).ok_or_else(|| {
1024                format_err!(
1025                    offset,
1026                    "missing module instantiation argument named `{module}`"
1027                )
1028            })?;
1029
1030            let arg = instance
1031                .internal_exports(types)
1032                .get(name.as_str())
1033                .ok_or_else(|| {
1034                    format_err!(
1035                        offset,
1036                        "module instantiation argument `{module}` does not \
1037                         export an item named `{name}`",
1038                    )
1039                })?;
1040
1041            match (arg, expected) {
1042                (EntityType::Func(_), EntityType::Func(_))
1043                | (EntityType::Table(_), EntityType::Table(_))
1044                | (EntityType::Memory(_), EntityType::Memory(_))
1045                | (EntityType::Global(_), EntityType::Global(_))
1046                | (EntityType::Tag(_), EntityType::Tag(_)) => {}
1047                _ => {
1048                    bail!(
1049                        offset,
1050                        "module instantiation argument `{module}` exports \
1051                         an item named `{name}` but it is not a {}",
1052                        expected.desc()
1053                    )
1054                }
1055            }
1056
1057            if !EntityType::internal_is_subtype_of(arg, types, expected, types) {
1058                bail!(
1059                    offset,
1060                    "{} type mismatch for export `{name}` of module \
1061                     instantiation argument `{module}`",
1062                    expected.desc(),
1063                );
1064            }
1065        }
1066
1067        let ty = Type::Instance(InstanceType {
1068            type_size: module_type
1069                .exports
1070                .iter()
1071                .fold(1, |acc, (_, ty)| acc + ty.type_size()),
1072            kind: InstanceTypeKind::Instantiated(module_type_id),
1073        });
1074
1075        Ok(types.push_anon(ty))
1076    }
1077
1078    fn instantiate_component(
1079        &mut self,
1080        component_index: u32,
1081        component_args: Vec<crate::ComponentInstantiationArg>,
1082        types: &mut TypeAlloc,
1083        offset: usize,
1084    ) -> Result<TypeId> {
1085        fn insert_arg<'a>(
1086            name: &'a str,
1087            arg: ComponentEntityType,
1088            args: &mut IndexMap<&'a KebabStr, ComponentEntityType>,
1089            offset: usize,
1090        ) -> Result<()> {
1091            let name = to_kebab_str(name, "instantiation argument", offset)?;
1092            match args.entry(name) {
1093                Entry::Occupied(e) => {
1094                    bail!(
1095                        offset,
1096                        "instantiation argument `{name}` conflicts with previous argument `{prev}`",
1097                        prev = e.key()
1098                    );
1099                }
1100                Entry::Vacant(e) => {
1101                    e.insert(arg);
1102                }
1103            }
1104
1105            Ok(())
1106        }
1107
1108        let component_type_id = self.component_at(component_index, offset)?;
1109        let mut args = IndexMap::new();
1110
1111        // Populate the arguments
1112        for component_arg in component_args {
1113            match component_arg.kind {
1114                ComponentExternalKind::Module => {
1115                    insert_arg(
1116                        component_arg.name,
1117                        ComponentEntityType::Module(self.module_at(component_arg.index, offset)?),
1118                        &mut args,
1119                        offset,
1120                    )?;
1121                }
1122                ComponentExternalKind::Component => {
1123                    insert_arg(
1124                        component_arg.name,
1125                        ComponentEntityType::Component(
1126                            self.component_at(component_arg.index, offset)?,
1127                        ),
1128                        &mut args,
1129                        offset,
1130                    )?;
1131                }
1132                ComponentExternalKind::Instance => {
1133                    insert_arg(
1134                        component_arg.name,
1135                        ComponentEntityType::Instance(
1136                            self.instance_at(component_arg.index, offset)?,
1137                        ),
1138                        &mut args,
1139                        offset,
1140                    )?;
1141                }
1142                ComponentExternalKind::Func => {
1143                    insert_arg(
1144                        component_arg.name,
1145                        ComponentEntityType::Func(self.function_at(component_arg.index, offset)?),
1146                        &mut args,
1147                        offset,
1148                    )?;
1149                }
1150                ComponentExternalKind::Value => {
1151                    insert_arg(
1152                        component_arg.name,
1153                        ComponentEntityType::Value(*self.value_at(component_arg.index, offset)?),
1154                        &mut args,
1155                        offset,
1156                    )?;
1157                }
1158                ComponentExternalKind::Type => {
1159                    let ty = self.type_at(component_arg.index, false, offset)?;
1160                    insert_arg(
1161                        component_arg.name,
1162                        ComponentEntityType::Type {
1163                            referenced: ty,
1164                            created: ty,
1165                        },
1166                        &mut args,
1167                        offset,
1168                    )?;
1169                }
1170            }
1171        }
1172
1173        // Validate the arguments
1174        let component_type = types[component_type_id].as_component_type().unwrap();
1175        for (name, (_, expected)) in component_type.imports.iter() {
1176            match args.get(&name.as_kebab_str()) {
1177                Some(arg) => {
1178                    match (arg, expected) {
1179                        (ComponentEntityType::Module(_), ComponentEntityType::Module(_))
1180                        | (ComponentEntityType::Component(_), ComponentEntityType::Component(_))
1181                        | (ComponentEntityType::Instance(_), ComponentEntityType::Instance(_))
1182                        | (ComponentEntityType::Func(_), ComponentEntityType::Func(_))
1183                        | (ComponentEntityType::Value(_), ComponentEntityType::Value(_))
1184                        | (ComponentEntityType::Type { .. }, ComponentEntityType::Type { .. }) => {}
1185                        _ => {
1186                            bail!(
1187                                offset,
1188                                "expected component instantiation argument `{name}` to be a {desc}",
1189                                desc = expected.desc()
1190                            )
1191                        }
1192                    };
1193
1194                    if !ComponentEntityType::internal_is_subtype_of(arg, types, expected, types) {
1195                        bail!(
1196                            offset,
1197                            "type mismatch for component instantiation argument `{name}`"
1198                        );
1199                    }
1200                }
1201                None => {
1202                    bail!(
1203                        offset,
1204                        "missing component instantiation argument named `{name}`"
1205                    );
1206                }
1207            }
1208        }
1209
1210        let ty = Type::ComponentInstance(ComponentInstanceType {
1211            type_size: component_type
1212                .exports
1213                .iter()
1214                .fold(1, |acc, (_, (_, ty))| acc + ty.type_size()),
1215            kind: ComponentInstanceTypeKind::Instantiated(component_type_id),
1216        });
1217
1218        Ok(types.push_anon(ty))
1219    }
1220
1221    fn instantiate_exports(
1222        &mut self,
1223        exports: Vec<crate::ComponentExport>,
1224        types: &mut TypeAlloc,
1225        offset: usize,
1226    ) -> Result<TypeId> {
1227        fn insert_export(
1228            name: &str,
1229            export: ComponentEntityType,
1230            exports: &mut IndexMap<KebabString, (Option<Url>, ComponentEntityType)>,
1231            type_size: &mut u32,
1232            offset: usize,
1233        ) -> Result<()> {
1234            let name = to_kebab_str(name, "instance export", offset)?;
1235            match exports.entry(name.to_owned()) {
1236                Entry::Occupied(e) => bail!(
1237                    offset,
1238                    "instance export name `{name}` conflicts with previous export name `{prev}`",
1239                    prev = e.key()
1240                ),
1241                Entry::Vacant(e) => {
1242                    *type_size = combine_type_sizes(*type_size, export.type_size(), offset)?;
1243                    e.insert((None, export));
1244                }
1245            }
1246
1247            Ok(())
1248        }
1249
1250        let mut type_size = 1;
1251        let mut inst_exports = IndexMap::new();
1252        for export in exports {
1253            assert!(export.ty.is_none());
1254            match export.kind {
1255                ComponentExternalKind::Module => {
1256                    insert_export(
1257                        export.name,
1258                        ComponentEntityType::Module(self.module_at(export.index, offset)?),
1259                        &mut inst_exports,
1260                        &mut type_size,
1261                        offset,
1262                    )?;
1263                }
1264                ComponentExternalKind::Component => {
1265                    insert_export(
1266                        export.name,
1267                        ComponentEntityType::Component(self.component_at(export.index, offset)?),
1268                        &mut inst_exports,
1269                        &mut type_size,
1270                        offset,
1271                    )?;
1272                }
1273                ComponentExternalKind::Instance => {
1274                    insert_export(
1275                        export.name,
1276                        ComponentEntityType::Instance(self.instance_at(export.index, offset)?),
1277                        &mut inst_exports,
1278                        &mut type_size,
1279                        offset,
1280                    )?;
1281                }
1282                ComponentExternalKind::Func => {
1283                    insert_export(
1284                        export.name,
1285                        ComponentEntityType::Func(self.function_at(export.index, offset)?),
1286                        &mut inst_exports,
1287                        &mut type_size,
1288                        offset,
1289                    )?;
1290                }
1291                ComponentExternalKind::Value => {
1292                    insert_export(
1293                        export.name,
1294                        ComponentEntityType::Value(*self.value_at(export.index, offset)?),
1295                        &mut inst_exports,
1296                        &mut type_size,
1297                        offset,
1298                    )?;
1299                }
1300                ComponentExternalKind::Type => {
1301                    let ty = self.type_at(export.index, false, offset)?;
1302                    insert_export(
1303                        export.name,
1304                        ComponentEntityType::Type {
1305                            referenced: ty,
1306                            // The created type index here isn't used anywhere
1307                            // in index spaces because a "bag of exports"
1308                            // doesn't build up its own index spaces. Just fill
1309                            // in the same index here in this case as what's
1310                            // referenced.
1311                            created: ty,
1312                        },
1313                        &mut inst_exports,
1314                        &mut type_size,
1315                        offset,
1316                    )?;
1317                }
1318            }
1319        }
1320
1321        let ty = Type::ComponentInstance(ComponentInstanceType {
1322            type_size,
1323            kind: ComponentInstanceTypeKind::Exports(inst_exports),
1324        });
1325
1326        Ok(types.push_anon(ty))
1327    }
1328
1329    fn instantiate_core_exports(
1330        &mut self,
1331        exports: Vec<crate::Export>,
1332        types: &mut TypeAlloc,
1333        offset: usize,
1334    ) -> Result<TypeId> {
1335        fn insert_export(
1336            name: &str,
1337            export: EntityType,
1338            exports: &mut IndexMap<String, EntityType>,
1339            type_size: &mut u32,
1340            offset: usize,
1341        ) -> Result<()> {
1342            *type_size = combine_type_sizes(*type_size, export.type_size(), offset)?;
1343
1344            if exports.insert(name.to_string(), export).is_some() {
1345                bail!(
1346                    offset,
1347                    "duplicate instantiation export name `{name}` already defined",
1348                )
1349            }
1350
1351            Ok(())
1352        }
1353
1354        let mut type_size = 1;
1355        let mut inst_exports = IndexMap::new();
1356        for export in exports {
1357            match export.kind {
1358                ExternalKind::Func => {
1359                    insert_export(
1360                        export.name,
1361                        EntityType::Func(self.core_function_at(export.index, offset)?),
1362                        &mut inst_exports,
1363                        &mut type_size,
1364                        offset,
1365                    )?;
1366                }
1367                ExternalKind::Table => insert_export(
1368                    export.name,
1369                    EntityType::Table(*self.table_at(export.index, offset)?),
1370                    &mut inst_exports,
1371                    &mut type_size,
1372                    offset,
1373                )?,
1374                ExternalKind::Memory => insert_export(
1375                    export.name,
1376                    EntityType::Memory(*self.memory_at(export.index, offset)?),
1377                    &mut inst_exports,
1378                    &mut type_size,
1379                    offset,
1380                )?,
1381                ExternalKind::Global => {
1382                    insert_export(
1383                        export.name,
1384                        EntityType::Global(*self.global_at(export.index, offset)?),
1385                        &mut inst_exports,
1386                        &mut type_size,
1387                        offset,
1388                    )?;
1389                }
1390                ExternalKind::Tag => insert_export(
1391                    export.name,
1392                    EntityType::Tag(self.core_function_at(export.index, offset)?),
1393                    &mut inst_exports,
1394                    &mut type_size,
1395                    offset,
1396                )?,
1397            }
1398        }
1399
1400        let ty = Type::Instance(InstanceType {
1401            type_size,
1402            kind: InstanceTypeKind::Exports(inst_exports),
1403        });
1404
1405        Ok(types.push_anon(ty))
1406    }
1407
1408    fn alias_core_instance_export(
1409        &mut self,
1410        instance_index: u32,
1411        kind: ExternalKind,
1412        name: &str,
1413        types: &TypeList,
1414        offset: usize,
1415    ) -> Result<()> {
1416        macro_rules! push_module_export {
1417            ($expected:path, $collection:ident, $ty:literal) => {{
1418                match self.core_instance_export(instance_index, name, types, offset)? {
1419                    $expected(ty) => {
1420                        self.$collection.push(*ty);
1421                        Ok(())
1422                    }
1423                    _ => {
1424                        bail!(
1425                            offset,
1426                            "export `{name}` for core instance {instance_index} is not a {}",
1427                            $ty
1428                        )
1429                    }
1430                }
1431            }};
1432        }
1433
1434        match kind {
1435            ExternalKind::Func => {
1436                check_max(
1437                    self.function_count(),
1438                    1,
1439                    MAX_WASM_FUNCTIONS,
1440                    "functions",
1441                    offset,
1442                )?;
1443                push_module_export!(EntityType::Func, core_funcs, "function")
1444            }
1445            ExternalKind::Table => {
1446                check_max(self.core_tables.len(), 1, MAX_WASM_TABLES, "tables", offset)?;
1447                push_module_export!(EntityType::Table, core_tables, "table")
1448            }
1449            ExternalKind::Memory => {
1450                check_max(
1451                    self.core_memories.len(),
1452                    1,
1453                    MAX_WASM_MEMORIES,
1454                    "memories",
1455                    offset,
1456                )?;
1457                push_module_export!(EntityType::Memory, core_memories, "memory")
1458            }
1459            ExternalKind::Global => {
1460                check_max(
1461                    self.core_globals.len(),
1462                    1,
1463                    MAX_WASM_GLOBALS,
1464                    "globals",
1465                    offset,
1466                )?;
1467                push_module_export!(EntityType::Global, core_globals, "global")
1468            }
1469            ExternalKind::Tag => {
1470                check_max(self.core_tags.len(), 1, MAX_WASM_TAGS, "tags", offset)?;
1471                push_module_export!(EntityType::Tag, core_tags, "tag")
1472            }
1473        }
1474    }
1475
1476    fn alias_instance_export(
1477        &mut self,
1478        instance_index: u32,
1479        kind: ComponentExternalKind,
1480        name: &str,
1481        types: &mut TypeAlloc,
1482        offset: usize,
1483    ) -> Result<()> {
1484        let name = to_kebab_str(name, "alias export", offset)?;
1485
1486        macro_rules! push_component_export {
1487            ($expected:path, $collection:ident, $ty:literal) => {{
1488                match self.instance_export(instance_index, name, types, offset)? {
1489                    $expected(ty) => {
1490                        self.$collection.push(*ty);
1491                        Ok(())
1492                    }
1493                    _ => {
1494                        bail!(
1495                            offset,
1496                            "export `{name}` for instance {instance_index} is not a {}",
1497                            $ty
1498                        )
1499                    }
1500                }
1501            }};
1502        }
1503
1504        match kind {
1505            ComponentExternalKind::Module => {
1506                check_max(
1507                    self.core_modules.len(),
1508                    1,
1509                    MAX_WASM_MODULES,
1510                    "modules",
1511                    offset,
1512                )?;
1513                push_component_export!(ComponentEntityType::Module, core_modules, "module")
1514            }
1515            ComponentExternalKind::Component => {
1516                check_max(
1517                    self.components.len(),
1518                    1,
1519                    MAX_WASM_COMPONENTS,
1520                    "components",
1521                    offset,
1522                )?;
1523                push_component_export!(ComponentEntityType::Component, components, "component")
1524            }
1525            ComponentExternalKind::Instance => {
1526                check_max(
1527                    self.instance_count(),
1528                    1,
1529                    MAX_WASM_INSTANCES,
1530                    "instances",
1531                    offset,
1532                )?;
1533                push_component_export!(ComponentEntityType::Instance, instances, "instance")
1534            }
1535            ComponentExternalKind::Func => {
1536                check_max(
1537                    self.function_count(),
1538                    1,
1539                    MAX_WASM_FUNCTIONS,
1540                    "functions",
1541                    offset,
1542                )?;
1543                push_component_export!(ComponentEntityType::Func, funcs, "function")
1544            }
1545            ComponentExternalKind::Value => {
1546                check_max(self.values.len(), 1, MAX_WASM_VALUES, "values", offset)?;
1547                match self.instance_export(instance_index, name, types, offset)? {
1548                    ComponentEntityType::Value(ty) => {
1549                        self.values.push((*ty, false));
1550                        Ok(())
1551                    }
1552                    _ => bail!(
1553                        offset,
1554                        "export `{name}` for instance {instance_index} is not a value",
1555                    ),
1556                }
1557            }
1558            ComponentExternalKind::Type => {
1559                check_max(self.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
1560                match *self.instance_export(instance_index, name, types, offset)? {
1561                    ComponentEntityType::Type { created, .. } => {
1562                        let id = types.with_unique(created);
1563                        self.types.push(id);
1564                        Ok(())
1565                    }
1566                    _ => {
1567                        bail!(
1568                            offset,
1569                            "export `{name}` for instance {instance_index} is not a type",
1570                        )
1571                    }
1572                }
1573            }
1574        }
1575    }
1576
1577    fn alias_module(components: &mut [Self], count: u32, index: u32, offset: usize) -> Result<()> {
1578        let component = Self::check_alias_count(components, count, offset)?;
1579        let ty = component.module_at(index, offset)?;
1580
1581        let current = components.last_mut().unwrap();
1582        check_max(
1583            current.core_modules.len(),
1584            1,
1585            MAX_WASM_MODULES,
1586            "modules",
1587            offset,
1588        )?;
1589
1590        current.core_modules.push(ty);
1591        Ok(())
1592    }
1593
1594    fn alias_component(
1595        components: &mut [Self],
1596        count: u32,
1597        index: u32,
1598        offset: usize,
1599    ) -> Result<()> {
1600        let component = Self::check_alias_count(components, count, offset)?;
1601        let ty = component.component_at(index, offset)?;
1602
1603        let current = components.last_mut().unwrap();
1604        check_max(
1605            current.components.len(),
1606            1,
1607            MAX_WASM_COMPONENTS,
1608            "components",
1609            offset,
1610        )?;
1611
1612        current.components.push(ty);
1613        Ok(())
1614    }
1615
1616    fn alias_core_type(
1617        components: &mut [Self],
1618        count: u32,
1619        index: u32,
1620        types: &mut TypeAlloc,
1621        offset: usize,
1622    ) -> Result<()> {
1623        let component = Self::check_alias_count(components, count, offset)?;
1624        let ty = component.type_at(index, true, offset)?;
1625
1626        let current = components.last_mut().unwrap();
1627        check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
1628
1629        let id = types.with_unique(ty);
1630        current.core_types.push(id);
1631
1632        Ok(())
1633    }
1634
1635    fn alias_type(
1636        components: &mut [Self],
1637        count: u32,
1638        index: u32,
1639        types: &mut TypeAlloc,
1640        offset: usize,
1641    ) -> Result<()> {
1642        let component = Self::check_alias_count(components, count, offset)?;
1643        let ty = component.type_at(index, false, offset)?;
1644
1645        let current = components.last_mut().unwrap();
1646        check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
1647
1648        let id = types.with_unique(ty);
1649        current.types.push(id);
1650
1651        Ok(())
1652    }
1653
1654    fn check_alias_count(components: &[Self], count: u32, offset: usize) -> Result<&Self> {
1655        let count = count as usize;
1656        if count >= components.len() {
1657            bail!(offset, "invalid outer alias count of {count}");
1658        }
1659
1660        Ok(&components[components.len() - count - 1])
1661    }
1662
1663    fn create_defined_type(
1664        &self,
1665        ty: crate::ComponentDefinedType,
1666        types: &TypeList,
1667        offset: usize,
1668    ) -> Result<ComponentDefinedType> {
1669        match ty {
1670            crate::ComponentDefinedType::Primitive(ty) => Ok(ComponentDefinedType::Primitive(ty)),
1671            crate::ComponentDefinedType::Record(fields) => {
1672                self.create_record_type(fields.as_ref(), types, offset)
1673            }
1674            crate::ComponentDefinedType::Variant(cases) => {
1675                self.create_variant_type(cases.as_ref(), types, offset)
1676            }
1677            crate::ComponentDefinedType::List(ty) => Ok(ComponentDefinedType::List(
1678                self.create_component_val_type(ty, types, offset)?,
1679            )),
1680            crate::ComponentDefinedType::Tuple(tys) => {
1681                self.create_tuple_type(tys.as_ref(), types, offset)
1682            }
1683            crate::ComponentDefinedType::Flags(names) => {
1684                self.create_flags_type(names.as_ref(), offset)
1685            }
1686            crate::ComponentDefinedType::Enum(cases) => {
1687                self.create_enum_type(cases.as_ref(), offset)
1688            }
1689            crate::ComponentDefinedType::Union(tys) => {
1690                self.create_union_type(tys.as_ref(), types, offset)
1691            }
1692            crate::ComponentDefinedType::Option(ty) => Ok(ComponentDefinedType::Option(
1693                self.create_component_val_type(ty, types, offset)?,
1694            )),
1695            crate::ComponentDefinedType::Result { ok, err } => Ok(ComponentDefinedType::Result {
1696                ok: ok
1697                    .map(|ty| self.create_component_val_type(ty, types, offset))
1698                    .transpose()?,
1699                err: err
1700                    .map(|ty| self.create_component_val_type(ty, types, offset))
1701                    .transpose()?,
1702            }),
1703        }
1704    }
1705
1706    fn create_record_type(
1707        &self,
1708        fields: &[(&str, crate::ComponentValType)],
1709        types: &TypeList,
1710        offset: usize,
1711    ) -> Result<ComponentDefinedType> {
1712        let mut type_size = 1;
1713        let mut field_map = IndexMap::with_capacity(fields.len());
1714
1715        for (name, ty) in fields {
1716            let name = to_kebab_str(name, "record field", offset)?;
1717            let ty = self.create_component_val_type(*ty, types, offset)?;
1718
1719            match field_map.entry(name.to_owned()) {
1720                Entry::Occupied(e) => bail!(
1721                    offset,
1722                    "record field name `{name}` conflicts with previous field name `{prev}`",
1723                    prev = e.key()
1724                ),
1725                Entry::Vacant(e) => {
1726                    type_size = combine_type_sizes(type_size, ty.type_size(), offset)?;
1727                    e.insert(ty);
1728                }
1729            }
1730        }
1731
1732        Ok(ComponentDefinedType::Record(RecordType {
1733            type_size,
1734            fields: field_map,
1735        }))
1736    }
1737
1738    fn create_variant_type(
1739        &self,
1740        cases: &[crate::VariantCase],
1741        types: &TypeList,
1742        offset: usize,
1743    ) -> Result<ComponentDefinedType> {
1744        let mut type_size = 1;
1745        let mut case_map: IndexMap<KebabString, VariantCase> = IndexMap::with_capacity(cases.len());
1746
1747        if cases.is_empty() {
1748            return Err(BinaryReaderError::new(
1749                "variant type must have at least one case",
1750                offset,
1751            ));
1752        }
1753
1754        if cases.len() > u32::MAX as usize {
1755            return Err(BinaryReaderError::new(
1756                "variant type cannot be represented with a 32-bit discriminant value",
1757                offset,
1758            ));
1759        }
1760
1761        for (i, case) in cases.iter().enumerate() {
1762            if let Some(refines) = case.refines {
1763                if refines >= i as u32 {
1764                    return Err(BinaryReaderError::new(
1765                        "variant case can only refine a previously defined case",
1766                        offset,
1767                    ));
1768                }
1769            }
1770
1771            let name = to_kebab_str(case.name, "variant case", offset)?;
1772
1773            let ty = case
1774                .ty
1775                .map(|ty| self.create_component_val_type(ty, types, offset))
1776                .transpose()?;
1777
1778            match case_map.entry(name.to_owned()) {
1779                Entry::Occupied(e) => bail!(
1780                    offset,
1781                    "variant case name `{name}` conflicts with previous case name `{prev}`",
1782                    name = case.name,
1783                    prev = e.key()
1784                ),
1785                Entry::Vacant(e) => {
1786                    type_size = combine_type_sizes(
1787                        type_size,
1788                        ty.map(|ty| ty.type_size()).unwrap_or(1),
1789                        offset,
1790                    )?;
1791
1792                    // Safety: the use of `KebabStr::new_unchecked` here is safe because the string
1793                    // was already verified to be kebab case.
1794                    e.insert(VariantCase {
1795                        ty,
1796                        refines: case
1797                            .refines
1798                            .map(|i| KebabStr::new_unchecked(cases[i as usize].name).to_owned()),
1799                    });
1800                }
1801            }
1802        }
1803
1804        Ok(ComponentDefinedType::Variant(VariantType {
1805            type_size,
1806            cases: case_map,
1807        }))
1808    }
1809
1810    fn create_tuple_type(
1811        &self,
1812        tys: &[crate::ComponentValType],
1813        types: &TypeList,
1814        offset: usize,
1815    ) -> Result<ComponentDefinedType> {
1816        let mut type_size = 1;
1817        let types = tys
1818            .iter()
1819            .map(|ty| {
1820                let ty = self.create_component_val_type(*ty, types, offset)?;
1821                type_size = combine_type_sizes(type_size, ty.type_size(), offset)?;
1822                Ok(ty)
1823            })
1824            .collect::<Result<_>>()?;
1825
1826        Ok(ComponentDefinedType::Tuple(TupleType { type_size, types }))
1827    }
1828
1829    fn create_flags_type(&self, names: &[&str], offset: usize) -> Result<ComponentDefinedType> {
1830        let mut names_set = IndexSet::with_capacity(names.len());
1831
1832        for name in names {
1833            let name = to_kebab_str(name, "flag", offset)?;
1834            if !names_set.insert(name.to_owned()) {
1835                bail!(
1836                    offset,
1837                    "flag name `{name}` conflicts with previous flag name `{prev}`",
1838                    prev = names_set.get(name).unwrap()
1839                );
1840            }
1841        }
1842
1843        Ok(ComponentDefinedType::Flags(names_set))
1844    }
1845
1846    fn create_enum_type(&self, cases: &[&str], offset: usize) -> Result<ComponentDefinedType> {
1847        if cases.len() > u32::MAX as usize {
1848            return Err(BinaryReaderError::new(
1849                "enumeration type cannot be represented with a 32-bit discriminant value",
1850                offset,
1851            ));
1852        }
1853
1854        let mut tags = IndexSet::with_capacity(cases.len());
1855
1856        for tag in cases {
1857            let tag = to_kebab_str(tag, "enum tag", offset)?;
1858            if !tags.insert(tag.to_owned()) {
1859                bail!(
1860                    offset,
1861                    "enum tag name `{tag}` conflicts with previous tag name `{prev}`",
1862                    prev = tags.get(tag).unwrap()
1863                );
1864            }
1865        }
1866
1867        Ok(ComponentDefinedType::Enum(tags))
1868    }
1869
1870    fn create_union_type(
1871        &self,
1872        tys: &[crate::ComponentValType],
1873        types: &TypeList,
1874        offset: usize,
1875    ) -> Result<ComponentDefinedType> {
1876        let mut type_size = 1;
1877        let types = tys
1878            .iter()
1879            .map(|ty| {
1880                let ty = self.create_component_val_type(*ty, types, offset)?;
1881                type_size = combine_type_sizes(type_size, ty.type_size(), offset)?;
1882                Ok(ty)
1883            })
1884            .collect::<Result<_>>()?;
1885
1886        Ok(ComponentDefinedType::Union(UnionType { type_size, types }))
1887    }
1888
1889    fn create_component_val_type(
1890        &self,
1891        ty: crate::ComponentValType,
1892        types: &TypeList,
1893        offset: usize,
1894    ) -> Result<ComponentValType> {
1895        Ok(match ty {
1896            crate::ComponentValType::Primitive(pt) => ComponentValType::Primitive(pt),
1897            crate::ComponentValType::Type(idx) => {
1898                ComponentValType::Type(self.defined_type_at(idx, types, offset)?)
1899            }
1900        })
1901    }
1902
1903    pub fn type_at(&self, idx: u32, core: bool, offset: usize) -> Result<TypeId> {
1904        let types = if core { &self.core_types } else { &self.types };
1905        types
1906            .get(idx as usize)
1907            .copied()
1908            .ok_or_else(|| format_err!(offset, "unknown type {idx}: type index out of bounds"))
1909    }
1910
1911    fn function_type_at<'a>(
1912        &self,
1913        idx: u32,
1914        types: &'a TypeList,
1915        offset: usize,
1916    ) -> Result<&'a ComponentFuncType> {
1917        types[self.type_at(idx, false, offset)?]
1918            .as_component_func_type()
1919            .ok_or_else(|| format_err!(offset, "type index {idx} is not a function type"))
1920    }
1921
1922    fn function_at(&self, idx: u32, offset: usize) -> Result<TypeId> {
1923        self.funcs.get(idx as usize).copied().ok_or_else(|| {
1924            format_err!(
1925                offset,
1926                "unknown function {idx}: function index out of bounds"
1927            )
1928        })
1929    }
1930
1931    fn component_at(&self, idx: u32, offset: usize) -> Result<TypeId> {
1932        self.components.get(idx as usize).copied().ok_or_else(|| {
1933            format_err!(
1934                offset,
1935                "unknown component {idx}: component index out of bounds"
1936            )
1937        })
1938    }
1939
1940    fn instance_at(&self, idx: u32, offset: usize) -> Result<TypeId> {
1941        self.instances.get(idx as usize).copied().ok_or_else(|| {
1942            format_err!(
1943                offset,
1944                "unknown instance {idx}: instance index out of bounds"
1945            )
1946        })
1947    }
1948
1949    fn instance_export<'a>(
1950        &self,
1951        instance_index: u32,
1952        name: &KebabStr,
1953        types: &'a TypeList,
1954        offset: usize,
1955    ) -> Result<&'a ComponentEntityType> {
1956        match types[self.instance_at(instance_index, offset)?]
1957            .as_component_instance_type()
1958            .unwrap()
1959            .internal_exports(types)
1960            .get(name)
1961        {
1962            Some((_, ty)) => Ok(ty),
1963            None => bail!(
1964                offset,
1965                "instance {instance_index} has no export named `{name}`"
1966            ),
1967        }
1968    }
1969
1970    fn value_at(&mut self, idx: u32, offset: usize) -> Result<&ComponentValType> {
1971        match self.values.get_mut(idx as usize) {
1972            Some((ty, used)) if !*used => {
1973                *used = true;
1974                Ok(ty)
1975            }
1976            Some(_) => bail!(offset, "value {idx} cannot be used more than once"),
1977            None => bail!(offset, "unknown value {idx}: value index out of bounds"),
1978        }
1979    }
1980
1981    fn defined_type_at(&self, idx: u32, types: &TypeList, offset: usize) -> Result<TypeId> {
1982        let id = self.type_at(idx, false, offset)?;
1983        match &types[id] {
1984            Type::Defined(_) => Ok(id),
1985            _ => bail!(offset, "type index {} is not a defined type", idx),
1986        }
1987    }
1988
1989    fn core_function_at(&self, idx: u32, offset: usize) -> Result<TypeId> {
1990        match self.core_funcs.get(idx as usize) {
1991            Some(id) => Ok(*id),
1992            None => bail!(
1993                offset,
1994                "unknown core function {idx}: function index out of bounds"
1995            ),
1996        }
1997    }
1998
1999    fn module_at(&self, idx: u32, offset: usize) -> Result<TypeId> {
2000        match self.core_modules.get(idx as usize) {
2001            Some(id) => Ok(*id),
2002            None => bail!(offset, "unknown module {idx}: module index out of bounds"),
2003        }
2004    }
2005
2006    fn core_instance_at(&self, idx: u32, offset: usize) -> Result<TypeId> {
2007        match self.core_instances.get(idx as usize) {
2008            Some(id) => Ok(*id),
2009            None => bail!(
2010                offset,
2011                "unknown core instance {idx}: instance index out of bounds"
2012            ),
2013        }
2014    }
2015
2016    fn core_instance_export<'a>(
2017        &self,
2018        instance_index: u32,
2019        name: &str,
2020        types: &'a TypeList,
2021        offset: usize,
2022    ) -> Result<&'a EntityType> {
2023        match types[self.core_instance_at(instance_index, offset)?]
2024            .as_instance_type()
2025            .unwrap()
2026            .internal_exports(types)
2027            .get(name)
2028        {
2029            Some(export) => Ok(export),
2030            None => bail!(
2031                offset,
2032                "core instance {instance_index} has no export named `{name}`"
2033            ),
2034        }
2035    }
2036
2037    fn global_at(&self, idx: u32, offset: usize) -> Result<&GlobalType> {
2038        match self.core_globals.get(idx as usize) {
2039            Some(t) => Ok(t),
2040            None => bail!(offset, "unknown global {idx}: global index out of bounds"),
2041        }
2042    }
2043
2044    fn table_at(&self, idx: u32, offset: usize) -> Result<&TableType> {
2045        match self.core_tables.get(idx as usize) {
2046            Some(t) => Ok(t),
2047            None => bail!(offset, "unknown table {idx}: table index out of bounds"),
2048        }
2049    }
2050
2051    fn memory_at(&self, idx: u32, offset: usize) -> Result<&MemoryType> {
2052        match self.core_memories.get(idx as usize) {
2053            Some(t) => Ok(t),
2054            None => bail!(offset, "unknown memory {idx}: memory index out of bounds"),
2055        }
2056    }
2057
2058    fn take_component_type(&mut self) -> ComponentType {
2059        let mut ty = ComponentType {
2060            type_size: self.type_size,
2061            imports: Default::default(),
2062            exports: Default::default(),
2063        };
2064
2065        for (name, (url, t, kind)) in mem::take(&mut self.externs) {
2066            let map = match kind {
2067                ExternKind::Import => &mut ty.imports,
2068                ExternKind::Export => &mut ty.exports,
2069            };
2070            let prev = map.insert(name, (url, t));
2071            assert!(prev.is_none());
2072        }
2073
2074        ty
2075    }
2076}
2077
2078impl Default for ComponentState {
2079    fn default() -> Self {
2080        Self {
2081            core_types: Default::default(),
2082            core_modules: Default::default(),
2083            core_instances: Default::default(),
2084            core_funcs: Default::default(),
2085            core_memories: Default::default(),
2086            core_tables: Default::default(),
2087            core_globals: Default::default(),
2088            core_tags: Default::default(),
2089            types: Default::default(),
2090            funcs: Default::default(),
2091            values: Default::default(),
2092            instances: Default::default(),
2093            components: Default::default(),
2094            externs: Default::default(),
2095            export_urls: Default::default(),
2096            import_urls: Default::default(),
2097            has_start: Default::default(),
2098            type_size: 1,
2099        }
2100    }
2101}