Skip to main content

wit_component/
validation.rs

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