Skip to main content

wit_component/
validation.rs

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