Skip to main content

wit_component/
validation.rs

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