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