Skip to main content

wasmtime_environ/component/
types_builder.rs

1use crate::PanicOnOom as _;
2use crate::component::*;
3use crate::error::{Result, bail};
4use crate::prelude::*;
5use crate::{
6    EngineOrModuleTypeIndex, EntityType, ModuleInternedTypeIndex, ModuleTypes, ModuleTypesBuilder,
7    PrimaryMap, TypeConvert, TypeIndex, WasmHeapType, WasmparserTypeConverter,
8};
9use cranelift_entity::EntityRef;
10use std::collections::HashMap;
11use std::hash::Hash;
12use std::ops::Index;
13use wasmparser::component_types::{
14    ComponentAnyTypeId, ComponentCoreModuleTypeId, ComponentDefinedType, ComponentDefinedTypeId,
15    ComponentEntityType, ComponentFuncTypeId, ComponentInstanceTypeId, ComponentTypeId,
16    ComponentValType, RecordType, ResourceId, TupleType, VariantType,
17};
18use wasmparser::names::KebabString;
19use wasmparser::types::TypesRef;
20use wasmparser::{PrimitiveValType, Validator};
21use wasmtime_component_util::FlagsSize;
22
23mod resources;
24pub use resources::ResourcesBuilder;
25
26/// Structure used to build a [`ComponentTypes`] during translation.
27///
28/// This contains tables to intern any component types found as well as
29/// managing building up core wasm [`ModuleTypes`] as well.
30pub struct ComponentTypesBuilder {
31    functions: HashMap<TypeFunc, TypeFuncIndex>,
32    lists: HashMap<TypeList, TypeListIndex>,
33    maps: HashMap<TypeMap, TypeMapIndex>,
34    records: HashMap<TypeRecord, TypeRecordIndex>,
35    variants: HashMap<TypeVariant, TypeVariantIndex>,
36    tuples: HashMap<TypeTuple, TypeTupleIndex>,
37    enums: HashMap<TypeEnum, TypeEnumIndex>,
38    flags: HashMap<TypeFlags, TypeFlagsIndex>,
39    options: HashMap<TypeOption, TypeOptionIndex>,
40    results: HashMap<TypeResult, TypeResultIndex>,
41    futures: HashMap<TypeFuture, TypeFutureIndex>,
42    streams: HashMap<TypeStream, TypeStreamIndex>,
43    future_tables: HashMap<TypeFutureTable, TypeFutureTableIndex>,
44    stream_tables: HashMap<TypeStreamTable, TypeStreamTableIndex>,
45    error_context_tables: HashMap<TypeErrorContextTable, TypeComponentLocalErrorContextTableIndex>,
46    fixed_length_lists: HashMap<TypeFixedLengthList, TypeFixedLengthListIndex>,
47
48    component_types: ComponentTypes,
49    module_types: ModuleTypesBuilder,
50
51    // Cache of what the "flat" representation of all types are which is only
52    // used at compile-time and not used at runtime, hence the location here
53    // as opposed to `ComponentTypes`.
54    type_info: TypeInformationCache,
55
56    resources: ResourcesBuilder,
57
58    // Total number of abstract resources allocated.
59    //
60    // These are only allocated within component and instance types when
61    // translating them.
62    abstract_resources: u32,
63}
64
65impl<T> Index<T> for ComponentTypesBuilder
66where
67    ModuleTypes: Index<T>,
68{
69    type Output = <ModuleTypes as Index<T>>::Output;
70    fn index(&self, idx: T) -> &Self::Output {
71        self.module_types.index(idx)
72    }
73}
74
75macro_rules! intern_and_fill_flat_types {
76    ($me:ident, $name:ident, $val:ident) => {{
77        if let Some(idx) = $me.$name.get(&$val) {
78            *idx
79        } else {
80            let idx = $me
81                .component_types
82                .$name
83                .push($val.clone_panic_on_oom())
84                .panic_on_oom();
85            let mut info = TypeInformation::new();
86            info.$name($me, &$val);
87            let idx2 = $me.type_info.$name.push(info);
88            assert_eq!(idx, idx2);
89            $me.$name.insert($val, idx);
90            idx
91        }
92    }};
93}
94
95impl ComponentTypesBuilder {
96    /// Construct a new `ComponentTypesBuilder` for use with the given validator.
97    pub fn new(validator: &Validator) -> Self {
98        Self {
99            module_types: ModuleTypesBuilder::new(validator),
100
101            functions: HashMap::default(),
102            lists: HashMap::default(),
103            maps: HashMap::default(),
104            records: HashMap::default(),
105            variants: HashMap::default(),
106            tuples: HashMap::default(),
107            enums: HashMap::default(),
108            flags: HashMap::default(),
109            options: HashMap::default(),
110            results: HashMap::default(),
111            futures: HashMap::default(),
112            streams: HashMap::default(),
113            future_tables: HashMap::default(),
114            stream_tables: HashMap::default(),
115            error_context_tables: HashMap::default(),
116            component_types: ComponentTypes::default(),
117            type_info: TypeInformationCache::default(),
118            resources: ResourcesBuilder::default(),
119            abstract_resources: 0,
120            fixed_length_lists: HashMap::default(),
121        }
122    }
123
124    fn export_type_def(
125        &mut self,
126        export_items: &TryPrimaryMap<ExportIndex, Export>,
127        idx: ExportIndex,
128    ) -> TypeDef {
129        match &export_items[idx] {
130            Export::LiftedFunction { ty, .. } => TypeDef::ComponentFunc(*ty),
131            Export::ModuleStatic { ty, .. } | Export::ModuleImport { ty, .. } => {
132                TypeDef::Module(*ty)
133            }
134            Export::Instance { ty, .. } => TypeDef::ComponentInstance(*ty),
135            Export::Type(ty) => *ty,
136        }
137    }
138
139    /// Finishes this list of component types and returns the finished
140    /// structure and the [`TypeComponentIndex`] corresponding to top-level component
141    /// with `imports` and `exports` specified.
142    pub fn finish(mut self, component: &Component) -> (ComponentTypes, TypeComponentIndex) {
143        let mut component_ty = TypeComponent::default();
144        for (_, (name, ty)) in component.import_types.iter() {
145            component_ty
146                .imports
147                .insert(name.clone_panic_on_oom(), ty.clone_panic_on_oom())
148                .panic_on_oom();
149        }
150        for (name, (ty, data)) in component.exports.raw_iter() {
151            component_ty
152                .exports
153                .insert(
154                    name.clone_panic_on_oom(),
155                    ComponentExtern {
156                        data: data.clone_panic_on_oom(),
157                        ty: self.export_type_def(&component.export_items, *ty),
158                    },
159                )
160                .panic_on_oom();
161        }
162        let ty = self
163            .component_types
164            .components
165            .push(component_ty)
166            .panic_on_oom();
167
168        self.component_types.module_types = Some(self.module_types.finish());
169        (self.component_types, ty)
170    }
171
172    /// Returns the underlying builder used to build up core wasm module types.
173    ///
174    /// Note that this is shared across all modules found within a component to
175    /// improve the wins from deduplicating function signatures.
176    pub fn module_types_builder(&self) -> &ModuleTypesBuilder {
177        &self.module_types
178    }
179
180    /// Same as `module_types_builder`, but `mut`.
181    pub fn module_types_builder_mut(&mut self) -> &mut ModuleTypesBuilder {
182        &mut self.module_types
183    }
184
185    /// Returns the internal reference to the in-progress `&ComponentTypes`.
186    pub(super) fn component_types(&self) -> &ComponentTypes {
187        &self.component_types
188    }
189
190    /// Returns the number of resource tables allocated so far, or the maximum
191    /// `TypeResourceTableIndex`.
192    pub fn num_resource_tables(&self) -> usize {
193        self.component_types.resource_tables.len()
194    }
195
196    /// Forwards to `ComponentTypes::resource_owned_by_own_instance`.
197    pub fn resource_owned_by_own_instance(
198        &self,
199        ty: TypeResourceTableIndex,
200        defined_resource_instance: impl FnOnce(ResourceIndex) -> Option<RuntimeComponentInstanceIndex>,
201    ) -> bool {
202        self.component_types
203            .resource_owned_by_own_instance(ty, defined_resource_instance)
204    }
205
206    /// Returns the number of future tables allocated so far, or the maximum
207    /// `TypeFutureTableIndex`.
208    pub fn num_future_tables(&self) -> usize {
209        self.component_types.future_tables.len()
210    }
211
212    /// Returns the number of stream tables allocated so far, or the maximum
213    /// `TypeStreamTableIndex`.
214    pub fn num_stream_tables(&self) -> usize {
215        self.component_types.stream_tables.len()
216    }
217
218    /// Returns the number of error-context tables allocated so far, or the maximum
219    /// `TypeComponentLocalErrorContextTableIndex`.
220    pub fn num_error_context_tables(&self) -> usize {
221        self.component_types.error_context_tables.len()
222    }
223
224    /// Returns a mutable reference to the underlying `ResourcesBuilder`.
225    pub fn resources_mut(&mut self) -> &mut ResourcesBuilder {
226        &mut self.resources
227    }
228
229    /// Work around the borrow checker to borrow two sub-fields simultaneously
230    /// externally.
231    pub fn resources_mut_and_types(&mut self) -> (&mut ResourcesBuilder, &ComponentTypes) {
232        (&mut self.resources, &self.component_types)
233    }
234
235    /// Converts a wasmparser `ComponentFuncType` into Wasmtime's type
236    /// representation.
237    pub fn convert_component_func_type(
238        &mut self,
239        types: TypesRef<'_>,
240        id: ComponentFuncTypeId,
241    ) -> Result<TypeFuncIndex> {
242        assert_eq!(types.id(), self.module_types.validator_id());
243        let ty = &types[id];
244        let param_names = ty
245            .params
246            .iter()
247            .map(|(name, _)| TryString::try_from(name.as_str()))
248            .try_collect::<TryVec<_>, _>()?;
249        let params = ty
250            .params
251            .iter()
252            .map(|(_name, ty)| self.valtype(types, ty))
253            .collect::<Result<_>>()?;
254        let results = ty
255            .result
256            .iter()
257            .map(|ty| self.valtype(types, ty))
258            .collect::<Result<_>>()?;
259        let params = self.new_tuple_type(params);
260        let results = self.new_tuple_type(results);
261        let ty = TypeFunc {
262            async_: ty.async_,
263            param_names,
264            params,
265            results,
266        };
267        Ok(self.add_func_type(ty))
268    }
269
270    /// Converts a wasmparser `wasmparser::ComponentItem` into Wasmtime's type
271    /// representation.
272    pub fn convert_component_item(
273        &mut self,
274        types: TypesRef<'_>,
275        ty: &wasmparser::component_types::ComponentItem,
276    ) -> Result<ComponentExtern> {
277        Ok(ComponentExtern {
278            ty: self.convert_component_entity_type(types, ty.ty)?,
279            data: ComponentExternData {
280                implements: ty.implements.clone().map(Into::into),
281                external_id: ty.external_id.clone().map(Into::into),
282            },
283        })
284    }
285
286    /// Converts a wasmparser `ComponentEntityType` into Wasmtime's type
287    /// representation.
288    pub fn convert_component_entity_type(
289        &mut self,
290        types: TypesRef<'_>,
291        ty: ComponentEntityType,
292    ) -> Result<TypeDef> {
293        assert_eq!(types.id(), self.module_types.validator_id());
294        Ok(match ty {
295            ComponentEntityType::Module(id) => TypeDef::Module(self.convert_module(types, id)?),
296            ComponentEntityType::Component(id) => {
297                TypeDef::Component(self.convert_component(types, id)?)
298            }
299            ComponentEntityType::Instance(id) => {
300                TypeDef::ComponentInstance(self.convert_instance(types, id)?)
301            }
302            ComponentEntityType::Func(id) => {
303                TypeDef::ComponentFunc(self.convert_component_func_type(types, id)?)
304            }
305            ComponentEntityType::Type { created, .. } => match created {
306                ComponentAnyTypeId::Defined(id) => {
307                    TypeDef::Interface(self.defined_type(types, id)?)
308                }
309                ComponentAnyTypeId::Resource(id) => {
310                    TypeDef::Resource(self.resource_id(id.resource()))
311                }
312                _ => bail!("unsupported type export"),
313            },
314            ComponentEntityType::Value(_) => bail!("values not supported"),
315        })
316    }
317
318    /// Converts a wasmparser `Type` into Wasmtime's type representation.
319    pub fn convert_type(&mut self, types: TypesRef<'_>, id: ComponentAnyTypeId) -> Result<TypeDef> {
320        assert_eq!(types.id(), self.module_types.validator_id());
321        Ok(match id {
322            ComponentAnyTypeId::Defined(id) => TypeDef::Interface(self.defined_type(types, id)?),
323            ComponentAnyTypeId::Component(id) => {
324                TypeDef::Component(self.convert_component(types, id)?)
325            }
326            ComponentAnyTypeId::Instance(id) => {
327                TypeDef::ComponentInstance(self.convert_instance(types, id)?)
328            }
329            ComponentAnyTypeId::Func(id) => {
330                TypeDef::ComponentFunc(self.convert_component_func_type(types, id)?)
331            }
332            ComponentAnyTypeId::Resource(id) => TypeDef::Resource(self.resource_id(id.resource())),
333        })
334    }
335
336    fn convert_component(
337        &mut self,
338        types: TypesRef<'_>,
339        id: ComponentTypeId,
340    ) -> Result<TypeComponentIndex> {
341        assert_eq!(types.id(), self.module_types.validator_id());
342        let ty = &types[id];
343        let mut result = TypeComponent::default();
344        for (name, ty) in ty.imports.iter() {
345            self.register_abstract_component_entity_type(types, ty.ty);
346            result
347                .imports
348                .insert(name.clone().into(), self.convert_component_item(types, ty)?)?;
349        }
350        for (name, ty) in ty.exports.iter() {
351            self.register_abstract_component_entity_type(types, ty.ty);
352            result
353                .exports
354                .insert(name.clone().into(), self.convert_component_item(types, ty)?)?;
355        }
356        Ok(self.component_types.components.push(result)?)
357    }
358
359    pub(crate) fn convert_instance(
360        &mut self,
361        types: TypesRef<'_>,
362        id: ComponentInstanceTypeId,
363    ) -> Result<TypeComponentInstanceIndex> {
364        assert_eq!(types.id(), self.module_types.validator_id());
365        let ty = &types[id];
366        let mut result = TypeComponentInstance::default();
367        for (name, ty) in ty.exports.iter() {
368            self.register_abstract_component_entity_type(types, ty.ty);
369            result
370                .exports
371                .insert(name.clone().into(), self.convert_component_item(types, ty)?)?;
372        }
373        Ok(self.component_types.component_instances.push(result)?)
374    }
375
376    fn register_abstract_component_entity_type(
377        &mut self,
378        types: TypesRef<'_>,
379        ty: ComponentEntityType,
380    ) {
381        let mut path = Vec::new();
382        self.resources.register_abstract_component_entity_type(
383            &types,
384            ty,
385            &mut path,
386            &mut |_path| {
387                self.abstract_resources += 1;
388                AbstractResourceIndex::from_u32(self.abstract_resources)
389            },
390        );
391    }
392
393    pub(crate) fn convert_module(
394        &mut self,
395        types: TypesRef<'_>,
396        id: ComponentCoreModuleTypeId,
397    ) -> Result<TypeModuleIndex> {
398        assert_eq!(types.id(), self.module_types.validator_id());
399        let ty = &types[id];
400
401        // Intern all types found in this module as they could show up anywhere
402        // within imports/exports/etc.
403        for id in ty.types.iter() {
404            self.module_types_builder_mut().intern_type(types, *id)?;
405        }
406
407        let mut result = TypeModule::default();
408        for ((module, field), ty) in ty.imports.iter() {
409            result.imports.insert(
410                (module.clone().into(), field.clone().into()),
411                self.entity_type(types, ty)?,
412            )?;
413        }
414        for (name, ty) in ty.exports.iter() {
415            result
416                .exports
417                .insert(name.clone().into(), self.entity_type(types, ty)?)?;
418        }
419        Ok(self.component_types.modules.push(result)?)
420    }
421
422    fn entity_type(
423        &mut self,
424        types: TypesRef<'_>,
425        ty: &wasmparser::types::EntityType,
426    ) -> Result<EntityType> {
427        use wasmparser::types::EntityType::*;
428
429        assert_eq!(types.id(), self.module_types.validator_id());
430        Ok(match ty {
431            Func(id) => EntityType::Function({
432                self.module_types_builder_mut()
433                    .intern_type(types, *id)?
434                    .into()
435            }),
436            Table(ty) => EntityType::Table(self.convert_table_type(ty)?),
437            Memory(ty) => EntityType::Memory((*ty).into()),
438            Global(ty) => EntityType::Global(self.convert_global_type(ty)?),
439            Tag(id) => {
440                let func = self.module_types_builder_mut().intern_type(types, *id)?;
441                let exc = self
442                    .module_types_builder_mut()
443                    .define_exception_type_for_tag(func);
444                EntityType::Tag(crate::types::Tag {
445                    signature: func.into(),
446                    exception: exc.into(),
447                })
448            }
449            FuncExact(_) => bail!("custom-descriptors proposal not implemented"),
450        })
451    }
452
453    /// Convert a wasmparser `ComponentDefinedTypeId` into Wasmtime's type representation.
454    pub fn defined_type(
455        &mut self,
456        types: TypesRef<'_>,
457        id: ComponentDefinedTypeId,
458    ) -> Result<InterfaceType> {
459        assert_eq!(types.id(), self.module_types.validator_id());
460        Ok(match &types[id] {
461            ComponentDefinedType::Primitive(ty) => self.primitive_type(ty)?,
462            ComponentDefinedType::Record(e) => InterfaceType::Record(self.record_type(types, e)?),
463            ComponentDefinedType::Variant(e) => {
464                InterfaceType::Variant(self.variant_type(types, e)?)
465            }
466            ComponentDefinedType::List { element, .. } => {
467                InterfaceType::List(self.list_type(types, element)?)
468            }
469            ComponentDefinedType::Map { key, value, .. } => {
470                InterfaceType::Map(self.map_type(types, key, value)?)
471            }
472            ComponentDefinedType::Tuple(e) => InterfaceType::Tuple(self.tuple_type(types, e)?),
473            ComponentDefinedType::Flags(e) => InterfaceType::Flags(self.flags_type(e)),
474            ComponentDefinedType::Enum(e) => InterfaceType::Enum(self.enum_type(e)),
475            ComponentDefinedType::Option { ty, .. } => {
476                InterfaceType::Option(self.option_type(types, ty)?)
477            }
478            ComponentDefinedType::Result { ok, err, .. } => {
479                InterfaceType::Result(self.result_type(types, ok, err)?)
480            }
481            ComponentDefinedType::Own(r) => InterfaceType::Own(self.resource_id(r.resource())),
482            ComponentDefinedType::Borrow(r) => {
483                InterfaceType::Borrow(self.resource_id(r.resource()))
484            }
485            ComponentDefinedType::Future { ty, .. } => {
486                InterfaceType::Future(self.future_table_type(types, ty)?)
487            }
488            ComponentDefinedType::Stream { ty, .. } => {
489                InterfaceType::Stream(self.stream_table_type(types, ty)?)
490            }
491            ComponentDefinedType::FixedLengthList {
492                element, length, ..
493            } => InterfaceType::FixedLengthList(
494                self.fixed_length_list_type(types, element, *length)?,
495            ),
496        })
497    }
498
499    /// Retrieve Wasmtime's type representation of the `error-context` type.
500    pub fn error_context_type(&mut self) -> Result<TypeComponentLocalErrorContextTableIndex> {
501        self.error_context_table_type()
502    }
503
504    pub(crate) fn valtype(
505        &mut self,
506        types: TypesRef<'_>,
507        ty: &ComponentValType,
508    ) -> Result<InterfaceType> {
509        assert_eq!(types.id(), self.module_types.validator_id());
510        match ty {
511            ComponentValType::Primitive(p) => self.primitive_type(p),
512            ComponentValType::Type(id) => self.defined_type(types, *id),
513        }
514    }
515
516    fn primitive_type(&mut self, ty: &PrimitiveValType) -> Result<InterfaceType> {
517        match ty {
518            wasmparser::PrimitiveValType::Bool => Ok(InterfaceType::Bool),
519            wasmparser::PrimitiveValType::S8 => Ok(InterfaceType::S8),
520            wasmparser::PrimitiveValType::U8 => Ok(InterfaceType::U8),
521            wasmparser::PrimitiveValType::S16 => Ok(InterfaceType::S16),
522            wasmparser::PrimitiveValType::U16 => Ok(InterfaceType::U16),
523            wasmparser::PrimitiveValType::S32 => Ok(InterfaceType::S32),
524            wasmparser::PrimitiveValType::U32 => Ok(InterfaceType::U32),
525            wasmparser::PrimitiveValType::S64 => Ok(InterfaceType::S64),
526            wasmparser::PrimitiveValType::U64 => Ok(InterfaceType::U64),
527            wasmparser::PrimitiveValType::F32 => Ok(InterfaceType::Float32),
528            wasmparser::PrimitiveValType::F64 => Ok(InterfaceType::Float64),
529            wasmparser::PrimitiveValType::Char => Ok(InterfaceType::Char),
530            wasmparser::PrimitiveValType::String => Ok(InterfaceType::String),
531            wasmparser::PrimitiveValType::ErrorContext => Ok(InterfaceType::ErrorContext(
532                self.error_context_table_type()?,
533            )),
534        }
535    }
536
537    fn record_type(&mut self, types: TypesRef<'_>, ty: &RecordType) -> Result<TypeRecordIndex> {
538        assert_eq!(types.id(), self.module_types.validator_id());
539        let fields = ty
540            .fields
541            .iter()
542            .map(|(name, ty)| {
543                Ok(RecordField {
544                    name: TryString::try_from(name.as_str())?,
545                    ty: self.valtype(types, ty)?,
546                })
547            })
548            .try_collect::<TryVec<_>, Error>()?;
549        let abi = CanonicalAbiInfo::record(
550            fields
551                .iter()
552                .map(|field| self.component_types.canonical_abi(&field.ty)),
553        );
554        Ok(self.add_record_type(TypeRecord { fields, abi }))
555    }
556
557    fn variant_type(&mut self, types: TypesRef<'_>, ty: &VariantType) -> Result<TypeVariantIndex> {
558        assert_eq!(types.id(), self.module_types.validator_id());
559        let cases = ty
560            .cases
561            .iter()
562            .map(|(name, case)| {
563                Ok((
564                    TryString::try_from(name.as_str())?,
565                    match &case.ty.as_ref() {
566                        Some(ty) => Some(self.valtype(types, ty)?),
567                        None => None,
568                    },
569                ))
570            })
571            .try_collect::<TryIndexMap<_, _>, Error>()?;
572        let (info, abi) = VariantInfo::new(
573            cases
574                .iter()
575                .map(|(_, c)| c.as_ref().map(|ty| self.component_types.canonical_abi(ty))),
576        );
577        Ok(self.add_variant_type(TypeVariant { cases, abi, info }))
578    }
579
580    fn tuple_type(&mut self, types: TypesRef<'_>, ty: &TupleType) -> Result<TypeTupleIndex> {
581        assert_eq!(types.id(), self.module_types.validator_id());
582        let types = ty
583            .types
584            .iter()
585            .map(|ty| self.valtype(types, ty))
586            .collect::<Result<Box<[_]>>>()?;
587        Ok(self.new_tuple_type(types))
588    }
589
590    pub(crate) fn new_tuple_type(&mut self, types: Box<[InterfaceType]>) -> TypeTupleIndex {
591        let abi = CanonicalAbiInfo::record(
592            types
593                .iter()
594                .map(|ty| self.component_types.canonical_abi(ty)),
595        );
596        self.add_tuple_type(TypeTuple {
597            types: types.into(),
598            abi,
599        })
600    }
601
602    fn fixed_length_list_type(
603        &mut self,
604        types: TypesRef<'_>,
605        ty: &ComponentValType,
606        size: u32,
607    ) -> Result<TypeFixedLengthListIndex> {
608        assert_eq!(types.id(), self.module_types.validator_id());
609        let element = self.valtype(types, ty)?;
610        Ok(self.new_fixed_length_list_type(element, size))
611    }
612
613    pub(crate) fn new_fixed_length_list_type(
614        &mut self,
615        element: InterfaceType,
616        size: u32,
617    ) -> TypeFixedLengthListIndex {
618        let element_abi = self.component_types.canonical_abi(&element);
619        let abi = CanonicalAbiInfo::fixed_length_list_static(
620            element_abi,
621            size.try_into().expect("size should fit into usize"),
622        );
623        self.add_fixed_length_list_type(TypeFixedLengthList { element, size, abi })
624    }
625
626    fn flags_type(&mut self, flags: &IndexSet<KebabString>) -> TypeFlagsIndex {
627        let flags = TypeFlags {
628            names: flags
629                .iter()
630                .map(|s| TryString::try_from(s.as_str()))
631                .try_collect::<TryIndexSet<_>, _>()
632                .panic_on_oom(),
633            abi: CanonicalAbiInfo::flags(flags.len()),
634        };
635        self.add_flags_type(flags)
636    }
637
638    fn enum_type(&mut self, variants: &IndexSet<KebabString>) -> TypeEnumIndex {
639        let names = variants
640            .iter()
641            .map(|s| TryString::try_from(s.as_str()))
642            .try_collect::<TryIndexSet<_>, _>()
643            .panic_on_oom();
644        let (info, abi) = VariantInfo::new(names.iter().map(|_| None));
645        self.add_enum_type(TypeEnum { names, abi, info })
646    }
647
648    fn option_type(
649        &mut self,
650        types: TypesRef<'_>,
651        ty: &ComponentValType,
652    ) -> Result<TypeOptionIndex> {
653        assert_eq!(types.id(), self.module_types.validator_id());
654        let ty = self.valtype(types, ty)?;
655        let (info, abi) = VariantInfo::new([None, Some(self.component_types.canonical_abi(&ty))]);
656        Ok(self.add_option_type(TypeOption { ty, abi, info }))
657    }
658
659    fn result_type(
660        &mut self,
661        types: TypesRef<'_>,
662        ok: &Option<ComponentValType>,
663        err: &Option<ComponentValType>,
664    ) -> Result<TypeResultIndex> {
665        assert_eq!(types.id(), self.module_types.validator_id());
666        let ok = match ok {
667            Some(ty) => Some(self.valtype(types, ty)?),
668            None => None,
669        };
670        let err = match err {
671            Some(ty) => Some(self.valtype(types, ty)?),
672            None => None,
673        };
674        let (info, abi) = VariantInfo::new([
675            ok.as_ref().map(|t| self.component_types.canonical_abi(t)),
676            err.as_ref().map(|t| self.component_types.canonical_abi(t)),
677        ]);
678        Ok(self.add_result_type(TypeResult { ok, err, abi, info }))
679    }
680
681    fn future_table_type(
682        &mut self,
683        types: TypesRef<'_>,
684        ty: &Option<ComponentValType>,
685    ) -> Result<TypeFutureTableIndex> {
686        let payload = ty.as_ref().map(|ty| self.valtype(types, ty)).transpose()?;
687        let ty = self.add_future_type(TypeFuture { payload });
688        Ok(self.add_future_table_type(TypeFutureTable {
689            ty,
690            instance: self.resources.get_current_instance().unwrap(),
691        }))
692    }
693
694    fn stream_table_type(
695        &mut self,
696        types: TypesRef<'_>,
697        ty: &Option<ComponentValType>,
698    ) -> Result<TypeStreamTableIndex> {
699        let payload = ty.as_ref().map(|ty| self.valtype(types, ty)).transpose()?;
700        let ty = self.add_stream_type(TypeStream { payload });
701        Ok(self.add_stream_table_type(TypeStreamTable {
702            ty,
703            instance: self.resources.get_current_instance().unwrap(),
704        }))
705    }
706
707    /// Retrieve Wasmtime's type representation of the `error-context` type from
708    /// the point of view of the current component instance.
709    pub fn error_context_table_type(&mut self) -> Result<TypeComponentLocalErrorContextTableIndex> {
710        Ok(self.add_error_context_table_type(TypeErrorContextTable {
711            instance: self.resources.get_current_instance().unwrap(),
712        }))
713    }
714
715    fn list_type(&mut self, types: TypesRef<'_>, ty: &ComponentValType) -> Result<TypeListIndex> {
716        assert_eq!(types.id(), self.module_types.validator_id());
717        let element = self.valtype(types, ty)?;
718        Ok(self.add_list_type(TypeList { element }))
719    }
720
721    fn map_type(
722        &mut self,
723        types: TypesRef<'_>,
724        key: &ComponentValType,
725        value: &ComponentValType,
726    ) -> Result<TypeMapIndex> {
727        assert_eq!(types.id(), self.module_types.validator_id());
728        let key_ty = self.valtype(types, key)?;
729        let value_ty = self.valtype(types, value)?;
730        let key_abi = self.component_types.canonical_abi(&key_ty);
731        let value_abi = self.component_types.canonical_abi(&value_ty);
732        let entry_abi = CanonicalAbiInfo::record([key_abi, value_abi].into_iter());
733
734        let mut offset32 = 0;
735        key_abi.next_field32(&mut offset32);
736        let value_offset32 = value_abi.next_field32(&mut offset32);
737
738        let mut offset64 = 0;
739        key_abi.next_field64(&mut offset64);
740        let value_offset64 = value_abi.next_field64(&mut offset64);
741
742        Ok(self.add_map_type(TypeMap {
743            key: key_ty,
744            value: value_ty,
745            entry_abi,
746            value_offset32,
747            value_offset64,
748        }))
749    }
750
751    /// Converts a wasmparser `id`, which must point to a resource, to its
752    /// corresponding `TypeResourceTableIndex`.
753    pub fn resource_id(&mut self, id: ResourceId) -> TypeResourceTableIndex {
754        self.resources.convert(id, &mut self.component_types)
755    }
756
757    /// Interns a new function type within this type information.
758    pub fn add_func_type(&mut self, ty: TypeFunc) -> TypeFuncIndex {
759        intern(&mut self.functions, &mut self.component_types.functions, ty)
760    }
761
762    /// Interns a new record type within this type information.
763    pub fn add_record_type(&mut self, ty: TypeRecord) -> TypeRecordIndex {
764        intern_and_fill_flat_types!(self, records, ty)
765    }
766
767    /// Interns a new flags type within this type information.
768    pub fn add_flags_type(&mut self, ty: TypeFlags) -> TypeFlagsIndex {
769        intern_and_fill_flat_types!(self, flags, ty)
770    }
771
772    /// Interns a new tuple type within this type information.
773    pub fn add_tuple_type(&mut self, ty: TypeTuple) -> TypeTupleIndex {
774        intern_and_fill_flat_types!(self, tuples, ty)
775    }
776
777    /// Interns a new tuple type within this type information.
778    pub fn add_fixed_length_list_type(
779        &mut self,
780        ty: TypeFixedLengthList,
781    ) -> TypeFixedLengthListIndex {
782        intern_and_fill_flat_types!(self, fixed_length_lists, ty)
783    }
784
785    /// Interns a new variant type within this type information.
786    pub fn add_variant_type(&mut self, ty: TypeVariant) -> TypeVariantIndex {
787        intern_and_fill_flat_types!(self, variants, ty)
788    }
789
790    /// Interns a new enum type within this type information.
791    pub fn add_enum_type(&mut self, ty: TypeEnum) -> TypeEnumIndex {
792        intern_and_fill_flat_types!(self, enums, ty)
793    }
794
795    /// Interns a new option type within this type information.
796    pub fn add_option_type(&mut self, ty: TypeOption) -> TypeOptionIndex {
797        intern_and_fill_flat_types!(self, options, ty)
798    }
799
800    /// Interns a new result type within this type information.
801    pub fn add_result_type(&mut self, ty: TypeResult) -> TypeResultIndex {
802        intern_and_fill_flat_types!(self, results, ty)
803    }
804
805    /// Interns a new list type within this type information.
806    pub fn add_list_type(&mut self, ty: TypeList) -> TypeListIndex {
807        intern_and_fill_flat_types!(self, lists, ty)
808    }
809
810    /// Interns a new map type within this type information.
811    pub fn add_map_type(&mut self, ty: TypeMap) -> TypeMapIndex {
812        intern_and_fill_flat_types!(self, maps, ty)
813    }
814
815    /// Interns a new future type within this type information.
816    pub fn add_future_type(&mut self, ty: TypeFuture) -> TypeFutureIndex {
817        intern(&mut self.futures, &mut self.component_types.futures, ty)
818    }
819
820    /// Interns a new future table type within this type information.
821    pub fn add_future_table_type(&mut self, ty: TypeFutureTable) -> TypeFutureTableIndex {
822        intern(
823            &mut self.future_tables,
824            &mut self.component_types.future_tables,
825            ty,
826        )
827    }
828
829    /// Interns a new stream type within this type information.
830    pub fn add_stream_type(&mut self, ty: TypeStream) -> TypeStreamIndex {
831        intern(&mut self.streams, &mut self.component_types.streams, ty)
832    }
833
834    /// Interns a new stream table type within this type information.
835    pub fn add_stream_table_type(&mut self, ty: TypeStreamTable) -> TypeStreamTableIndex {
836        intern(
837            &mut self.stream_tables,
838            &mut self.component_types.stream_tables,
839            ty,
840        )
841    }
842
843    /// Interns a new error context table type within this type information.
844    pub fn add_error_context_table_type(
845        &mut self,
846        ty: TypeErrorContextTable,
847    ) -> TypeComponentLocalErrorContextTableIndex {
848        intern(
849            &mut self.error_context_tables,
850            &mut self.component_types.error_context_tables,
851            ty,
852        )
853    }
854
855    /// Returns the canonical ABI information about the specified type.
856    pub fn canonical_abi(&self, ty: &InterfaceType) -> &CanonicalAbiInfo {
857        self.component_types.canonical_abi(ty)
858    }
859
860    /// Returns the "flat types" for the given interface type used in the
861    /// canonical ABI.
862    ///
863    /// Returns `None` if the type is too large to be represented via flat types
864    /// in the canonical abi.
865    pub fn flat_types(&self, ty: &InterfaceType) -> Option<FlatTypes<'_>> {
866        self.type_information(ty).flat.as_flat_types()
867    }
868
869    /// Returns whether the type specified contains any borrowed resources
870    /// within it.
871    pub fn ty_contains_borrow_resource(&self, ty: &InterfaceType) -> bool {
872        self.type_information(ty).handles.has_borrow()
873    }
874
875    /// Returns whether the type specified contains any handle within it, where
876    /// "handle" means `own`, `borrow`, `future`, `stream`, or `error-context`.
877    fn ty_contains_any_handle(&self, ty: &InterfaceType) -> bool {
878        self.type_information(ty).handles.has_any()
879    }
880
881    /// Returns whether the type specified contains a `string` within it.
882    pub fn ty_contains_string(&self, ty: &InterfaceType) -> bool {
883        self.type_information(ty).has_string
884    }
885
886    /// Returns whether the signature of `ty` mentions any handle, in either its
887    /// parameters or its results.
888    pub fn func_contains_any_handle(&self, ty: TypeFuncIndex) -> bool {
889        let ty = &self[ty];
890        let params = &self[ty.params].types;
891        let results = &self[ty.results].types;
892        params
893            .iter()
894            .chain(results.iter())
895            .any(|ty| self.ty_contains_any_handle(ty))
896    }
897
898    fn type_information(&self, ty: &InterfaceType) -> &TypeInformation {
899        match ty {
900            InterfaceType::U8
901            | InterfaceType::S8
902            | InterfaceType::Bool
903            | InterfaceType::U16
904            | InterfaceType::S16
905            | InterfaceType::U32
906            | InterfaceType::S32
907            | InterfaceType::Char => {
908                static INFO: TypeInformation = TypeInformation::primitive(FlatType::I32);
909                &INFO
910            }
911            InterfaceType::Own(_)
912            | InterfaceType::Future(_)
913            | InterfaceType::Stream(_)
914            | InterfaceType::ErrorContext(_) => {
915                static INFO: TypeInformation = {
916                    let mut info = TypeInformation::primitive(FlatType::I32);
917                    info.handles = Handles::NoBorrow;
918                    info
919                };
920                &INFO
921            }
922            InterfaceType::Borrow(_) => {
923                static INFO: TypeInformation = {
924                    let mut info = TypeInformation::primitive(FlatType::I32);
925                    info.handles = Handles::Borrow;
926                    info
927                };
928                &INFO
929            }
930            InterfaceType::U64 | InterfaceType::S64 => {
931                static INFO: TypeInformation = TypeInformation::primitive(FlatType::I64);
932                &INFO
933            }
934            InterfaceType::Float32 => {
935                static INFO: TypeInformation = TypeInformation::primitive(FlatType::F32);
936                &INFO
937            }
938            InterfaceType::Float64 => {
939                static INFO: TypeInformation = TypeInformation::primitive(FlatType::F64);
940                &INFO
941            }
942            InterfaceType::String => {
943                static INFO: TypeInformation = {
944                    let mut info = TypeInformation::string();
945                    info.has_string = true;
946                    info
947                };
948                &INFO
949            }
950
951            InterfaceType::List(i) => &self.type_info.lists[*i],
952            InterfaceType::Map(i) => &self.type_info.maps[*i],
953            InterfaceType::Record(i) => &self.type_info.records[*i],
954            InterfaceType::Variant(i) => &self.type_info.variants[*i],
955            InterfaceType::Tuple(i) => &self.type_info.tuples[*i],
956            InterfaceType::Flags(i) => &self.type_info.flags[*i],
957            InterfaceType::Enum(i) => &self.type_info.enums[*i],
958            InterfaceType::Option(i) => &self.type_info.options[*i],
959            InterfaceType::Result(i) => &self.type_info.results[*i],
960            InterfaceType::FixedLengthList(i) => &self.type_info.fixed_length_lists[*i],
961        }
962    }
963}
964
965impl TypeConvert for ComponentTypesBuilder {
966    fn lookup_heap_type(&self, index: wasmparser::UnpackedIndex) -> WasmHeapType {
967        self.module_type_converter().lookup_heap_type(index)
968    }
969
970    fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex {
971        self.module_type_converter().lookup_type_index(index)
972    }
973}
974
975impl ComponentTypesBuilder {
976    fn module_type_converter(
977        &self,
978    ) -> WasmparserTypeConverter<'_, impl Fn(TypeIndex) -> ModuleInternedTypeIndex> {
979        // Types at the component level are always referred to by their
980        // canonicalized `CoreTypeId`, never by a module-relative index.
981        WasmparserTypeConverter::new(&self.module_types, |_| {
982            unreachable!("component-level types don't use module type indices")
983        })
984    }
985}
986
987fn intern<T, U>(map: &mut HashMap<T, U>, list: &mut TryPrimaryMap<U, T>, item: T) -> U
988where
989    T: Hash + TryClone + Eq,
990    U: Copy + EntityRef,
991{
992    if let Some(idx) = map.get(&item) {
993        return *idx;
994    }
995    let idx = list.push(item.clone_panic_on_oom()).panic_on_oom();
996    map.insert(item, idx);
997    return idx;
998}
999
1000struct FlatTypesStorage {
1001    // This could be represented as `Vec<FlatType>` but on 64-bit architectures
1002    // that's 24 bytes. Otherwise `FlatType` is 1 byte large and
1003    // `MAX_FLAT_TYPES` is 16, so it should ideally be more space-efficient to
1004    // use a flat array instead of a heap-based vector.
1005    memory32: [FlatType; MAX_FLAT_TYPES],
1006    memory64: [FlatType; MAX_FLAT_TYPES],
1007
1008    // Tracks the number of flat types pushed into this storage. If this is
1009    // `MAX_FLAT_TYPES + 1` then this storage represents an un-reprsentable
1010    // type in flat types.
1011    len: u8,
1012}
1013
1014impl FlatTypesStorage {
1015    const fn new() -> FlatTypesStorage {
1016        FlatTypesStorage {
1017            memory32: [FlatType::I32; MAX_FLAT_TYPES],
1018            memory64: [FlatType::I32; MAX_FLAT_TYPES],
1019            len: 0,
1020        }
1021    }
1022
1023    fn as_flat_types(&self) -> Option<FlatTypes<'_>> {
1024        let len = usize::from(self.len);
1025        if len > MAX_FLAT_TYPES {
1026            assert_eq!(len, MAX_FLAT_TYPES + 1);
1027            None
1028        } else {
1029            Some(FlatTypes {
1030                memory32: &self.memory32[..len],
1031                memory64: &self.memory64[..len],
1032            })
1033        }
1034    }
1035
1036    /// Pushes a new flat type into this list using `t32` for 32-bit memories
1037    /// and `t64` for 64-bit memories.
1038    ///
1039    /// Returns whether the type was actually pushed or whether this list of
1040    /// flat types just exceeded the maximum meaning that it is now
1041    /// unrepresentable with a flat list of types.
1042    fn push(&mut self, t32: FlatType, t64: FlatType) -> bool {
1043        let len = usize::from(self.len);
1044        if len < MAX_FLAT_TYPES {
1045            self.memory32[len] = t32;
1046            self.memory64[len] = t64;
1047            self.len += 1;
1048            true
1049        } else {
1050            // If this was the first one to go over then flag the length as
1051            // being incompatible with a flat representation.
1052            if len == MAX_FLAT_TYPES {
1053                self.len += 1;
1054            }
1055            false
1056        }
1057    }
1058}
1059
1060impl FlatType {
1061    fn join(&mut self, other: FlatType) {
1062        if *self == other {
1063            return;
1064        }
1065        *self = match (*self, other) {
1066            (FlatType::I32, FlatType::F32) | (FlatType::F32, FlatType::I32) => FlatType::I32,
1067            _ => FlatType::I64,
1068        };
1069    }
1070}
1071
1072#[derive(Default)]
1073struct TypeInformationCache {
1074    records: PrimaryMap<TypeRecordIndex, TypeInformation>,
1075    variants: PrimaryMap<TypeVariantIndex, TypeInformation>,
1076    tuples: PrimaryMap<TypeTupleIndex, TypeInformation>,
1077    enums: PrimaryMap<TypeEnumIndex, TypeInformation>,
1078    flags: PrimaryMap<TypeFlagsIndex, TypeInformation>,
1079    options: PrimaryMap<TypeOptionIndex, TypeInformation>,
1080    results: PrimaryMap<TypeResultIndex, TypeInformation>,
1081    lists: PrimaryMap<TypeListIndex, TypeInformation>,
1082    maps: PrimaryMap<TypeMapIndex, TypeInformation>,
1083    fixed_length_lists: PrimaryMap<TypeFixedLengthListIndex, TypeInformation>,
1084}
1085
1086/// What kind of handles a type transitively contains.
1087#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1088enum Handles {
1089    /// This type contains no handles at all.
1090    None,
1091
1092    /// This type contains at least one handle, but none of them are `borrow`s.
1093    ///
1094    /// That is, it contains an `own`, `future`, `stream`, or `error-context`.
1095    NoBorrow,
1096
1097    /// This type contains at least one `borrow` handle.
1098    Borrow,
1099}
1100
1101impl Handles {
1102    /// Does this type contain any handle at all?
1103    const fn has_any(self) -> bool {
1104        !matches!(self, Handles::None)
1105    }
1106
1107    /// Does this type contain a `borrow` handle?
1108    const fn has_borrow(self) -> bool {
1109        matches!(self, Handles::Borrow)
1110    }
1111
1112    /// Join two facts together.
1113    const fn join(a: Self, b: Self) -> Handles {
1114        match (a, b) {
1115            (Handles::Borrow, _) | (_, Handles::Borrow) => Handles::Borrow,
1116            (Handles::NoBorrow, _) | (_, Handles::NoBorrow) => Handles::NoBorrow,
1117            (Handles::None, Handles::None) => Handles::None,
1118        }
1119    }
1120}
1121
1122struct TypeInformation {
1123    flat: FlatTypesStorage,
1124
1125    /// Which handles this type transitively contains, if any.
1126    handles: Handles,
1127
1128    /// Whether this type transitively contains a `string`.
1129    has_string: bool,
1130}
1131
1132impl TypeInformation {
1133    const fn new() -> TypeInformation {
1134        TypeInformation {
1135            flat: FlatTypesStorage::new(),
1136            handles: Handles::None,
1137            has_string: false,
1138        }
1139    }
1140
1141    const fn primitive(flat: FlatType) -> TypeInformation {
1142        let mut info = TypeInformation::new();
1143        info.flat.memory32[0] = flat;
1144        info.flat.memory64[0] = flat;
1145        info.flat.len = 1;
1146        info
1147    }
1148
1149    const fn string() -> TypeInformation {
1150        let mut info = TypeInformation::new();
1151        info.flat.memory32[0] = FlatType::I32;
1152        info.flat.memory32[1] = FlatType::I32;
1153        info.flat.memory64[0] = FlatType::I64;
1154        info.flat.memory64[1] = FlatType::I64;
1155        info.flat.len = 2;
1156        info
1157    }
1158
1159    /// Builds up all flat types internally using the specified representation
1160    /// for all of the component fields of the record.
1161    fn build_record<'a>(&mut self, types: impl Iterator<Item = &'a TypeInformation>) {
1162        for info in types {
1163            self.handles = Handles::join(self.handles, info.handles);
1164            self.has_string |= info.has_string;
1165            match info.flat.as_flat_types() {
1166                Some(types) => {
1167                    for (t32, t64) in types.memory32.iter().zip(types.memory64) {
1168                        if !self.flat.push(*t32, *t64) {
1169                            break;
1170                        }
1171                    }
1172                }
1173                None => {
1174                    self.flat.len = u8::try_from(MAX_FLAT_TYPES + 1).unwrap();
1175                }
1176            }
1177        }
1178    }
1179
1180    /// Builds up the flat types used to represent a `variant` which notably
1181    /// handles "join"ing types together so each case is representable as a
1182    /// single flat list of types.
1183    ///
1184    /// The iterator item is:
1185    ///
1186    /// * `None` - no payload for this case
1187    /// * `Some(None)` - this case has a payload but can't be represented with
1188    ///   flat types
1189    /// * `Some(Some(types))` - this case has a payload and is represented with
1190    ///   the types specified in the flat representation.
1191    fn build_variant<'a, I>(&mut self, cases: I)
1192    where
1193        I: IntoIterator<Item = Option<&'a TypeInformation>>,
1194    {
1195        let cases = cases.into_iter();
1196        self.flat.push(FlatType::I32, FlatType::I32);
1197
1198        for info in cases {
1199            let info = match info {
1200                Some(info) => info,
1201                // If this case doesn't have a payload then it doesn't change
1202                // the flat representation
1203                None => continue,
1204            };
1205            self.handles = Handles::join(self.handles, info.handles);
1206            self.has_string |= info.has_string;
1207
1208            // If this variant is already unrepresentable in a flat
1209            // representation then this can be skipped.
1210            if usize::from(self.flat.len) > MAX_FLAT_TYPES {
1211                continue;
1212            }
1213
1214            let types = match info.flat.as_flat_types() {
1215                Some(types) => types,
1216                // If this case isn't representable with a flat list of types
1217                // then this variant also isn't representable.
1218                None => {
1219                    self.flat.len = u8::try_from(MAX_FLAT_TYPES + 1).unwrap();
1220                    continue;
1221                }
1222            };
1223            // If the case used all of the flat types then the discriminant
1224            // added for this variant means that this variant is no longer
1225            // representable.
1226            if types.memory32.len() >= MAX_FLAT_TYPES {
1227                self.flat.len = u8::try_from(MAX_FLAT_TYPES + 1).unwrap();
1228                continue;
1229            }
1230            let dst = self
1231                .flat
1232                .memory32
1233                .iter_mut()
1234                .zip(&mut self.flat.memory64)
1235                .skip(1);
1236            for (i, ((t32, t64), (dst32, dst64))) in types
1237                .memory32
1238                .iter()
1239                .zip(types.memory64)
1240                .zip(dst)
1241                .enumerate()
1242            {
1243                if i + 1 < usize::from(self.flat.len) {
1244                    // If this index hs already been set by some previous case
1245                    // then the types are joined together.
1246                    dst32.join(*t32);
1247                    dst64.join(*t64);
1248                } else {
1249                    // Otherwise if this is the first time that the
1250                    // representation has gotten this large then the destination
1251                    // is simply whatever the type is. The length is also
1252                    // increased here to indicate this.
1253                    self.flat.len += 1;
1254                    *dst32 = *t32;
1255                    *dst64 = *t64;
1256                }
1257            }
1258        }
1259    }
1260
1261    fn records(&mut self, types: &ComponentTypesBuilder, ty: &TypeRecord) {
1262        self.build_record(ty.fields.iter().map(|f| types.type_information(&f.ty)));
1263    }
1264
1265    fn tuples(&mut self, types: &ComponentTypesBuilder, ty: &TypeTuple) {
1266        self.build_record(ty.types.iter().map(|t| types.type_information(t)));
1267    }
1268
1269    fn fixed_length_lists(&mut self, types: &ComponentTypesBuilder, ty: &TypeFixedLengthList) {
1270        let element_info = types.type_information(&ty.element);
1271        self.handles = element_info.handles;
1272        self.has_string = element_info.has_string;
1273        match element_info.flat.as_flat_types() {
1274            Some(types) => {
1275                'outer: for _ in 0..ty.size {
1276                    for (t32, t64) in types.memory32.iter().zip(types.memory64) {
1277                        if !self.flat.push(*t32, *t64) {
1278                            break 'outer;
1279                        }
1280                    }
1281                }
1282            }
1283            None => self.flat.len = u8::try_from(MAX_FLAT_TYPES + 1).unwrap(),
1284        }
1285    }
1286
1287    fn enums(&mut self, _types: &ComponentTypesBuilder, _ty: &TypeEnum) {
1288        self.flat.push(FlatType::I32, FlatType::I32);
1289    }
1290
1291    fn flags(&mut self, _types: &ComponentTypesBuilder, ty: &TypeFlags) {
1292        match FlagsSize::from_count(ty.names.len()) {
1293            FlagsSize::Size0 => {}
1294            FlagsSize::Size1 | FlagsSize::Size2 => {
1295                self.flat.push(FlatType::I32, FlatType::I32);
1296            }
1297            FlagsSize::Size4Plus(n) => {
1298                for _ in 0..n {
1299                    self.flat.push(FlatType::I32, FlatType::I32);
1300                }
1301            }
1302        }
1303    }
1304
1305    fn variants(&mut self, types: &ComponentTypesBuilder, ty: &TypeVariant) {
1306        self.build_variant(
1307            ty.cases
1308                .iter()
1309                .map(|(_, c)| c.as_ref().map(|ty| types.type_information(ty))),
1310        )
1311    }
1312
1313    fn results(&mut self, types: &ComponentTypesBuilder, ty: &TypeResult) {
1314        self.build_variant([
1315            ty.ok.as_ref().map(|ty| types.type_information(ty)),
1316            ty.err.as_ref().map(|ty| types.type_information(ty)),
1317        ])
1318    }
1319
1320    fn options(&mut self, types: &ComponentTypesBuilder, ty: &TypeOption) {
1321        self.build_variant([None, Some(types.type_information(&ty.ty))]);
1322    }
1323
1324    fn lists(&mut self, types: &ComponentTypesBuilder, ty: &TypeList) {
1325        *self = TypeInformation::string();
1326        let info = types.type_information(&ty.element);
1327        self.handles = info.handles;
1328        self.has_string = info.has_string;
1329    }
1330
1331    fn maps(&mut self, types: &ComponentTypesBuilder, ty: &TypeMap) {
1332        // Maps are represented as list<tuple<k, v>> in canonical ABI
1333        // So we use POINTER_PAIR like lists, and calculate borrow from key and value
1334        *self = TypeInformation::string();
1335        let key_info = types.type_information(&ty.key);
1336        let value_info = types.type_information(&ty.value);
1337        self.handles = Handles::join(key_info.handles, value_info.handles);
1338        self.has_string = key_info.has_string || value_info.has_string;
1339    }
1340}