wit_component/
validation.rs

1use crate::encoding::{Instance, Item, LibraryInfo, MainOrAdapter, ModuleImportMap};
2use crate::{ComponentEncoder, StringEncoding};
3use anyhow::{Context, Result, anyhow, bail};
4use indexmap::{IndexMap, IndexSet, map::Entry};
5use std::fmt;
6use std::hash::Hash;
7use std::mem;
8use wasm_encoder::ExportKind;
9use wasmparser::names::{ComponentName, ComponentNameKind};
10use wasmparser::{
11    Encoding, ExternalKind, FuncType, Parser, Payload, TypeRef, ValType, ValidPayload, Validator,
12    WasmFeatures, types::TypesRef,
13};
14use wit_parser::{
15    Function, InterfaceId, PackageName, Resolve, Type, TypeDefKind, TypeId, World, WorldId,
16    WorldItem, WorldKey,
17    abi::{AbiVariant, WasmSignature, WasmType},
18};
19
20fn wasm_sig_to_func_type(signature: WasmSignature) -> FuncType {
21    fn from_wasm_type(ty: &WasmType) -> ValType {
22        match ty {
23            WasmType::I32 => ValType::I32,
24            WasmType::I64 => ValType::I64,
25            WasmType::F32 => ValType::F32,
26            WasmType::F64 => ValType::F64,
27            WasmType::Pointer => ValType::I32,
28            WasmType::PointerOrI64 => ValType::I64,
29            WasmType::Length => ValType::I32,
30        }
31    }
32
33    FuncType::new(
34        signature.params.iter().map(from_wasm_type),
35        signature.results.iter().map(from_wasm_type),
36    )
37}
38
39/// Metadata about a validated module and what was found internally.
40///
41/// This structure houses information about `imports` and `exports` to the
42/// module. Each of these specialized types contains "connection" information
43/// between a module's imports/exports and the WIT or component-level constructs
44/// they correspond to.
45
46#[derive(Default)]
47pub struct ValidatedModule {
48    /// Information about a module's imports.
49    pub imports: ImportMap,
50
51    /// Information about a module's exports.
52    pub exports: ExportMap,
53}
54
55impl ValidatedModule {
56    fn new(
57        encoder: &ComponentEncoder,
58        bytes: &[u8],
59        exports: &IndexSet<WorldKey>,
60        import_map: Option<&ModuleImportMap>,
61        info: Option<&LibraryInfo>,
62    ) -> Result<ValidatedModule> {
63        let mut validator = Validator::new_with_features(WasmFeatures::all());
64        let mut ret = ValidatedModule::default();
65
66        for payload in Parser::new(0).parse_all(bytes) {
67            let payload = payload?;
68            if let ValidPayload::End(_) = validator.payload(&payload)? {
69                break;
70            }
71
72            let types = validator.types(0).unwrap();
73
74            match payload {
75                Payload::Version { encoding, .. } if encoding != Encoding::Module => {
76                    bail!("data is not a WebAssembly module");
77                }
78                Payload::ImportSection(s) => {
79                    for import in s.into_imports() {
80                        let import = import?;
81                        ret.imports.add(import, encoder, import_map, info, types)?;
82                    }
83                }
84                Payload::ExportSection(s) => {
85                    for export in s {
86                        let export = export?;
87                        ret.exports.add(export, encoder, &exports, types)?;
88                    }
89                }
90                _ => continue,
91            }
92        }
93
94        ret.exports.validate(encoder, exports)?;
95
96        Ok(ret)
97    }
98}
99
100/// Metadata information about a module's imports.
101///
102/// This structure maintains the connection between component model "things" and
103/// core wasm "things" by ensuring that all imports to the core wasm module are
104/// classified by the `Import` enumeration.
105#[derive(Default)]
106pub struct ImportMap {
107    /// The first level of the map here is the module namespace of the import
108    /// and the second level of the map is the field namespace. The item is then
109    /// how the import is satisfied.
110    names: IndexMap<String, ImportInstance>,
111}
112
113pub enum ImportInstance {
114    /// This import is satisfied by an entire instance of another
115    /// adapter/module.
116    Whole(MainOrAdapter),
117
118    /// This import is satisfied by filling out each name possibly differently.
119    Names(IndexMap<String, Import>),
120}
121
122/// Represents metadata about a `stream<T>` or `future<T>` type for a specific
123/// payload type `T`.
124///
125/// Currently, the name mangling scheme we use to represent `stream` and
126/// `future` intrinsics as core module function imports refers to a specific
127/// `stream` or `future` type by naming an imported or exported component
128/// function which has that type as a parameter or return type (where the
129/// specific type is referred to using an ordinal numbering scheme).  Not only
130/// does this approach unambiguously indicate the type of interest, but it
131/// allows us to reuse the `realloc`, string encoding, memory, etc. used by that
132/// function when emitting intrinsic declarations.
133///
134/// TODO: Rather than reusing the same canon opts as the function in which the
135/// type appears, consider encoding them in the name mangling stream on an
136/// individual basis, similar to how we encode `error-context.*` built-in
137/// imports.
138#[derive(Debug, Eq, PartialEq, Clone, Hash)]
139pub struct PayloadInfo {
140    /// The original, mangled import name used to import this built-in
141    /// (currently used only for hashing and debugging).
142    pub name: String,
143    /// The resolved type id for the `stream` or `future` type of interest.
144    ///
145    /// If `Unit{Future,Stream}` this means that it's a "unit" payload or has no associated
146    /// type being sent.
147    pub ty: PayloadType,
148    /// The world key representing the import or export context of `function`.
149    pub key: WorldKey,
150    /// The interface that `function` was imported from or exported in, if any.
151    pub interface: Option<InterfaceId>,
152    /// Whether `function` is being imported or exported.
153    ///
154    /// This may affect how we emit the declaration of the built-in, e.g. if the
155    /// payload type is an exported resource.
156    pub imported: bool,
157}
158
159/// The type of future/stream referenced by a `PayloadInfo`
160#[derive(Debug, Eq, PartialEq, Clone, Hash)]
161pub enum PayloadType {
162    /// This is a future or stream located in a `Resolve` where `id` points to
163    /// either of `TypeDefKind::{Future, Stream}`.
164    Type {
165        id: TypeId,
166        /// The component-level function import or export where the type
167        /// appeared as a parameter or result type.
168        function: String,
169    },
170    /// This is a `future` (no type)
171    UnitFuture,
172    /// This is a `stream` (no type)
173    UnitStream,
174}
175
176impl PayloadInfo {
177    /// Returns the payload type that this future/stream type is using.
178    pub fn payload(&self, resolve: &Resolve) -> Option<Type> {
179        let id = match self.ty {
180            PayloadType::Type { id, .. } => id,
181            PayloadType::UnitFuture | PayloadType::UnitStream => return None,
182        };
183        match resolve.types[id].kind {
184            TypeDefKind::Future(payload) | TypeDefKind::Stream(payload) => payload,
185            _ => unreachable!(),
186        }
187    }
188}
189
190/// The different kinds of items that a module or an adapter can import.
191///
192/// This is intended to be an exhaustive definition of what can be imported into
193/// core modules within a component that wit-component supports. This doesn't
194/// get down to the level of storing any idx numbers; at its most specific, it
195/// gives a name.
196#[derive(Debug, Clone)]
197pub enum Import {
198    /// A top-level world function, with the name provided here, is imported
199    /// into the module.
200    WorldFunc(WorldKey, String, AbiVariant),
201
202    /// An interface's function is imported into the module.
203    ///
204    /// The `WorldKey` here is the name of the interface in the world in
205    /// question. The `InterfaceId` is the interface that was imported from and
206    /// `String` is the WIT name of the function.
207    InterfaceFunc(WorldKey, InterfaceId, String, AbiVariant),
208
209    /// An imported resource's destructor is imported.
210    ///
211    /// The key provided indicates whether it's for the top-level types of the
212    /// world (`None`) or an interface (`Some` with the name of the interface).
213    /// The `TypeId` is what resource is being dropped.
214    ImportedResourceDrop(WorldKey, Option<InterfaceId>, TypeId),
215
216    /// A `canon resource.drop` intrinsic for an exported item is being
217    /// imported.
218    ///
219    /// This lists the key of the interface that's exporting the resource plus
220    /// the id within that interface.
221    ExportedResourceDrop(WorldKey, TypeId),
222
223    /// A `canon resource.new` intrinsic for an exported item is being
224    /// imported.
225    ///
226    /// This lists the key of the interface that's exporting the resource plus
227    /// the id within that interface.
228    ExportedResourceNew(WorldKey, TypeId),
229
230    /// A `canon resource.rep` intrinsic for an exported item is being
231    /// imported.
232    ///
233    /// This lists the key of the interface that's exporting the resource plus
234    /// the id within that interface.
235    ExportedResourceRep(WorldKey, TypeId),
236
237    /// An export of an adapter is being imported with the specified type.
238    ///
239    /// This is used for when the main module imports an adapter function. The
240    /// adapter name and function name match the module's own import, and the
241    /// type must match that listed here.
242    AdapterExport {
243        adapter: String,
244        func: String,
245        ty: FuncType,
246    },
247
248    /// An adapter is importing the memory of the main module.
249    ///
250    /// (should be combined with `MainModuleExport` below one day)
251    MainModuleMemory,
252
253    /// An adapter is importing an arbitrary item from the main module.
254    MainModuleExport { name: String, kind: ExportKind },
255
256    /// An arbitrary item from either the main module or an adapter is being
257    /// imported.
258    ///
259    /// (should probably subsume `MainModule*` and maybe `AdapterExport` above
260    /// one day.
261    Item(Item),
262
263    /// A `canon task.return` intrinsic for an exported function.
264    ///
265    /// This allows an exported function to return a value and then continue
266    /// running.
267    ///
268    /// As of this writing, only async-lifted exports use `task.return`, but the
269    /// plan is to also support it for sync-lifted exports in the future as
270    /// well.
271    ExportedTaskReturn(WorldKey, Option<InterfaceId>, String, Option<Type>),
272
273    /// A `canon task.cancel` intrinsic for an exported function.
274    ///
275    /// This allows an exported function to acknowledge a `CANCELLED` event.
276    ExportedTaskCancel,
277
278    /// The `context.get` intrinsic for the nth slot of storage.
279    ContextGet(u32),
280    /// The `context.set` intrinsic for the nth slot of storage.
281    ContextSet(u32),
282
283    /// A `canon backpressure.inc` intrinsic.
284    BackpressureInc,
285
286    /// A `canon backpressure.dec` intrinsic.
287    BackpressureDec,
288
289    /// A `waitable-set.new` intrinsic.
290    WaitableSetNew,
291
292    /// A `canon waitable-set.wait` intrinsic.
293    ///
294    /// This allows the guest to wait for any pending calls to async-lowered
295    /// imports and/or `stream` and `future` operations to complete without
296    /// unwinding the current Wasm stack.
297    WaitableSetWait { cancellable: bool },
298
299    /// A `canon waitable.poll` intrinsic.
300    ///
301    /// This allows the guest to check whether any pending calls to
302    /// async-lowered imports and/or `stream` and `future` operations have
303    /// completed without unwinding the current Wasm stack and without blocking.
304    WaitableSetPoll { cancellable: bool },
305
306    /// A `waitable-set.drop` intrinsic.
307    WaitableSetDrop,
308
309    /// A `waitable.join` intrinsic.
310    WaitableJoin,
311
312    /// A `canon thread.yield` intrinsic.
313    ///
314    /// This allows the guest to yield (e.g. during an computationally-intensive
315    /// operation) and allow other subtasks to make progress.
316    ThreadYield { cancellable: bool },
317
318    /// A `canon subtask.drop` intrinsic.
319    ///
320    /// This allows the guest to release its handle to a completed subtask.
321    SubtaskDrop,
322
323    /// A `canon subtask.cancel` intrinsic.
324    ///
325    /// This allows the guest to cancel an in-progress subtask.
326    SubtaskCancel { async_: bool },
327
328    /// A `canon stream.new` intrinsic.
329    ///
330    /// This allows the guest to create a new `stream` of the specified type.
331    StreamNew(PayloadInfo),
332
333    /// A `canon stream.read` intrinsic.
334    ///
335    /// This allows the guest to read the next values (if any) from the specified
336    /// stream.
337    StreamRead { async_: bool, info: PayloadInfo },
338
339    /// A `canon stream.write` intrinsic.
340    ///
341    /// This allows the guest to write one or more values to the specified
342    /// stream.
343    StreamWrite { async_: bool, info: PayloadInfo },
344
345    /// A `canon stream.cancel-read` intrinsic.
346    ///
347    /// This allows the guest to cancel a pending read it initiated earlier (but
348    /// which may have already partially or entirely completed).
349    StreamCancelRead { info: PayloadInfo, async_: bool },
350
351    /// A `canon stream.cancel-write` intrinsic.
352    ///
353    /// This allows the guest to cancel a pending write it initiated earlier
354    /// (but which may have already partially or entirely completed).
355    StreamCancelWrite { info: PayloadInfo, async_: bool },
356
357    /// A `canon stream.drop-readable` intrinsic.
358    ///
359    /// This allows the guest to drop the readable end of a `stream`.
360    StreamDropReadable(PayloadInfo),
361
362    /// A `canon stream.drop-writable` intrinsic.
363    ///
364    /// This allows the guest to drop the writable end of a `stream`.
365    StreamDropWritable(PayloadInfo),
366
367    /// A `canon future.new` intrinsic.
368    ///
369    /// This allows the guest to create a new `future` of the specified type.
370    FutureNew(PayloadInfo),
371
372    /// A `canon future.read` intrinsic.
373    ///
374    /// This allows the guest to read the value (if any) from the specified
375    /// future.
376    FutureRead { async_: bool, info: PayloadInfo },
377
378    /// A `canon future.write` intrinsic.
379    ///
380    /// This allows the guest to write a value to the specified future.
381    FutureWrite { async_: bool, info: PayloadInfo },
382
383    /// A `canon future.cancel-read` intrinsic.
384    ///
385    /// This allows the guest to cancel a pending read it initiated earlier (but
386    /// which may have already completed).
387    FutureCancelRead { info: PayloadInfo, async_: bool },
388
389    /// A `canon future.cancel-write` intrinsic.
390    ///
391    /// This allows the guest to cancel a pending write it initiated earlier
392    /// (but which may have already completed).
393    FutureCancelWrite { info: PayloadInfo, async_: bool },
394
395    /// A `canon future.drop-readable` intrinsic.
396    ///
397    /// This allows the guest to drop the readable end of a `future`.
398    FutureDropReadable(PayloadInfo),
399
400    /// A `canon future.drop-writable` intrinsic.
401    ///
402    /// This allows the guest to drop the writable end of a `future`.
403    FutureDropWritable(PayloadInfo),
404
405    /// A `canon error-context.new` intrinsic.
406    ///
407    /// This allows the guest to create a new `error-context` instance with a
408    /// specified debug message.
409    ErrorContextNew { encoding: StringEncoding },
410
411    /// A `canon error-context.debug-message` intrinsic.
412    ///
413    /// This allows the guest to retrieve the debug message from a
414    /// `error-context` instance.  Note that the content of this message might
415    /// not be identical to what was passed in to `error-context.new`.
416    ErrorContextDebugMessage { encoding: StringEncoding },
417
418    /// A `canon error-context.drop` intrinsic.
419    ///
420    /// This allows the guest to release its handle to the specified
421    /// `error-context` instance.
422    ErrorContextDrop,
423
424    /// A `canon thread.index` intrinsic.
425    ///
426    /// This allows the guest to get the index of the current thread.
427    ThreadIndex,
428
429    /// A `canon thread.new-indirect` intrinsic.
430    ///
431    /// This allows the guest to create a new thread running a specified function.
432    ThreadNewIndirect,
433
434    /// A `canon thread.switch-to` intrinsic.
435    ///
436    /// This allows the guest to switch execution to another thread.
437    ThreadSwitchTo { cancellable: bool },
438
439    /// A `canon thread.suspend` intrinsic.
440    ///
441    /// This allows the guest to suspend the current thread, switching execution to
442    /// an unspecified thread.
443    ThreadSuspend { cancellable: bool },
444
445    /// A `canon thread.resume-later` intrinsic.
446    ///
447    /// This allows the guest to mark a suspended thread for later resumption.
448    ThreadResumeLater,
449
450    /// A `canon thread.yield-to` intrinsic.
451    ///
452    /// This allows the guest to suspend, yielding execution to a specified thread.
453    ThreadYieldTo { cancellable: bool },
454}
455
456impl ImportMap {
457    /// Returns the list of items that the adapter named `name` must export.
458    pub fn required_from_adapter(&self, name: &str) -> IndexMap<String, FuncType> {
459        let names = match self.names.get(name) {
460            Some(ImportInstance::Names(names)) => names,
461            _ => return IndexMap::new(),
462        };
463        names
464            .iter()
465            .map(|(_, import)| match import {
466                Import::AdapterExport { ty, func, adapter } => {
467                    assert_eq!(adapter, name);
468                    (func.clone(), ty.clone())
469                }
470                _ => unreachable!(),
471            })
472            .collect()
473    }
474
475    /// Returns an iterator over all individual imports registered in this map.
476    ///
477    /// Note that this doesn't iterate over the "whole instance" imports.
478    pub fn imports(&self) -> impl Iterator<Item = (&str, &str, &Import)> + '_ {
479        self.names
480            .iter()
481            .filter_map(|(module, m)| match m {
482                ImportInstance::Names(names) => Some((module, names)),
483                ImportInstance::Whole(_) => None,
484            })
485            .flat_map(|(module, m)| {
486                m.iter()
487                    .map(move |(field, import)| (module.as_str(), field.as_str(), import))
488            })
489    }
490
491    /// Returns the map for how all imports must be satisfied.
492    pub fn modules(&self) -> &IndexMap<String, ImportInstance> {
493        &self.names
494    }
495
496    /// Classify an import and call `insert_import()` on it. Used during
497    /// validation to build up this `ImportMap`.
498    fn add(
499        &mut self,
500        import: wasmparser::Import<'_>,
501        encoder: &ComponentEncoder,
502        import_map: Option<&ModuleImportMap>,
503        library_info: Option<&LibraryInfo>,
504        types: TypesRef<'_>,
505    ) -> Result<()> {
506        if self.classify_import_with_library(import, library_info)? {
507            return Ok(());
508        }
509        let mut import_to_classify = import;
510        if let Some(map) = import_map {
511            if let Some(original_name) = map.original_name(&import) {
512                import_to_classify.name = original_name;
513            }
514        }
515        let item = self
516            .classify(import_to_classify, encoder, types)
517            .with_context(|| {
518                format!(
519                    "failed to resolve import `{}::{}`",
520                    import.module, import.name,
521                )
522            })?;
523        self.insert_import(import, item)
524    }
525
526    /// Determines what kind of thing is being imported: maps it from the
527    /// module/name/type triple in the raw wasm module to an enum.
528    ///
529    /// Handles a few special cases, then delegates to
530    /// `classify_component_model_import()`.
531    fn classify(
532        &self,
533        import: wasmparser::Import<'_>,
534        encoder: &ComponentEncoder,
535        types: TypesRef<'_>,
536    ) -> Result<Import> {
537        // Special-case the main module's memory imported into adapters which
538        // currently with `wasm-ld` is not easily configurable.
539        if import.module == "env" && import.name == "memory" {
540            return Ok(Import::MainModuleMemory);
541        }
542
543        // Special-case imports from the main module into adapters.
544        if import.module == "__main_module__" {
545            return Ok(Import::MainModuleExport {
546                name: import.name.to_string(),
547                kind: match import.ty {
548                    TypeRef::Func(_) => ExportKind::Func,
549                    TypeRef::Table(_) => ExportKind::Table,
550                    TypeRef::Memory(_) => ExportKind::Memory,
551                    TypeRef::Global(_) => ExportKind::Global,
552                    TypeRef::Tag(_) => ExportKind::Tag,
553                    TypeRef::FuncExact(_) => bail!("Unexpected func_exact export"),
554                },
555            });
556        }
557
558        let ty_index = match import.ty {
559            TypeRef::Func(ty) => ty,
560            _ => bail!("module is only allowed to import functions"),
561        };
562        let ty = types[types.core_type_at_in_module(ty_index)].unwrap_func();
563
564        // Handle main module imports that match known adapters and set it up as
565        // an import of an adapter export.
566        if encoder.adapters.contains_key(import.module) {
567            return Ok(Import::AdapterExport {
568                adapter: import.module.to_string(),
569                func: import.name.to_string(),
570                ty: ty.clone(),
571            });
572        }
573
574        let (module, names) = match import.module.strip_prefix("cm32p2") {
575            Some(suffix) => (suffix, STANDARD),
576            None if encoder.reject_legacy_names => (import.module, STANDARD),
577            None => (import.module, LEGACY),
578        };
579        self.classify_component_model_import(module, import.name, encoder, ty, names)
580    }
581
582    /// Attempts to classify the import `{module}::{name}` with the rules
583    /// specified in WebAssembly/component-model#378
584    fn classify_component_model_import(
585        &self,
586        module: &str,
587        name: &str,
588        encoder: &ComponentEncoder,
589        ty: &FuncType,
590        names: &dyn NameMangling,
591    ) -> Result<Import> {
592        let resolve = &encoder.metadata.resolve;
593        let world_id = encoder.metadata.world;
594        let world = &resolve.worlds[world_id];
595
596        if module == names.import_root() {
597            if names.error_context_drop(name) {
598                let expected = FuncType::new([ValType::I32], []);
599                validate_func_sig(name, &expected, ty)?;
600                return Ok(Import::ErrorContextDrop);
601            }
602
603            if names.backpressure_inc(name) {
604                let expected = FuncType::new([], []);
605                validate_func_sig(name, &expected, ty)?;
606                return Ok(Import::BackpressureInc);
607            }
608
609            if names.backpressure_dec(name) {
610                let expected = FuncType::new([], []);
611                validate_func_sig(name, &expected, ty)?;
612                return Ok(Import::BackpressureDec);
613            }
614
615            if names.waitable_set_new(name) {
616                let expected = FuncType::new([], [ValType::I32]);
617                validate_func_sig(name, &expected, ty)?;
618                return Ok(Import::WaitableSetNew);
619            }
620
621            if let Some(info) = names.waitable_set_wait(name) {
622                let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
623                validate_func_sig(name, &expected, ty)?;
624                return Ok(Import::WaitableSetWait {
625                    cancellable: info.cancellable,
626                });
627            }
628
629            if let Some(info) = names.waitable_set_poll(name) {
630                let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
631                validate_func_sig(name, &expected, ty)?;
632                return Ok(Import::WaitableSetPoll {
633                    cancellable: info.cancellable,
634                });
635            }
636
637            if names.waitable_set_drop(name) {
638                let expected = FuncType::new([ValType::I32], []);
639                validate_func_sig(name, &expected, ty)?;
640                return Ok(Import::WaitableSetDrop);
641            }
642
643            if names.waitable_join(name) {
644                let expected = FuncType::new([ValType::I32; 2], []);
645                validate_func_sig(name, &expected, ty)?;
646                return Ok(Import::WaitableJoin);
647            }
648
649            if let Some(info) = names.thread_yield(name) {
650                let expected = FuncType::new([], [ValType::I32]);
651                validate_func_sig(name, &expected, ty)?;
652                return Ok(Import::ThreadYield {
653                    cancellable: info.cancellable,
654                });
655            }
656
657            if names.subtask_drop(name) {
658                let expected = FuncType::new([ValType::I32], []);
659                validate_func_sig(name, &expected, ty)?;
660                return Ok(Import::SubtaskDrop);
661            }
662
663            if let Some(info) = names.subtask_cancel(name) {
664                let expected = FuncType::new([ValType::I32], [ValType::I32]);
665                validate_func_sig(name, &expected, ty)?;
666                return Ok(Import::SubtaskCancel {
667                    async_: info.async_lowered,
668                });
669            }
670
671            if let Some(encoding) = names.error_context_new(name) {
672                let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
673                validate_func_sig(name, &expected, ty)?;
674                return Ok(Import::ErrorContextNew { encoding });
675            }
676
677            if let Some(encoding) = names.error_context_debug_message(name) {
678                let expected = FuncType::new([ValType::I32; 2], []);
679                validate_func_sig(name, &expected, ty)?;
680                return Ok(Import::ErrorContextDebugMessage { encoding });
681            }
682
683            if let Some(i) = names.context_get(name) {
684                let expected = FuncType::new([], [ValType::I32]);
685                validate_func_sig(name, &expected, ty)?;
686                return Ok(Import::ContextGet(i));
687            }
688            if let Some(i) = names.context_set(name) {
689                let expected = FuncType::new([ValType::I32], []);
690                validate_func_sig(name, &expected, ty)?;
691                return Ok(Import::ContextSet(i));
692            }
693            if names.thread_index(name) {
694                let expected = FuncType::new([], [ValType::I32]);
695                validate_func_sig(name, &expected, ty)?;
696                return Ok(Import::ThreadIndex);
697            }
698            if names.thread_new_indirect(name) {
699                let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
700                validate_func_sig(name, &expected, ty)?;
701                return Ok(Import::ThreadNewIndirect);
702            }
703            if let Some(info) = names.thread_switch_to(name) {
704                let expected = FuncType::new([ValType::I32], [ValType::I32]);
705                validate_func_sig(name, &expected, ty)?;
706                return Ok(Import::ThreadSwitchTo {
707                    cancellable: info.cancellable,
708                });
709            }
710            if let Some(info) = names.thread_suspend(name) {
711                let expected = FuncType::new([], [ValType::I32]);
712                validate_func_sig(name, &expected, ty)?;
713                return Ok(Import::ThreadSuspend {
714                    cancellable: info.cancellable,
715                });
716            }
717            if names.thread_resume_later(name) {
718                let expected = FuncType::new([ValType::I32], []);
719                validate_func_sig(name, &expected, ty)?;
720                return Ok(Import::ThreadResumeLater);
721            }
722            if let Some(info) = names.thread_yield_to(name) {
723                let expected = FuncType::new([ValType::I32], [ValType::I32]);
724                validate_func_sig(name, &expected, ty)?;
725                return Ok(Import::ThreadYieldTo {
726                    cancellable: info.cancellable,
727                });
728            }
729
730            let (key_name, abi) = names.world_key_name_and_abi(name);
731            let key = WorldKey::Name(key_name.to_string());
732            if let Some(WorldItem::Function(func)) = world.imports.get(&key) {
733                validate_func(resolve, ty, func, abi)?;
734                return Ok(Import::WorldFunc(key, func.name.clone(), abi));
735            }
736
737            if let Some(import) =
738                self.maybe_classify_wit_intrinsic(name, None, encoder, ty, true, names)?
739            {
740                return Ok(import);
741            }
742
743            match world.imports.get(&key) {
744                Some(_) => bail!("expected world top-level import `{name}` to be a function"),
745                None => bail!("no top-level imported function `{name}` specified"),
746            }
747        }
748
749        // Check for `[export]$root::[task-return]foo` or similar
750        if matches!(
751            module.strip_prefix(names.import_exported_intrinsic_prefix()),
752            Some(module) if module == names.import_root()
753        ) {
754            if let Some(import) =
755                self.maybe_classify_wit_intrinsic(name, None, encoder, ty, false, names)?
756            {
757                return Ok(import);
758            }
759        }
760
761        let interface = match module.strip_prefix(names.import_non_root_prefix()) {
762            Some(name) => name,
763            None => bail!("unknown or invalid component model import syntax"),
764        };
765
766        if let Some(interface) = interface.strip_prefix(names.import_exported_intrinsic_prefix()) {
767            let (key, id) = names.module_to_interface(interface, resolve, &world.exports)?;
768
769            if let Some(import) =
770                self.maybe_classify_wit_intrinsic(name, Some((key, id)), encoder, ty, false, names)?
771            {
772                return Ok(import);
773            }
774            bail!("unknown function `{name}`")
775        }
776
777        let (key, id) = names.module_to_interface(interface, resolve, &world.imports)?;
778        let interface = &resolve.interfaces[id];
779        let (function_name, abi) = names.interface_function_name_and_abi(name);
780        if let Some(f) = interface.functions.get(function_name) {
781            validate_func(resolve, ty, f, abi).with_context(|| {
782                let name = resolve.name_world_key(&key);
783                format!("failed to validate import interface `{name}`")
784            })?;
785            return Ok(Import::InterfaceFunc(key, id, f.name.clone(), abi));
786        }
787
788        if let Some(import) =
789            self.maybe_classify_wit_intrinsic(name, Some((key, id)), encoder, ty, true, names)?
790        {
791            return Ok(import);
792        }
793        bail!(
794            "import interface `{module}` is missing function \
795             `{name}` that is required by the module",
796        )
797    }
798
799    /// Attempts to detect and classify `name` as a WIT intrinsic.
800    ///
801    /// This function is a bit of a sprawling sequence of matches used to
802    /// detect whether `name` corresponds to a WIT intrinsic, so specifically
803    /// not a WIT function itself. This is only used for functions imported
804    /// into a module but the import could be for an imported item in a world
805    /// or an exported item.
806    ///
807    /// ## Parameters
808    ///
809    /// * `name` - the core module name which is being pattern-matched. This
810    ///   should be the "field" of the import. This may include the "[async-lower]"
811    ///   or "[cancellable]" prefixes.
812    /// * `key_and_id` - this is the inferred "container" for the function
813    ///   being described which is inferred from the module portion of the core
814    ///   wasm import field. This is `None` for root-level function/type
815    ///   imports, such as when referring to `import x: func();`. This is `Some`
816    ///   when an interface is used (either `import x: interface { .. }` or a
817    ///   standalone `interface`) where the world key is specified for the
818    ///   interface in addition to the interface that was identified.
819    /// * `encoder` - this is the encoder state that contains
820    ///   `Resolve`/metadata information.
821    /// * `ty` - the core wasm type of this import.
822    /// * `import` - whether or not this core wasm import is operating on a WIT
823    ///   level import or export. An example of this being an export is when a
824    ///   core module imports a destructor for an exported resource.
825    /// * `names` - the name mangling scheme that's configured to be used.
826    fn maybe_classify_wit_intrinsic(
827        &self,
828        name: &str,
829        key_and_id: Option<(WorldKey, InterfaceId)>,
830        encoder: &ComponentEncoder,
831        ty: &FuncType,
832        import: bool,
833        names: &dyn NameMangling,
834    ) -> Result<Option<Import>> {
835        let resolve = &encoder.metadata.resolve;
836        let world_id = encoder.metadata.world;
837        let world = &resolve.worlds[world_id];
838
839        // Separate out `Option<WorldKey>` and `Option<InterfaceId>`. If an
840        // interface is NOT specified then the `WorldKey` which is attached to
841        // imports is going to be calculated based on the name of the item
842        // extracted, such as the resource or function referenced.
843        let (key, id) = match key_and_id {
844            Some((key, id)) => (Some(key), Some(id)),
845            None => (None, None),
846        };
847
848        // Tests whether `name` is a resource within `id` (or `world_id`).
849        let resource_test = |name: &str| match id {
850            Some(id) => resource_test_for_interface(resolve, id)(name),
851            None => resource_test_for_world(resolve, world_id)(name),
852        };
853
854        // Test whether this is a `resource.drop` intrinsic.
855        if let Some(resource) = names.resource_drop_name(name) {
856            if let Some(resource_id) = resource_test(resource) {
857                let key = key.unwrap_or_else(|| WorldKey::Name(resource.to_string()));
858                let expected = FuncType::new([ValType::I32], []);
859                validate_func_sig(name, &expected, ty)?;
860                return Ok(Some(if import {
861                    Import::ImportedResourceDrop(key, id, resource_id)
862                } else {
863                    Import::ExportedResourceDrop(key, resource_id)
864                }));
865            }
866        }
867
868        // There are some intrinsics which are only applicable to exported
869        // functions/resources, so check those use cases here.
870        if !import {
871            if let Some(name) = names.resource_new_name(name) {
872                if let Some(id) = resource_test(name) {
873                    let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
874                    let expected = FuncType::new([ValType::I32], [ValType::I32]);
875                    validate_func_sig(name, &expected, ty)?;
876                    return Ok(Some(Import::ExportedResourceNew(key, id)));
877                }
878            }
879            if let Some(name) = names.resource_rep_name(name) {
880                if let Some(id) = resource_test(name) {
881                    let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
882                    let expected = FuncType::new([ValType::I32], [ValType::I32]);
883                    validate_func_sig(name, &expected, ty)?;
884                    return Ok(Some(Import::ExportedResourceRep(key, id)));
885                }
886            }
887            if let Some(name) = names.task_return_name(name) {
888                let func = get_function(resolve, world, name, id, import)?;
889                let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
890                // TODO: should call `validate_func_sig` but would require
891                // calculating the expected signature based of `func.result`.
892                return Ok(Some(Import::ExportedTaskReturn(
893                    key,
894                    id,
895                    func.name.clone(),
896                    func.result,
897                )));
898            }
899            if names.task_cancel(name) {
900                let expected = FuncType::new([], []);
901                validate_func_sig(name, &expected, ty)?;
902                return Ok(Some(Import::ExportedTaskCancel));
903            }
904        }
905
906        let lookup_context = PayloadLookupContext {
907            resolve,
908            world,
909            key,
910            id,
911            import,
912        };
913
914        // Test for a number of async-related intrinsics. All intrinsics are
915        // prefixed with `[...-N]` where `...` is the name of the intrinsic and
916        // the `N` is the indexed future/stream that is being referred to.
917        let import = if let Some(info) = names.future_new(&lookup_context, name) {
918            validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?;
919            Import::FutureNew(info)
920        } else if let Some(info) = names.future_write(&lookup_context, name) {
921            validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?;
922            Import::FutureWrite {
923                async_: info.async_lowered,
924                info: info.inner,
925            }
926        } else if let Some(info) = names.future_read(&lookup_context, name) {
927            validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?;
928            Import::FutureRead {
929                async_: info.async_lowered,
930                info: info.inner,
931            }
932        } else if let Some(info) = names.future_cancel_write(&lookup_context, name) {
933            validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
934            Import::FutureCancelWrite {
935                async_: info.async_lowered,
936                info: info.inner,
937            }
938        } else if let Some(info) = names.future_cancel_read(&lookup_context, name) {
939            validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
940            Import::FutureCancelRead {
941                async_: info.async_lowered,
942                info: info.inner,
943            }
944        } else if let Some(info) = names.future_drop_writable(&lookup_context, name) {
945            validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
946            Import::FutureDropWritable(info)
947        } else if let Some(info) = names.future_drop_readable(&lookup_context, name) {
948            validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
949            Import::FutureDropReadable(info)
950        } else if let Some(info) = names.stream_new(&lookup_context, name) {
951            validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?;
952            Import::StreamNew(info)
953        } else if let Some(info) = names.stream_write(&lookup_context, name) {
954            validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?;
955            Import::StreamWrite {
956                async_: info.async_lowered,
957                info: info.inner,
958            }
959        } else if let Some(info) = names.stream_read(&lookup_context, name) {
960            validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?;
961            Import::StreamRead {
962                async_: info.async_lowered,
963                info: info.inner,
964            }
965        } else if let Some(info) = names.stream_cancel_write(&lookup_context, name) {
966            validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
967            Import::StreamCancelWrite {
968                async_: info.async_lowered,
969                info: info.inner,
970            }
971        } else if let Some(info) = names.stream_cancel_read(&lookup_context, name) {
972            validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
973            Import::StreamCancelRead {
974                async_: info.async_lowered,
975                info: info.inner,
976            }
977        } else if let Some(info) = names.stream_drop_writable(&lookup_context, name) {
978            validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
979            Import::StreamDropWritable(info)
980        } else if let Some(info) = names.stream_drop_readable(&lookup_context, name) {
981            validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
982            Import::StreamDropReadable(info)
983        } else {
984            return Ok(None);
985        };
986        Ok(Some(import))
987    }
988
989    fn classify_import_with_library(
990        &mut self,
991        import: wasmparser::Import<'_>,
992        library_info: Option<&LibraryInfo>,
993    ) -> Result<bool> {
994        let info = match library_info {
995            Some(info) => info,
996            None => return Ok(false),
997        };
998        let Some((_, instance)) = info
999            .arguments
1000            .iter()
1001            .find(|(name, _items)| *name == import.module)
1002        else {
1003            return Ok(false);
1004        };
1005        match instance {
1006            Instance::MainOrAdapter(module) => match self.names.get(import.module) {
1007                Some(ImportInstance::Whole(which)) => {
1008                    if which != module {
1009                        bail!("different whole modules imported under the same name");
1010                    }
1011                }
1012                Some(ImportInstance::Names(_)) => {
1013                    bail!("cannot mix individual imports and whole module imports")
1014                }
1015                None => {
1016                    let instance = ImportInstance::Whole(module.clone());
1017                    self.names.insert(import.module.to_string(), instance);
1018                }
1019            },
1020            Instance::Items(items) => {
1021                let Some(item) = items.iter().find(|i| i.alias == import.name) else {
1022                    return Ok(false);
1023                };
1024                self.insert_import(import, Import::Item(item.clone()))?;
1025            }
1026        }
1027        Ok(true)
1028    }
1029
1030    /// Map an imported item, by module and field name in `self.names`, to the
1031    /// kind of `Import` it is: for example, a certain-typed function from an
1032    /// adapter.
1033    fn insert_import(&mut self, import: wasmparser::Import<'_>, item: Import) -> Result<()> {
1034        let entry = self
1035            .names
1036            .entry(import.module.to_string())
1037            .or_insert(ImportInstance::Names(IndexMap::default()));
1038        let names = match entry {
1039            ImportInstance::Names(names) => names,
1040            _ => bail!("cannot mix individual imports with module imports"),
1041        };
1042        let entry = match names.entry(import.name.to_string()) {
1043            Entry::Occupied(_) => {
1044                bail!(
1045                    "module has duplicate import for `{}::{}`",
1046                    import.module,
1047                    import.name
1048                );
1049            }
1050            Entry::Vacant(v) => v,
1051        };
1052        log::trace!(
1053            "classifying import `{}::{} as {item:?}",
1054            import.module,
1055            import.name
1056        );
1057        entry.insert(item);
1058        Ok(())
1059    }
1060}
1061
1062/// Dual of `ImportMap` except describes the exports of a module instead of the
1063/// imports.
1064#[derive(Default)]
1065pub struct ExportMap {
1066    names: IndexMap<String, Export>,
1067    raw_exports: IndexMap<String, FuncType>,
1068}
1069
1070/// All possible (known) exports from a core wasm module that are recognized and
1071/// handled during the componentization process.
1072#[derive(Debug)]
1073pub enum Export {
1074    /// An export of a top-level function of a world, where the world function
1075    /// is named here.
1076    WorldFunc(WorldKey, String, AbiVariant),
1077
1078    /// A post-return for a top-level function of a world.
1079    WorldFuncPostReturn(WorldKey),
1080
1081    /// An export of a function in an interface.
1082    InterfaceFunc(WorldKey, InterfaceId, String, AbiVariant),
1083
1084    /// A post-return for the above function.
1085    InterfaceFuncPostReturn(WorldKey, String),
1086
1087    /// A destructor for an exported resource.
1088    ResourceDtor(TypeId),
1089
1090    /// Memory, typically for an adapter.
1091    Memory,
1092
1093    /// `cabi_realloc`
1094    GeneralPurposeRealloc,
1095
1096    /// `cabi_export_realloc`
1097    GeneralPurposeExportRealloc,
1098
1099    /// `cabi_import_realloc`
1100    GeneralPurposeImportRealloc,
1101
1102    /// `_initialize`
1103    Initialize,
1104
1105    /// `cabi_realloc_adapter`
1106    ReallocForAdapter,
1107
1108    WorldFuncCallback(WorldKey),
1109
1110    InterfaceFuncCallback(WorldKey, String),
1111
1112    /// __indirect_function_table, used for `thread.new-indirect`
1113    IndirectFunctionTable,
1114}
1115
1116impl ExportMap {
1117    fn add(
1118        &mut self,
1119        export: wasmparser::Export<'_>,
1120        encoder: &ComponentEncoder,
1121        exports: &IndexSet<WorldKey>,
1122        types: TypesRef<'_>,
1123    ) -> Result<()> {
1124        if let Some(item) = self.classify(export, encoder, exports, types)? {
1125            log::debug!("classifying export `{}` as {item:?}", export.name);
1126            let prev = self.names.insert(export.name.to_string(), item);
1127            assert!(prev.is_none());
1128        }
1129        Ok(())
1130    }
1131
1132    fn classify(
1133        &mut self,
1134        export: wasmparser::Export<'_>,
1135        encoder: &ComponentEncoder,
1136        exports: &IndexSet<WorldKey>,
1137        types: TypesRef<'_>,
1138    ) -> Result<Option<Export>> {
1139        match export.kind {
1140            ExternalKind::Func => {
1141                let ty = types[types.core_function_at(export.index)].unwrap_func();
1142                self.raw_exports.insert(export.name.to_string(), ty.clone());
1143            }
1144            _ => {}
1145        }
1146
1147        // Handle a few special-cased names first.
1148        if export.name == "canonical_abi_realloc" {
1149            return Ok(Some(Export::GeneralPurposeRealloc));
1150        } else if export.name == "cabi_import_realloc" {
1151            return Ok(Some(Export::GeneralPurposeImportRealloc));
1152        } else if export.name == "cabi_export_realloc" {
1153            return Ok(Some(Export::GeneralPurposeExportRealloc));
1154        } else if export.name == "cabi_realloc_adapter" {
1155            return Ok(Some(Export::ReallocForAdapter));
1156        }
1157
1158        let (name, names) = match export.name.strip_prefix("cm32p2") {
1159            Some(name) => (name, STANDARD),
1160            None if encoder.reject_legacy_names => return Ok(None),
1161            None => (export.name, LEGACY),
1162        };
1163
1164        if let Some(export) = self
1165            .classify_component_export(names, name, &export, encoder, exports, types)
1166            .with_context(|| format!("failed to classify export `{}`", export.name))?
1167        {
1168            return Ok(Some(export));
1169        }
1170        log::debug!("unknown export `{}`", export.name);
1171        Ok(None)
1172    }
1173
1174    fn classify_component_export(
1175        &mut self,
1176        names: &dyn NameMangling,
1177        name: &str,
1178        export: &wasmparser::Export<'_>,
1179        encoder: &ComponentEncoder,
1180        exports: &IndexSet<WorldKey>,
1181        types: TypesRef<'_>,
1182    ) -> Result<Option<Export>> {
1183        let resolve = &encoder.metadata.resolve;
1184        let world = encoder.metadata.world;
1185        match export.kind {
1186            ExternalKind::Func => {}
1187            ExternalKind::Memory => {
1188                if name == names.export_memory() {
1189                    return Ok(Some(Export::Memory));
1190                }
1191                return Ok(None);
1192            }
1193            ExternalKind::Table => {
1194                if Some(name) == names.export_indirect_function_table() {
1195                    return Ok(Some(Export::IndirectFunctionTable));
1196                }
1197                return Ok(None);
1198            }
1199            _ => return Ok(None),
1200        }
1201        let ty = types[types.core_function_at(export.index)].unwrap_func();
1202
1203        // Handle a few special-cased names first.
1204        if name == names.export_realloc() {
1205            let expected = FuncType::new([ValType::I32; 4], [ValType::I32]);
1206            validate_func_sig(name, &expected, ty)?;
1207            return Ok(Some(Export::GeneralPurposeRealloc));
1208        } else if name == names.export_initialize() {
1209            let expected = FuncType::new([], []);
1210            validate_func_sig(name, &expected, ty)?;
1211            return Ok(Some(Export::Initialize));
1212        }
1213
1214        let full_name = name;
1215        let (abi, name) = if let Some(name) = names.async_lift_name(name) {
1216            (AbiVariant::GuestExportAsync, name)
1217        } else if let Some(name) = names.async_lift_stackful_name(name) {
1218            (AbiVariant::GuestExportAsyncStackful, name)
1219        } else {
1220            (AbiVariant::GuestExport, name)
1221        };
1222
1223        // Try to match this to a known WIT export that `exports` allows.
1224        if let Some((key, id, f)) = names.match_wit_export(name, resolve, world, exports) {
1225            validate_func(resolve, ty, f, abi).with_context(|| {
1226                let key = resolve.name_world_key(key);
1227                format!("failed to validate export for `{key}`")
1228            })?;
1229            match id {
1230                Some(id) => {
1231                    return Ok(Some(Export::InterfaceFunc(
1232                        key.clone(),
1233                        id,
1234                        f.name.clone(),
1235                        abi,
1236                    )));
1237                }
1238                None => {
1239                    return Ok(Some(Export::WorldFunc(key.clone(), f.name.clone(), abi)));
1240                }
1241            }
1242        }
1243
1244        // See if this is a post-return for any known WIT export.
1245        if let Some(remaining) = names.strip_post_return(name) {
1246            if let Some((key, id, f)) = names.match_wit_export(remaining, resolve, world, exports) {
1247                validate_post_return(resolve, ty, f).with_context(|| {
1248                    let key = resolve.name_world_key(key);
1249                    format!("failed to validate export for `{key}`")
1250                })?;
1251                match id {
1252                    Some(_id) => {
1253                        return Ok(Some(Export::InterfaceFuncPostReturn(
1254                            key.clone(),
1255                            f.name.clone(),
1256                        )));
1257                    }
1258                    None => {
1259                        return Ok(Some(Export::WorldFuncPostReturn(key.clone())));
1260                    }
1261                }
1262            }
1263        }
1264
1265        if let Some(suffix) = names.async_lift_callback_name(full_name) {
1266            if let Some((key, id, f)) = names.match_wit_export(suffix, resolve, world, exports) {
1267                validate_func_sig(
1268                    full_name,
1269                    &FuncType::new([ValType::I32; 3], [ValType::I32]),
1270                    ty,
1271                )?;
1272                return Ok(Some(if id.is_some() {
1273                    Export::InterfaceFuncCallback(key.clone(), f.name.clone())
1274                } else {
1275                    Export::WorldFuncCallback(key.clone())
1276                }));
1277            }
1278        }
1279
1280        // And, finally, see if it matches a known destructor.
1281        if let Some(dtor) = names.match_wit_resource_dtor(name, resolve, world, exports) {
1282            let expected = FuncType::new([ValType::I32], []);
1283            validate_func_sig(full_name, &expected, ty)?;
1284            return Ok(Some(Export::ResourceDtor(dtor)));
1285        }
1286
1287        Ok(None)
1288    }
1289
1290    /// Returns the name of the post-return export, if any, for the `key` and
1291    /// `func` combo.
1292    pub fn post_return(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1293        self.find(|m| match m {
1294            Export::WorldFuncPostReturn(k) => k == key,
1295            Export::InterfaceFuncPostReturn(k, f) => k == key && func.name == *f,
1296            _ => false,
1297        })
1298    }
1299
1300    /// Returns the name of the async callback export, if any, for the `key` and
1301    /// `func` combo.
1302    pub fn callback(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1303        self.find(|m| match m {
1304            Export::WorldFuncCallback(k) => k == key,
1305            Export::InterfaceFuncCallback(k, f) => k == key && func.name == *f,
1306            _ => false,
1307        })
1308    }
1309
1310    pub fn abi(&self, key: &WorldKey, func: &Function) -> Option<AbiVariant> {
1311        self.names.values().find_map(|m| match m {
1312            Export::WorldFunc(k, f, abi) if k == key && func.name == *f => Some(*abi),
1313            Export::InterfaceFunc(k, _, f, abi) if k == key && func.name == *f => Some(*abi),
1314            _ => None,
1315        })
1316    }
1317
1318    /// Returns the realloc that the exported function `interface` and `func`
1319    /// are using.
1320    pub fn export_realloc_for(&self, key: &WorldKey, func: &str) -> Option<&str> {
1321        // TODO: This realloc detection should probably be improved with
1322        // some sort of scheme to have per-function reallocs like
1323        // `cabi_realloc_{name}` or something like that.
1324        let _ = (key, func);
1325
1326        if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeExportRealloc)) {
1327            return Some(name);
1328        }
1329        self.general_purpose_realloc()
1330    }
1331
1332    /// Returns the realloc that the imported function `interface` and `func`
1333    /// are using.
1334    pub fn import_realloc_for(&self, interface: Option<InterfaceId>, func: &str) -> Option<&str> {
1335        // TODO: This realloc detection should probably be improved with
1336        // some sort of scheme to have per-function reallocs like
1337        // `cabi_realloc_{name}` or something like that.
1338        let _ = (interface, func);
1339
1340        self.import_realloc_fallback()
1341    }
1342
1343    /// Returns the general-purpose realloc function to use for imports.
1344    ///
1345    /// Note that `import_realloc_for` should be used instead where possible.
1346    pub fn import_realloc_fallback(&self) -> Option<&str> {
1347        if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeImportRealloc)) {
1348            return Some(name);
1349        }
1350        self.general_purpose_realloc()
1351    }
1352
1353    /// Returns the realloc that the main module is exporting into the adapter.
1354    pub fn realloc_to_import_into_adapter(&self) -> Option<&str> {
1355        if let Some(name) = self.find(|m| matches!(m, Export::ReallocForAdapter)) {
1356            return Some(name);
1357        }
1358        self.general_purpose_realloc()
1359    }
1360
1361    fn general_purpose_realloc(&self) -> Option<&str> {
1362        self.find(|m| matches!(m, Export::GeneralPurposeRealloc))
1363    }
1364
1365    /// Returns the memory, if exported, for this module.
1366    pub fn memory(&self) -> Option<&str> {
1367        self.find(|m| matches!(m, Export::Memory))
1368    }
1369
1370    /// Returns the indirect function table, if exported, for this module.
1371    pub fn indirect_function_table(&self) -> Option<&str> {
1372        self.find(|t| matches!(t, Export::IndirectFunctionTable))
1373    }
1374
1375    /// Returns the `_initialize` intrinsic, if exported, for this module.
1376    pub fn initialize(&self) -> Option<&str> {
1377        self.find(|m| matches!(m, Export::Initialize))
1378    }
1379
1380    /// Returns destructor for the exported resource `ty`, if it was listed.
1381    pub fn resource_dtor(&self, ty: TypeId) -> Option<&str> {
1382        self.find(|m| match m {
1383            Export::ResourceDtor(t) => *t == ty,
1384            _ => false,
1385        })
1386    }
1387
1388    /// NB: this is a linear search and if that's ever a problem this should
1389    /// build up an inverse map during construction to accelerate it.
1390    fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1391        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1392        Some(name)
1393    }
1394
1395    /// Iterates over all exports of this module.
1396    pub fn iter(&self) -> impl Iterator<Item = (&str, &Export)> + '_ {
1397        self.names.iter().map(|(n, e)| (n.as_str(), e))
1398    }
1399
1400    fn validate(&self, encoder: &ComponentEncoder, exports: &IndexSet<WorldKey>) -> Result<()> {
1401        let resolve = &encoder.metadata.resolve;
1402        let world = encoder.metadata.world;
1403        // Multi-memory isn't supported because otherwise we don't know what
1404        // memory to put things in.
1405        if self
1406            .names
1407            .values()
1408            .filter(|m| matches!(m, Export::Memory))
1409            .count()
1410            > 1
1411        {
1412            bail!("cannot componentize module that exports multiple memories")
1413        }
1414
1415        // Every async-with-callback-lifted export must have a callback.
1416        for (name, export) in &self.names {
1417            match export {
1418                Export::WorldFunc(_, _, AbiVariant::GuestExportAsync) => {
1419                    if !matches!(
1420                        self.names.get(&format!("[callback]{name}")),
1421                        Some(Export::WorldFuncCallback(_))
1422                    ) {
1423                        bail!("missing callback for `{name}`");
1424                    }
1425                }
1426                Export::InterfaceFunc(_, _, _, AbiVariant::GuestExportAsync) => {
1427                    if !matches!(
1428                        self.names.get(&format!("[callback]{name}")),
1429                        Some(Export::InterfaceFuncCallback(_, _))
1430                    ) {
1431                        bail!("missing callback for `{name}`");
1432                    }
1433                }
1434                _ => {}
1435            }
1436        }
1437
1438        // All of `exports` must be exported and found within this module.
1439        for export in exports {
1440            let require_interface_func = |interface: InterfaceId, name: &str| -> Result<()> {
1441                let result = self.find(|e| match e {
1442                    Export::InterfaceFunc(_, id, s, _) => interface == *id && name == s,
1443                    _ => false,
1444                });
1445                if result.is_some() {
1446                    Ok(())
1447                } else {
1448                    let export = resolve.name_world_key(export);
1449                    bail!("failed to find export of interface `{export}` function `{name}`")
1450                }
1451            };
1452            let require_world_func = |name: &str| -> Result<()> {
1453                let result = self.find(|e| match e {
1454                    Export::WorldFunc(_, s, _) => name == s,
1455                    _ => false,
1456                });
1457                if result.is_some() {
1458                    Ok(())
1459                } else {
1460                    bail!("failed to find export of function `{name}`")
1461                }
1462            };
1463            match &resolve.worlds[world].exports[export] {
1464                WorldItem::Interface { id, .. } => {
1465                    for (name, _) in resolve.interfaces[*id].functions.iter() {
1466                        require_interface_func(*id, name)?;
1467                    }
1468                }
1469                WorldItem::Function(f) => {
1470                    require_world_func(&f.name)?;
1471                }
1472                WorldItem::Type(_) => unreachable!(),
1473            }
1474        }
1475
1476        Ok(())
1477    }
1478}
1479
1480/// A builtin that may be declared as cancellable.
1481struct MaybeCancellable<T> {
1482    #[allow(unused)]
1483    inner: T,
1484    cancellable: bool,
1485}
1486
1487/// A builtin that may be declared as async-lowered.
1488struct MaybeAsyncLowered<T> {
1489    inner: T,
1490    async_lowered: bool,
1491}
1492
1493/// Context passed to `NameMangling` implementations of stream and future functions
1494/// to help with looking up payload information.
1495struct PayloadLookupContext<'a> {
1496    resolve: &'a Resolve,
1497    world: &'a World,
1498    id: Option<InterfaceId>,
1499    import: bool,
1500    key: Option<WorldKey>,
1501}
1502
1503/// Trait dispatch and definition for parsing and interpreting "mangled names"
1504/// which show up in imports and exports of the component model.
1505///
1506/// This trait is used to implement classification of imports and exports in the
1507/// component model. The methods on `ImportMap` and `ExportMap` will use this to
1508/// determine what an import is and how it's lifted/lowered in the world being
1509/// bound.
1510///
1511/// This trait has a bit of history behind it as well. Before
1512/// WebAssembly/component-model#378 there was no standard naming scheme for core
1513/// wasm imports or exports when componenitizing. This meant that
1514/// `wit-component` implemented a particular scheme which mostly worked but was
1515/// mostly along the lines of "this at least works" rather than "someone sat
1516/// down and designed this". Since then, however, an standard naming scheme has
1517/// now been specified which was indeed designed.
1518///
1519/// This trait serves as the bridge between these two. The historical naming
1520/// scheme is still supported for now through the `Legacy` implementation below
1521/// and will be for some time. The transition plan at this time is to support
1522/// the new scheme, eventually get it supported in bindings generators, and once
1523/// that's all propagated remove support for the legacy scheme.
1524trait NameMangling {
1525    fn import_root(&self) -> &str;
1526    fn import_non_root_prefix(&self) -> &str;
1527    fn import_exported_intrinsic_prefix(&self) -> &str;
1528    fn export_memory(&self) -> &str;
1529    fn export_initialize(&self) -> &str;
1530    fn export_realloc(&self) -> &str;
1531    fn export_indirect_function_table(&self) -> Option<&str>;
1532    fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1533    fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1534    fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1535    fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1536    fn task_cancel(&self, name: &str) -> bool;
1537    fn backpressure_inc(&self, name: &str) -> bool;
1538    fn backpressure_dec(&self, name: &str) -> bool;
1539    fn waitable_set_new(&self, name: &str) -> bool;
1540    fn waitable_set_wait(&self, name: &str) -> Option<MaybeCancellable<()>>;
1541    fn waitable_set_poll(&self, name: &str) -> Option<MaybeCancellable<()>>;
1542    fn waitable_set_drop(&self, name: &str) -> bool;
1543    fn waitable_join(&self, name: &str) -> bool;
1544    fn thread_yield(&self, name: &str) -> Option<MaybeCancellable<()>>;
1545    fn subtask_drop(&self, name: &str) -> bool;
1546    fn subtask_cancel(&self, name: &str) -> Option<MaybeAsyncLowered<()>>;
1547    fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1548    fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1549    fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1550    fn error_context_new(&self, name: &str) -> Option<StringEncoding>;
1551    fn error_context_debug_message(&self, name: &str) -> Option<StringEncoding>;
1552    fn error_context_drop(&self, name: &str) -> bool;
1553    fn context_get(&self, name: &str) -> Option<u32>;
1554    fn context_set(&self, name: &str) -> Option<u32>;
1555    fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo>;
1556    fn future_write(
1557        &self,
1558        lookup_context: &PayloadLookupContext,
1559        name: &str,
1560    ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1561    fn future_read(
1562        &self,
1563        lookup_context: &PayloadLookupContext,
1564        name: &str,
1565    ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1566    fn future_cancel_write(
1567        &self,
1568        lookup_context: &PayloadLookupContext,
1569        name: &str,
1570    ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1571    fn future_cancel_read(
1572        &self,
1573        lookup_context: &PayloadLookupContext,
1574        name: &str,
1575    ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1576    fn future_drop_writable(
1577        &self,
1578        lookup_context: &PayloadLookupContext,
1579        name: &str,
1580    ) -> Option<PayloadInfo>;
1581    fn future_drop_readable(
1582        &self,
1583        lookup_context: &PayloadLookupContext,
1584        name: &str,
1585    ) -> Option<PayloadInfo>;
1586    fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo>;
1587    fn stream_write(
1588        &self,
1589        lookup_context: &PayloadLookupContext,
1590        name: &str,
1591    ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1592    fn stream_read(
1593        &self,
1594        lookup_context: &PayloadLookupContext,
1595        name: &str,
1596    ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1597    fn stream_cancel_write(
1598        &self,
1599        lookup_context: &PayloadLookupContext,
1600        name: &str,
1601    ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1602    fn stream_cancel_read(
1603        &self,
1604        lookup_context: &PayloadLookupContext,
1605        name: &str,
1606    ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1607    fn stream_drop_writable(
1608        &self,
1609        lookup_context: &PayloadLookupContext,
1610        name: &str,
1611    ) -> Option<PayloadInfo>;
1612    fn stream_drop_readable(
1613        &self,
1614        lookup_context: &PayloadLookupContext,
1615        name: &str,
1616    ) -> Option<PayloadInfo>;
1617    fn thread_index(&self, name: &str) -> bool;
1618    fn thread_new_indirect(&self, name: &str) -> bool;
1619    fn thread_switch_to(&self, name: &str) -> Option<MaybeCancellable<()>>;
1620    fn thread_suspend(&self, name: &str) -> Option<MaybeCancellable<()>>;
1621    fn thread_resume_later(&self, name: &str) -> bool;
1622    fn thread_yield_to(&self, name: &str) -> Option<MaybeCancellable<()>>;
1623    fn module_to_interface(
1624        &self,
1625        module: &str,
1626        resolve: &Resolve,
1627        items: &IndexMap<WorldKey, WorldItem>,
1628    ) -> Result<(WorldKey, InterfaceId)>;
1629    fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str>;
1630    fn match_wit_export<'a>(
1631        &self,
1632        export_name: &str,
1633        resolve: &'a Resolve,
1634        world: WorldId,
1635        exports: &'a IndexSet<WorldKey>,
1636    ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)>;
1637    fn match_wit_resource_dtor<'a>(
1638        &self,
1639        export_name: &str,
1640        resolve: &'a Resolve,
1641        world: WorldId,
1642        exports: &'a IndexSet<WorldKey>,
1643    ) -> Option<TypeId>;
1644    fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant);
1645    fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant);
1646}
1647
1648/// Definition of the "standard" naming scheme which currently starts with
1649/// "cm32p2". Note that wasm64 is not supported at this time.
1650struct Standard;
1651
1652const STANDARD: &'static dyn NameMangling = &Standard;
1653
1654impl NameMangling for Standard {
1655    fn import_root(&self) -> &str {
1656        ""
1657    }
1658    fn import_non_root_prefix(&self) -> &str {
1659        "|"
1660    }
1661    fn import_exported_intrinsic_prefix(&self) -> &str {
1662        "_ex_"
1663    }
1664    fn export_memory(&self) -> &str {
1665        "_memory"
1666    }
1667    fn export_initialize(&self) -> &str {
1668        "_initialize"
1669    }
1670    fn export_realloc(&self) -> &str {
1671        "_realloc"
1672    }
1673    fn export_indirect_function_table(&self) -> Option<&str> {
1674        None
1675    }
1676    fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1677        name.strip_suffix("_drop")
1678    }
1679    fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1680        name.strip_suffix("_new")
1681    }
1682    fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1683        name.strip_suffix("_rep")
1684    }
1685    fn task_return_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1686        None
1687    }
1688    fn task_cancel(&self, _name: &str) -> bool {
1689        false
1690    }
1691    fn backpressure_inc(&self, _name: &str) -> bool {
1692        false
1693    }
1694    fn backpressure_dec(&self, _name: &str) -> bool {
1695        false
1696    }
1697    fn waitable_set_new(&self, _name: &str) -> bool {
1698        false
1699    }
1700    fn waitable_set_wait(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1701        None
1702    }
1703    fn waitable_set_poll(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1704        None
1705    }
1706    fn waitable_set_drop(&self, _name: &str) -> bool {
1707        false
1708    }
1709    fn waitable_join(&self, _name: &str) -> bool {
1710        false
1711    }
1712    fn thread_yield(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1713        None
1714    }
1715    fn subtask_drop(&self, _name: &str) -> bool {
1716        false
1717    }
1718    fn subtask_cancel(&self, _name: &str) -> Option<MaybeAsyncLowered<()>> {
1719        None
1720    }
1721    fn async_lift_callback_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1722        None
1723    }
1724    fn async_lift_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1725        None
1726    }
1727    fn async_lift_stackful_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1728        None
1729    }
1730    fn error_context_new(&self, _name: &str) -> Option<StringEncoding> {
1731        None
1732    }
1733    fn error_context_debug_message(&self, _name: &str) -> Option<StringEncoding> {
1734        None
1735    }
1736    fn error_context_drop(&self, _name: &str) -> bool {
1737        false
1738    }
1739    fn context_get(&self, _name: &str) -> Option<u32> {
1740        None
1741    }
1742    fn context_set(&self, _name: &str) -> Option<u32> {
1743        None
1744    }
1745    fn thread_index(&self, _name: &str) -> bool {
1746        false
1747    }
1748    fn thread_new_indirect(&self, _name: &str) -> bool {
1749        false
1750    }
1751    fn thread_switch_to(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1752        None
1753    }
1754    fn thread_suspend(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1755        None
1756    }
1757    fn thread_resume_later(&self, _name: &str) -> bool {
1758        false
1759    }
1760    fn thread_yield_to(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1761        None
1762    }
1763    fn future_new(
1764        &self,
1765        _lookup_context: &PayloadLookupContext,
1766        _name: &str,
1767    ) -> Option<PayloadInfo> {
1768        None
1769    }
1770    fn future_write(
1771        &self,
1772        _lookup_context: &PayloadLookupContext,
1773        _name: &str,
1774    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1775        None
1776    }
1777    fn future_read(
1778        &self,
1779        _lookup_context: &PayloadLookupContext,
1780        _name: &str,
1781    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1782        None
1783    }
1784    fn future_cancel_write(
1785        &self,
1786        _lookup_context: &PayloadLookupContext,
1787        _name: &str,
1788    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1789        None
1790    }
1791    fn future_cancel_read(
1792        &self,
1793        _lookup_context: &PayloadLookupContext,
1794        _name: &str,
1795    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1796        None
1797    }
1798    fn future_drop_writable(
1799        &self,
1800        _lookup_context: &PayloadLookupContext,
1801        _name: &str,
1802    ) -> Option<PayloadInfo> {
1803        None
1804    }
1805    fn future_drop_readable(
1806        &self,
1807        _lookup_context: &PayloadLookupContext,
1808        _name: &str,
1809    ) -> Option<PayloadInfo> {
1810        None
1811    }
1812    fn stream_new(
1813        &self,
1814        _lookup_context: &PayloadLookupContext,
1815        _name: &str,
1816    ) -> Option<PayloadInfo> {
1817        None
1818    }
1819    fn stream_write(
1820        &self,
1821        _lookup_context: &PayloadLookupContext,
1822        _name: &str,
1823    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1824        None
1825    }
1826    fn stream_read(
1827        &self,
1828        _lookup_context: &PayloadLookupContext,
1829        _name: &str,
1830    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1831        None
1832    }
1833    fn stream_cancel_write(
1834        &self,
1835        _lookup_context: &PayloadLookupContext,
1836        _name: &str,
1837    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1838        None
1839    }
1840    fn stream_cancel_read(
1841        &self,
1842        _lookup_context: &PayloadLookupContext,
1843        _name: &str,
1844    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1845        None
1846    }
1847    fn stream_drop_writable(
1848        &self,
1849        _lookup_context: &PayloadLookupContext,
1850        _name: &str,
1851    ) -> Option<PayloadInfo> {
1852        None
1853    }
1854    fn stream_drop_readable(
1855        &self,
1856        _lookup_context: &PayloadLookupContext,
1857        _name: &str,
1858    ) -> Option<PayloadInfo> {
1859        None
1860    }
1861    fn module_to_interface(
1862        &self,
1863        interface: &str,
1864        resolve: &Resolve,
1865        items: &IndexMap<WorldKey, WorldItem>,
1866    ) -> Result<(WorldKey, InterfaceId)> {
1867        for (key, item) in items.iter() {
1868            let id = match key {
1869                // Bare keys are matched exactly against `interface`
1870                WorldKey::Name(name) => match item {
1871                    WorldItem::Interface { id, .. } if name == interface => *id,
1872                    _ => continue,
1873                },
1874                // ID-identified keys are matched with their "canonical name"
1875                WorldKey::Interface(id) => {
1876                    if resolve.canonicalized_id_of(*id).as_deref() != Some(interface) {
1877                        continue;
1878                    }
1879                    *id
1880                }
1881            };
1882            return Ok((key.clone(), id));
1883        }
1884        bail!("failed to find world item corresponding to interface `{interface}`")
1885    }
1886    fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> {
1887        name.strip_suffix("_post")
1888    }
1889    fn match_wit_export<'a>(
1890        &self,
1891        export_name: &str,
1892        resolve: &'a Resolve,
1893        world: WorldId,
1894        exports: &'a IndexSet<WorldKey>,
1895    ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
1896        if let Some(world_export_name) = export_name.strip_prefix("||") {
1897            let key = exports.get(&WorldKey::Name(world_export_name.to_string()))?;
1898            match &resolve.worlds[world].exports[key] {
1899                WorldItem::Function(f) => return Some((key, None, f)),
1900                _ => return None,
1901            }
1902        }
1903
1904        let (key, id, func_name) =
1905            self.match_wit_interface(export_name, resolve, world, exports)?;
1906        let func = resolve.interfaces[id].functions.get(func_name)?;
1907        Some((key, Some(id), func))
1908    }
1909
1910    fn match_wit_resource_dtor<'a>(
1911        &self,
1912        export_name: &str,
1913        resolve: &'a Resolve,
1914        world: WorldId,
1915        exports: &'a IndexSet<WorldKey>,
1916    ) -> Option<TypeId> {
1917        let (_key, id, name) =
1918            self.match_wit_interface(export_name.strip_suffix("_dtor")?, resolve, world, exports)?;
1919        let ty = *resolve.interfaces[id].types.get(name)?;
1920        match resolve.types[ty].kind {
1921            TypeDefKind::Resource => Some(ty),
1922            _ => None,
1923        }
1924    }
1925
1926    fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
1927        (name, AbiVariant::GuestImport)
1928    }
1929    fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
1930        (name, AbiVariant::GuestImport)
1931    }
1932}
1933
1934impl Standard {
1935    fn match_wit_interface<'a, 'b>(
1936        &self,
1937        export_name: &'b str,
1938        resolve: &'a Resolve,
1939        world: WorldId,
1940        exports: &'a IndexSet<WorldKey>,
1941    ) -> Option<(&'a WorldKey, InterfaceId, &'b str)> {
1942        let world = &resolve.worlds[world];
1943        let export_name = export_name.strip_prefix("|")?;
1944
1945        for export in exports {
1946            let id = match &world.exports[export] {
1947                WorldItem::Interface { id, .. } => *id,
1948                WorldItem::Function(_) => continue,
1949                WorldItem::Type(_) => unreachable!(),
1950            };
1951            let remaining = match export {
1952                WorldKey::Name(name) => export_name.strip_prefix(name),
1953                WorldKey::Interface(_) => {
1954                    let prefix = resolve.canonicalized_id_of(id).unwrap();
1955                    export_name.strip_prefix(&prefix)
1956                }
1957            };
1958            let item_name = match remaining.and_then(|s| s.strip_prefix("|")) {
1959                Some(name) => name,
1960                None => continue,
1961            };
1962            return Some((export, id, item_name));
1963        }
1964
1965        None
1966    }
1967}
1968
1969/// Definition of wit-component's "legacy" naming scheme which predates
1970/// WebAssembly/component-model#378.
1971struct Legacy;
1972
1973const LEGACY: &'static dyn NameMangling = &Legacy;
1974
1975impl Legacy {
1976    // Looks for `[$prefix-N]foo` within `name`. If found then `foo` is
1977    // used to find a function within `id` and `world` above. Once found
1978    // then `N` is used to index within that function to extract a
1979    // future/stream type. If that's all found then a `PayloadInfo` is
1980    // returned to get attached to an intrinsic.
1981    fn prefixed_payload(
1982        &self,
1983        lookup_context: &PayloadLookupContext,
1984        name: &str,
1985        prefix: &str,
1986    ) -> Option<PayloadInfo> {
1987        // parse the `prefix` into `func_name` and `type_index`, bailing out
1988        // with `None` if anything doesn't match.
1989        let (index_or_unit, func_name) = prefixed_intrinsic(name, prefix)?;
1990        let ty = match index_or_unit {
1991            "unit" => {
1992                if name.starts_with("[future") {
1993                    PayloadType::UnitFuture
1994                } else if name.starts_with("[stream") {
1995                    PayloadType::UnitStream
1996                } else {
1997                    unreachable!()
1998                }
1999            }
2000            other => {
2001                // Note that this is parsed as a `u32` to ensure that the
2002                // integer parsing is the same across platforms regardless of
2003                // the the width of `usize`.
2004                let type_index = other.parse::<u32>().ok()? as usize;
2005
2006                // Double-check that `func_name` is indeed a function name within
2007                // this interface/world. Then additionally double-check that
2008                // `type_index` is indeed a valid index for this function's type
2009                // signature.
2010                let function = get_function(
2011                    lookup_context.resolve,
2012                    lookup_context.world,
2013                    func_name,
2014                    lookup_context.id,
2015                    lookup_context.import,
2016                )
2017                .ok()?;
2018                PayloadType::Type {
2019                    id: *function
2020                        .find_futures_and_streams(lookup_context.resolve)
2021                        .get(type_index)?,
2022                    function: function.name.clone(),
2023                }
2024            }
2025        };
2026
2027        // And if all that passes wrap up everything in a `PayloadInfo`.
2028        Some(PayloadInfo {
2029            name: name.to_string(),
2030            ty,
2031            key: lookup_context
2032                .key
2033                .clone()
2034                .unwrap_or_else(|| WorldKey::Name(name.to_string())),
2035            interface: lookup_context.id,
2036            imported: lookup_context.import,
2037        })
2038    }
2039
2040    fn maybe_async_lowered_payload(
2041        &self,
2042        lookup_context: &PayloadLookupContext,
2043        name: &str,
2044        prefix: &str,
2045    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2046        let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name);
2047        let payload = self.prefixed_payload(lookup_context, clean_name, prefix)?;
2048        Some(MaybeAsyncLowered {
2049            inner: payload,
2050            async_lowered,
2051        })
2052    }
2053
2054    fn strip_async_lowered_prefix<'a>(&self, name: &'a str) -> (bool, &'a str) {
2055        name.strip_prefix("[async-lower]")
2056            .map_or((false, name), |s| (true, s))
2057    }
2058    fn match_with_async_lowered_prefix(
2059        &self,
2060        name: &str,
2061        expected: &str,
2062    ) -> Option<MaybeAsyncLowered<()>> {
2063        let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name);
2064        if clean_name == expected {
2065            Some(MaybeAsyncLowered {
2066                inner: (),
2067                async_lowered,
2068            })
2069        } else {
2070            None
2071        }
2072    }
2073    fn strip_cancellable_prefix<'a>(&self, name: &'a str) -> (bool, &'a str) {
2074        name.strip_prefix("[cancellable]")
2075            .map_or((false, name), |s| (true, s))
2076    }
2077    fn match_with_cancellable_prefix(
2078        &self,
2079        name: &str,
2080        expected: &str,
2081    ) -> Option<MaybeCancellable<()>> {
2082        let (cancellable, clean_name) = self.strip_cancellable_prefix(name);
2083        if clean_name == expected {
2084            Some(MaybeCancellable {
2085                inner: (),
2086                cancellable,
2087            })
2088        } else {
2089            None
2090        }
2091    }
2092}
2093
2094impl NameMangling for Legacy {
2095    fn import_root(&self) -> &str {
2096        "$root"
2097    }
2098    fn import_non_root_prefix(&self) -> &str {
2099        ""
2100    }
2101    fn import_exported_intrinsic_prefix(&self) -> &str {
2102        "[export]"
2103    }
2104    fn export_memory(&self) -> &str {
2105        "memory"
2106    }
2107    fn export_initialize(&self) -> &str {
2108        "_initialize"
2109    }
2110    fn export_realloc(&self) -> &str {
2111        "cabi_realloc"
2112    }
2113    fn export_indirect_function_table(&self) -> Option<&str> {
2114        Some("__indirect_function_table")
2115    }
2116    fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2117        name.strip_prefix("[resource-drop]")
2118    }
2119    fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2120        name.strip_prefix("[resource-new]")
2121    }
2122    fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2123        name.strip_prefix("[resource-rep]")
2124    }
2125    fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2126        name.strip_prefix("[task-return]")
2127    }
2128    fn task_cancel(&self, name: &str) -> bool {
2129        name == "[task-cancel]"
2130    }
2131    fn backpressure_inc(&self, name: &str) -> bool {
2132        name == "[backpressure-inc]"
2133    }
2134    fn backpressure_dec(&self, name: &str) -> bool {
2135        name == "[backpressure-dec]"
2136    }
2137    fn waitable_set_new(&self, name: &str) -> bool {
2138        name == "[waitable-set-new]"
2139    }
2140    fn waitable_set_wait(&self, name: &str) -> Option<MaybeCancellable<()>> {
2141        self.match_with_cancellable_prefix(name, "[waitable-set-wait]")
2142    }
2143    fn waitable_set_poll(&self, name: &str) -> Option<MaybeCancellable<()>> {
2144        self.match_with_cancellable_prefix(name, "[waitable-set-poll]")
2145    }
2146    fn waitable_set_drop(&self, name: &str) -> bool {
2147        name == "[waitable-set-drop]"
2148    }
2149    fn waitable_join(&self, name: &str) -> bool {
2150        name == "[waitable-join]"
2151    }
2152    fn thread_yield(&self, name: &str) -> Option<MaybeCancellable<()>> {
2153        self.match_with_cancellable_prefix(name, "[thread-yield]")
2154    }
2155    fn subtask_drop(&self, name: &str) -> bool {
2156        name == "[subtask-drop]"
2157    }
2158    fn subtask_cancel(&self, name: &str) -> Option<MaybeAsyncLowered<()>> {
2159        self.match_with_async_lowered_prefix(name, "[subtask-cancel]")
2160    }
2161    fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2162        name.strip_prefix("[callback][async-lift]")
2163    }
2164    fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2165        name.strip_prefix("[async-lift]")
2166    }
2167    fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2168        name.strip_prefix("[async-lift-stackful]")
2169    }
2170    fn error_context_new(&self, name: &str) -> Option<StringEncoding> {
2171        match name {
2172            "[error-context-new-utf8]" => Some(StringEncoding::UTF8),
2173            "[error-context-new-utf16]" => Some(StringEncoding::UTF16),
2174            "[error-context-new-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
2175            _ => None,
2176        }
2177    }
2178    fn error_context_debug_message(&self, name: &str) -> Option<StringEncoding> {
2179        match name {
2180            "[error-context-debug-message-utf8]" => Some(StringEncoding::UTF8),
2181            "[error-context-debug-message-utf16]" => Some(StringEncoding::UTF16),
2182            "[error-context-debug-message-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
2183            _ => None,
2184        }
2185    }
2186    fn error_context_drop(&self, name: &str) -> bool {
2187        name == "[error-context-drop]"
2188    }
2189    fn context_get(&self, name: &str) -> Option<u32> {
2190        let (n, rest) = prefixed_integer(name, "[context-get-")?;
2191        if rest.is_empty() { Some(n) } else { None }
2192    }
2193    fn context_set(&self, name: &str) -> Option<u32> {
2194        let (n, rest) = prefixed_integer(name, "[context-set-")?;
2195        if rest.is_empty() { Some(n) } else { None }
2196    }
2197    fn thread_index(&self, name: &str) -> bool {
2198        name == "[thread-index]"
2199    }
2200    fn thread_new_indirect(&self, name: &str) -> bool {
2201        // For now, we'll fix the type of the start function and the table to extract it from
2202        name == "[thread-new-indirect-v0]"
2203    }
2204    fn thread_switch_to(&self, name: &str) -> Option<MaybeCancellable<()>> {
2205        self.match_with_cancellable_prefix(name, "[thread-switch-to]")
2206    }
2207    fn thread_suspend(&self, name: &str) -> Option<MaybeCancellable<()>> {
2208        self.match_with_cancellable_prefix(name, "[thread-suspend]")
2209    }
2210    fn thread_resume_later(&self, name: &str) -> bool {
2211        name == "[thread-resume-later]"
2212    }
2213    fn thread_yield_to(&self, name: &str) -> Option<MaybeCancellable<()>> {
2214        self.match_with_cancellable_prefix(name, "[thread-yield-to]")
2215    }
2216    fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo> {
2217        self.prefixed_payload(lookup_context, name, "[future-new-")
2218    }
2219    fn future_write(
2220        &self,
2221        lookup_context: &PayloadLookupContext,
2222        name: &str,
2223    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2224        self.maybe_async_lowered_payload(lookup_context, name, "[future-write-")
2225    }
2226    fn future_read(
2227        &self,
2228        lookup_context: &PayloadLookupContext,
2229        name: &str,
2230    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2231        self.maybe_async_lowered_payload(lookup_context, name, "[future-read-")
2232    }
2233    fn future_cancel_write(
2234        &self,
2235        lookup_context: &PayloadLookupContext,
2236        name: &str,
2237    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2238        self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-write-")
2239    }
2240    fn future_cancel_read(
2241        &self,
2242        lookup_context: &PayloadLookupContext,
2243        name: &str,
2244    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2245        self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-read-")
2246    }
2247    fn future_drop_writable(
2248        &self,
2249        lookup_context: &PayloadLookupContext,
2250        name: &str,
2251    ) -> Option<PayloadInfo> {
2252        self.prefixed_payload(lookup_context, name, "[future-drop-writable-")
2253    }
2254    fn future_drop_readable(
2255        &self,
2256        lookup_context: &PayloadLookupContext,
2257        name: &str,
2258    ) -> Option<PayloadInfo> {
2259        self.prefixed_payload(lookup_context, name, "[future-drop-readable-")
2260    }
2261    fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo> {
2262        self.prefixed_payload(lookup_context, name, "[stream-new-")
2263    }
2264    fn stream_write(
2265        &self,
2266        lookup_context: &PayloadLookupContext,
2267        name: &str,
2268    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2269        self.maybe_async_lowered_payload(lookup_context, name, "[stream-write-")
2270    }
2271    fn stream_read(
2272        &self,
2273        lookup_context: &PayloadLookupContext,
2274        name: &str,
2275    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2276        self.maybe_async_lowered_payload(lookup_context, name, "[stream-read-")
2277    }
2278    fn stream_cancel_write(
2279        &self,
2280        lookup_context: &PayloadLookupContext,
2281        name: &str,
2282    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2283        self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-write-")
2284    }
2285    fn stream_cancel_read(
2286        &self,
2287        lookup_context: &PayloadLookupContext,
2288        name: &str,
2289    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2290        self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-read-")
2291    }
2292    fn stream_drop_writable(
2293        &self,
2294        lookup_context: &PayloadLookupContext,
2295        name: &str,
2296    ) -> Option<PayloadInfo> {
2297        self.prefixed_payload(lookup_context, name, "[stream-drop-writable-")
2298    }
2299    fn stream_drop_readable(
2300        &self,
2301        lookup_context: &PayloadLookupContext,
2302        name: &str,
2303    ) -> Option<PayloadInfo> {
2304        self.prefixed_payload(lookup_context, name, "[stream-drop-readable-")
2305    }
2306    fn module_to_interface(
2307        &self,
2308        module: &str,
2309        resolve: &Resolve,
2310        items: &IndexMap<WorldKey, WorldItem>,
2311    ) -> Result<(WorldKey, InterfaceId)> {
2312        // First see if this is a bare name
2313        let bare_name = WorldKey::Name(module.to_string());
2314        if let Some(WorldItem::Interface { id, .. }) = items.get(&bare_name) {
2315            return Ok((bare_name, *id));
2316        }
2317
2318        // ... and if this isn't a bare name then it's time to do some parsing
2319        // related to interfaces, versions, and such. First up the `module` name
2320        // is parsed as a normal component name from `wasmparser` to see if it's
2321        // of the "interface kind". If it's not then that means the above match
2322        // should have been a hit but it wasn't, so an error is returned.
2323        let kebab_name = ComponentName::new(module, 0);
2324        let name = match kebab_name.as_ref().map(|k| k.kind()) {
2325            Ok(ComponentNameKind::Interface(name)) => name,
2326            _ => bail!("module requires an import interface named `{module}`"),
2327        };
2328
2329        // Prioritize an exact match based on versions, so try that first.
2330        let pkgname = PackageName {
2331            namespace: name.namespace().to_string(),
2332            name: name.package().to_string(),
2333            version: name.version(),
2334        };
2335        if let Some(pkg) = resolve.package_names.get(&pkgname) {
2336            if let Some(id) = resolve.packages[*pkg]
2337                .interfaces
2338                .get(name.interface().as_str())
2339            {
2340                let key = WorldKey::Interface(*id);
2341                if items.contains_key(&key) {
2342                    return Ok((key, *id));
2343                }
2344            }
2345        }
2346
2347        // If an exact match wasn't found then instead search for the first
2348        // match based on versions. This means that a core wasm import for
2349        // "1.2.3" might end up matching an interface at "1.2.4", for example.
2350        // (or "1.2.2", depending on what's available).
2351        for (key, _) in items {
2352            let id = match key {
2353                WorldKey::Interface(id) => *id,
2354                WorldKey::Name(_) => continue,
2355            };
2356            // Make sure the interface names match
2357            let interface = &resolve.interfaces[id];
2358            if interface.name.as_ref().unwrap() != name.interface().as_str() {
2359                continue;
2360            }
2361
2362            // Make sure the package name (without version) matches
2363            let pkg = &resolve.packages[interface.package.unwrap()];
2364            if pkg.name.namespace != pkgname.namespace || pkg.name.name != pkgname.name {
2365                continue;
2366            }
2367
2368            let module_version = match name.version() {
2369                Some(version) => version,
2370                None => continue,
2371            };
2372            let pkg_version = match &pkg.name.version {
2373                Some(version) => version,
2374                None => continue,
2375            };
2376
2377            // Test if the two semver versions are compatible
2378            let module_compat = PackageName::version_compat_track(&module_version);
2379            let pkg_compat = PackageName::version_compat_track(pkg_version);
2380            if module_compat == pkg_compat {
2381                return Ok((key.clone(), id));
2382            }
2383        }
2384
2385        bail!("module requires an import interface named `{module}`")
2386    }
2387    fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> {
2388        name.strip_prefix("cabi_post_")
2389    }
2390    fn match_wit_export<'a>(
2391        &self,
2392        export_name: &str,
2393        resolve: &'a Resolve,
2394        world: WorldId,
2395        exports: &'a IndexSet<WorldKey>,
2396    ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
2397        let world = &resolve.worlds[world];
2398        for name in exports {
2399            match &world.exports[name] {
2400                WorldItem::Function(f) => {
2401                    if f.legacy_core_export_name(None) == export_name {
2402                        return Some((name, None, f));
2403                    }
2404                }
2405                WorldItem::Interface { id, .. } => {
2406                    let string = resolve.name_world_key(name);
2407                    for (_, func) in resolve.interfaces[*id].functions.iter() {
2408                        if func.legacy_core_export_name(Some(&string)) == export_name {
2409                            return Some((name, Some(*id), func));
2410                        }
2411                    }
2412                }
2413
2414                WorldItem::Type(_) => unreachable!(),
2415            }
2416        }
2417
2418        None
2419    }
2420
2421    fn match_wit_resource_dtor<'a>(
2422        &self,
2423        export_name: &str,
2424        resolve: &'a Resolve,
2425        world: WorldId,
2426        exports: &'a IndexSet<WorldKey>,
2427    ) -> Option<TypeId> {
2428        let world = &resolve.worlds[world];
2429        for name in exports {
2430            let id = match &world.exports[name] {
2431                WorldItem::Interface { id, .. } => *id,
2432                WorldItem::Function(_) => continue,
2433                WorldItem::Type(_) => unreachable!(),
2434            };
2435            let name = resolve.name_world_key(name);
2436            let resource = match export_name
2437                .strip_prefix(&name)
2438                .and_then(|s| s.strip_prefix("#[dtor]"))
2439                .and_then(|r| resolve.interfaces[id].types.get(r))
2440            {
2441                Some(id) => *id,
2442                None => continue,
2443            };
2444
2445            match resolve.types[resource].kind {
2446                TypeDefKind::Resource => {}
2447                _ => continue,
2448            }
2449
2450            return Some(resource);
2451        }
2452
2453        None
2454    }
2455
2456    fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2457        let (async_abi, name) = self.strip_async_lowered_prefix(name);
2458        (
2459            name,
2460            if async_abi {
2461                AbiVariant::GuestImportAsync
2462            } else {
2463                AbiVariant::GuestImport
2464            },
2465        )
2466    }
2467    fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2468        let (async_abi, name) = self.strip_async_lowered_prefix(name);
2469        (
2470            name,
2471            if async_abi {
2472                AbiVariant::GuestImportAsync
2473            } else {
2474                AbiVariant::GuestImport
2475            },
2476        )
2477    }
2478}
2479
2480/// This function validates the following:
2481///
2482/// * The `bytes` represent a valid core WebAssembly module.
2483/// * The module's imports are all satisfied by the given `imports` interfaces
2484///   or the `adapters` set.
2485/// * The given default and exported interfaces are satisfied by the module's
2486///   exports.
2487///
2488/// The `ValidatedModule` return value contains the metadata which describes the
2489/// input module on success. This is then further used to generate a component
2490/// for this module.
2491pub fn validate_module(
2492    encoder: &ComponentEncoder,
2493    bytes: &[u8],
2494    import_map: Option<&ModuleImportMap>,
2495) -> Result<ValidatedModule> {
2496    ValidatedModule::new(
2497        encoder,
2498        bytes,
2499        &encoder.main_module_exports,
2500        import_map,
2501        None,
2502    )
2503}
2504
2505/// This function will validate the `bytes` provided as a wasm adapter module.
2506/// Notably this will validate the wasm module itself in addition to ensuring
2507/// that it has the "shape" of an adapter module. Current constraints are:
2508///
2509/// * The adapter module can import only one memory
2510/// * The adapter module can only import from the name of `interface` specified,
2511///   and all function imports must match the `required` types which correspond
2512///   to the lowered types of the functions in `interface`.
2513///
2514/// The wasm module passed into this function is the output of the GC pass of an
2515/// adapter module's original source. This means that the adapter module is
2516/// already minimized and this is a double-check that the minimization pass
2517/// didn't accidentally break the wasm module.
2518///
2519/// If `is_library` is true, we waive some of the constraints described above,
2520/// allowing the module to import tables and globals, as well as import
2521/// functions at the world level, not just at the interface level.
2522pub fn validate_adapter_module(
2523    encoder: &ComponentEncoder,
2524    bytes: &[u8],
2525    required_by_import: &IndexMap<String, FuncType>,
2526    exports: &IndexSet<WorldKey>,
2527    library_info: Option<&LibraryInfo>,
2528) -> Result<ValidatedModule> {
2529    let ret = ValidatedModule::new(encoder, bytes, exports, None, library_info)?;
2530
2531    for (name, required_ty) in required_by_import {
2532        let actual = match ret.exports.raw_exports.get(name) {
2533            Some(ty) => ty,
2534            None => return Err(AdapterModuleDidNotExport(name.clone()).into()),
2535        };
2536        validate_func_sig(name, required_ty, &actual)?;
2537    }
2538
2539    Ok(ret)
2540}
2541
2542/// An error that can be returned from adapting a core Wasm module into a
2543/// component using an adapter module.
2544///
2545/// If the core Wasm module contained an import that it requires to be
2546/// satisfied by the adapter, and the adapter does not contain an export
2547/// with the same name, an instance of this error is returned.
2548#[derive(Debug, Clone)]
2549pub struct AdapterModuleDidNotExport(String);
2550
2551impl fmt::Display for AdapterModuleDidNotExport {
2552    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2553        write!(f, "adapter module did not export `{}`", self.0)
2554    }
2555}
2556
2557impl std::error::Error for AdapterModuleDidNotExport {}
2558
2559fn resource_test_for_interface<'a>(
2560    resolve: &'a Resolve,
2561    id: InterfaceId,
2562) -> impl Fn(&str) -> Option<TypeId> + 'a {
2563    let interface = &resolve.interfaces[id];
2564    move |name: &str| {
2565        let ty = match interface.types.get(name) {
2566            Some(ty) => *ty,
2567            None => return None,
2568        };
2569        if matches!(resolve.types[ty].kind, TypeDefKind::Resource) {
2570            Some(ty)
2571        } else {
2572            None
2573        }
2574    }
2575}
2576
2577fn resource_test_for_world<'a>(
2578    resolve: &'a Resolve,
2579    id: WorldId,
2580) -> impl Fn(&str) -> Option<TypeId> + 'a {
2581    let world = &resolve.worlds[id];
2582    move |name: &str| match world.imports.get(&WorldKey::Name(name.to_string()))? {
2583        WorldItem::Type(r) => {
2584            if matches!(resolve.types[*r].kind, TypeDefKind::Resource) {
2585                Some(*r)
2586            } else {
2587                None
2588            }
2589        }
2590        _ => None,
2591    }
2592}
2593
2594fn validate_func(
2595    resolve: &Resolve,
2596    ty: &wasmparser::FuncType,
2597    func: &Function,
2598    abi: AbiVariant,
2599) -> Result<()> {
2600    validate_func_sig(
2601        &func.name,
2602        &wasm_sig_to_func_type(resolve.wasm_signature(abi, func)),
2603        ty,
2604    )
2605}
2606
2607fn validate_post_return(
2608    resolve: &Resolve,
2609    ty: &wasmparser::FuncType,
2610    func: &Function,
2611) -> Result<()> {
2612    // The expected signature of a post-return function is to take all the
2613    // parameters that are returned by the guest function and then return no
2614    // results. Model this by calculating the signature of `func` and then
2615    // moving its results into the parameters list while emptying out the
2616    // results.
2617    let mut sig = resolve.wasm_signature(AbiVariant::GuestExport, func);
2618    sig.params = mem::take(&mut sig.results);
2619    validate_func_sig(
2620        &format!("{} post-return", func.name),
2621        &wasm_sig_to_func_type(sig),
2622        ty,
2623    )
2624}
2625
2626fn validate_func_sig(name: &str, expected: &FuncType, ty: &wasmparser::FuncType) -> Result<()> {
2627    if ty != expected {
2628        bail!(
2629            "type mismatch for function `{}`: expected `{:?} -> {:?}` but found `{:?} -> {:?}`",
2630            name,
2631            expected.params(),
2632            expected.results(),
2633            ty.params(),
2634            ty.results()
2635        );
2636    }
2637
2638    Ok(())
2639}
2640
2641/// Matches `name` as `[${prefix}S]...`, and if found returns `("S", "...")`
2642fn prefixed_intrinsic<'a>(name: &'a str, prefix: &str) -> Option<(&'a str, &'a str)> {
2643    assert!(prefix.starts_with("["));
2644    assert!(prefix.ends_with("-"));
2645    let suffix = name.strip_prefix(prefix)?;
2646    let index = suffix.find(']')?;
2647    let rest = &suffix[index + 1..];
2648    Some((&suffix[..index], rest))
2649}
2650
2651/// Matches `name` as `[${prefix}N]...`, and if found returns `(N, "...")`
2652fn prefixed_integer<'a>(name: &'a str, prefix: &str) -> Option<(u32, &'a str)> {
2653    let (suffix, rest) = prefixed_intrinsic(name, prefix)?;
2654    let n = suffix.parse().ok()?;
2655    Some((n, rest))
2656}
2657
2658fn get_function<'a>(
2659    resolve: &'a Resolve,
2660    world: &'a World,
2661    name: &str,
2662    interface: Option<InterfaceId>,
2663    imported: bool,
2664) -> Result<&'a Function> {
2665    let function = if let Some(id) = interface {
2666        return resolve.interfaces[id]
2667            .functions
2668            .get(name)
2669            .ok_or_else(|| anyhow!("no export `{name}` found"));
2670    } else if imported {
2671        world.imports.get(&WorldKey::Name(name.to_string()))
2672    } else {
2673        world.exports.get(&WorldKey::Name(name.to_string()))
2674    };
2675    let Some(WorldItem::Function(function)) = function else {
2676        bail!("no export `{name}` found");
2677    };
2678    Ok(function)
2679}