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