Skip to main content

wit_component/
validation.rs

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