Coverage Report

Created: 2026-08-28 08:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wasm-tools/crates/wasmparser/src/validator/component.rs
Line
Count
Source
1
//! State relating to validating a WebAssembly component.
2
3
use super::{
4
    check_max,
5
    component_types::{
6
        Abi, AbiInfo, AliasableResourceId, ComponentAnyTypeId, ComponentCoreInstanceTypeId,
7
        ComponentCoreModuleTypeId, ComponentCoreTypeId, ComponentDefinedType,
8
        ComponentDefinedTypeId, ComponentEntityType, ComponentFuncType, ComponentFuncTypeId,
9
        ComponentInstanceType, ComponentInstanceTypeId, ComponentItem, ComponentType,
10
        ComponentTypeId, ComponentValType, Context, CoreInstanceTypeKind, InstanceType, ModuleType,
11
        RecordType, Remap, Remapping, ResourceId, SubtypeCx, TupleType, VariantCase, VariantType,
12
    },
13
    core::{InternRecGroup, Module},
14
    types::{CoreTypeId, EntityType, TypeAlloc, TypeData, TypeInfo, TypeList},
15
};
16
use crate::collections::index_map::Entry;
17
use crate::limits::*;
18
use crate::prelude::*;
19
use crate::validator::names::{ComponentName, ComponentNameKind, KebabStr, KebabString};
20
use crate::{
21
    CanonicalFunction, CanonicalOption, ComponentExternName, ComponentExternalKind,
22
    ComponentOuterAliasKind, ComponentTypeRef, CompositeInnerType, Error, ExternalKind, FuncType,
23
    GlobalType, InstantiationArgKind, MemoryType, PackedIndex, RefType, Result, SubType, TableType,
24
    TypeBounds, ValType, WasmFeatures, require_feature,
25
};
26
use core::mem;
27
28
501k
fn to_kebab_string<'a>(s: &'a str, desc: &str, offset: u64) -> Result<KebabString> {
29
501k
    match KebabString::new(s) {
30
501k
        Some(s) => Ok(s),
31
        None => {
32
0
            if s.is_empty() {
33
0
                bail!(offset, "{desc} name cannot be empty");
34
0
            }
35
36
0
            bail!(offset, "{desc} name `{s}` is not in kebab case");
37
        }
38
    }
39
501k
}
40
41
pub(crate) struct ComponentState {
42
    /// Whether this state is a concrete component, an instance type, or a
43
    /// component type.
44
    kind: ComponentKind,
45
    features: WasmFeatures,
46
47
    // Core index spaces
48
    pub core_types: Vec<ComponentCoreTypeId>,
49
    pub core_funcs: Vec<CoreTypeId>,
50
    pub core_tags: Vec<CoreTypeId>,
51
    pub core_modules: Vec<ComponentCoreModuleTypeId>,
52
    pub core_instances: Vec<ComponentCoreInstanceTypeId>,
53
    pub core_memories: Vec<MemoryType>,
54
    pub core_tables: Vec<TableType>,
55
    pub core_globals: Vec<GlobalType>,
56
57
    // Component index spaces
58
    pub types: Vec<ComponentAnyTypeId>,
59
    pub funcs: Vec<ComponentFuncTypeId>,
60
    pub values: Vec<(ComponentValType, bool)>,
61
    pub instances: Vec<ComponentInstanceTypeId>,
62
    pub components: Vec<ComponentTypeId>,
63
64
    pub imports: IndexMap<String, ComponentItem>,
65
    pub import_names: IndexSet<ComponentName>,
66
    pub exports: IndexMap<String, ComponentItem>,
67
    pub export_names: IndexSet<ComponentName>,
68
69
    has_start: bool,
70
    type_info: TypeInfo,
71
72
    /// A mapping of imported resources in this component.
73
    ///
74
    /// This mapping represents all "type variables" imported into the
75
    /// component, or resources. This could be resources imported directly as
76
    /// a top-level type import or additionally transitively through other
77
    /// imported instances.
78
    ///
79
    /// The mapping element here is a "path" which is a list of indexes into
80
    /// the import map that will be generated for this component. Each index
81
    /// is an index into an `IndexMap`, and each list is guaranteed to have at
82
    /// least one element.
83
    ///
84
    /// An example of this map is:
85
    ///
86
    /// ```wasm
87
    /// (component
88
    ///     ;; [0] - the first import
89
    ///     (import "r" (type (sub resource)))
90
    ///
91
    ///     ;; [1] - the second import
92
    ///     (import "r2" (type (sub resource)))
93
    ///
94
    ///     (import "i" (instance
95
    ///         ;; [2, 0] - the third import, and the first export the instance
96
    ///         (export "r3" (type (sub resource)))
97
    ///         ;; [2, 1] - the third import, and the second export the instance
98
    ///         (export "r4" (type (sub resource)))
99
    ///     ))
100
    ///
101
    ///     ;; ...
102
    /// )
103
    /// ```
104
    ///
105
    /// The `Vec<usize>` here can be thought of as `Vec<String>` but a
106
    /// (hopefully) more efficient representation.
107
    ///
108
    /// Finally note that this map is listed as an "append only" map because all
109
    /// insertions into it should always succeed. Any insertion which overlaps
110
    /// with a previous entry indicates a bug in the validator which needs to be
111
    /// corrected via other means.
112
    //
113
    // TODO: make these `SkolemResourceId` and then go fix all the compile
114
    // errors, don't add skolem things into the type area
115
    imported_resources: IndexMapAppendOnly<ResourceId, Vec<usize>>,
116
117
    /// A mapping of "defined" resources in this component, or those which
118
    /// are defined within the instantiation of this component.
119
    ///
120
    /// Defined resources, as the name implies, can sort of be thought of as
121
    /// "these are defined within the component". Note though that the means by
122
    /// which a local definition can occur are not simply those defined in the
123
    /// component but also in its transitively instantiated components
124
    /// internally. This means that this set closes over many transitive
125
    /// internal items in addition to those defined immediately in the component
126
    /// itself.
127
    ///
128
    /// The `Option<ValType>` in this mapping is whether or not the underlying
129
    /// representation of the resource is known to this component. Immediately
130
    /// defined resources, for example, will have `Some(I32)` here. Resources
131
    /// that come from transitively defined components, for example, will have
132
    /// `None`. In the type context all entries here are `None`.
133
    ///
134
    /// Note that like `imported_resources` all insertions into this map are
135
    /// expected to succeed to it's declared as append-only.
136
    defined_resources: IndexMapAppendOnly<ResourceId, Option<ValType>>,
137
138
    /// A mapping of explicitly exported resources from this component in
139
    /// addition to the path that they're exported at.
140
    ///
141
    /// For more information on the path here see the documentation for
142
    /// `imported_resources`. Note that the indexes here index into the
143
    /// list of exports of this component.
144
    explicit_resources: IndexMap<ResourceId, Vec<usize>>,
145
146
    /// The set of types which are considered "exported" from this component.
147
    ///
148
    /// This is added to whenever a type export is found, or an instance export
149
    /// which itself contains a type export. This additionally includes all
150
    /// imported types since those are suitable for export as well.
151
    ///
152
    /// This set is consulted whenever an exported item is added since all
153
    /// referenced types must be members of this set.
154
    exported_types: Set<ComponentAnyTypeId>,
155
156
    /// Same as `exported_types`, but for imports.
157
    imported_types: Set<ComponentAnyTypeId>,
158
159
    /// The set of top-level resource exports and their names.
160
    ///
161
    /// This context is used to validate method names such as `[method]foo.bar`
162
    /// to ensure that `foo` is an exported resource and that the type mentioned
163
    /// in a function type is actually named `foo`.
164
    ///
165
    /// Note that imports/exports have disjoint contexts to ensure that they're
166
    /// validated correctly. Namely you can't retroactively attach methods to an
167
    /// import, for example.
168
    toplevel_exported_resources: ComponentNameContext,
169
170
    /// Same as `toplevel_exported_resources`, but for imports.
171
    toplevel_imported_resources: ComponentNameContext,
172
173
    /// The type that's been assigned to slots of `context.{get,set}` by this
174
    /// component. This is `None` until the first intrinsic is seen.
175
    context_type: Option<ValType>,
176
}
177
178
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
179
pub enum ComponentKind {
180
    Component,
181
    InstanceType,
182
    ComponentType,
183
}
184
185
/// Helper context used to track information about resource names for method
186
/// name validation.
187
#[derive(Default)]
188
struct ComponentNameContext {
189
    /// A map from a resource type id to an index in the `all_resource_names`
190
    /// set for the name of that resource.
191
    resource_name_map: Map<AliasableResourceId, usize>,
192
193
    /// All known resource names in this context, used to validate static method
194
    /// names to by ensuring that static methods' resource names are somewhere
195
    /// in this set.
196
    all_resource_names: IndexSet<String>,
197
}
198
199
#[derive(Debug, Copy, Clone)]
200
pub enum ExternKind {
201
    Import,
202
    Export,
203
}
204
205
impl ExternKind {
206
0
    pub fn desc(&self) -> &'static str {
207
0
        match self {
208
0
            ExternKind::Import => "import",
209
0
            ExternKind::Export => "export",
210
        }
211
0
    }
212
}
213
214
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
215
pub(crate) enum StringEncoding {
216
    #[default]
217
    Utf8,
218
    Utf16,
219
    CompactUtf16,
220
}
221
222
impl core::fmt::Display for StringEncoding {
223
0
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
224
0
        f.write_str(match self {
225
0
            Self::Utf8 => "utf8",
226
0
            Self::Utf16 => "utf16",
227
0
            Self::CompactUtf16 => "latin1-utf16",
228
        })
229
0
    }
230
}
231
232
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
233
pub(crate) enum Concurrency {
234
    /// Synchronous.
235
    #[default]
236
    Sync,
237
238
    /// Asynchronous.
239
    Async {
240
        /// When present, this is the function index of the async callback. When
241
        /// omitted, we are either using stack-switching based asynchrony or are
242
        /// in an operation that does not support the `callback` option (like
243
        /// lowering).
244
        callback: Option<u32>,
245
    },
246
}
247
248
impl Concurrency {
249
14.6k
    pub(crate) fn is_sync(&self) -> bool {
250
14.6k
        matches!(self, Self::Sync)
251
14.6k
    }
252
253
12.5k
    pub(crate) fn is_async(&self) -> bool {
254
12.5k
        !self.is_sync()
255
12.5k
    }
256
}
257
258
#[derive(Clone, Copy)]
259
pub(crate) enum PtrSize {
260
    Ptr32,
261
    Ptr64,
262
}
263
264
impl PtrSize {
265
3.45k
    pub(crate) fn core_type(&self) -> ValType {
266
3.45k
        match self {
267
3.45k
            PtrSize::Ptr32 => ValType::I32,
268
0
            PtrSize::Ptr64 => ValType::I64,
269
        }
270
3.45k
    }
271
}
272
273
#[derive(Clone, Copy)]
274
pub(crate) struct CanonicalOptions {
275
    pub(crate) string_encoding: StringEncoding,
276
    pub(crate) memory: Option<(u32, PtrSize)>,
277
    pub(crate) realloc: Option<u32>,
278
    pub(crate) post_return: Option<u32>,
279
    pub(crate) concurrency: Concurrency,
280
    pub(crate) core_type: Option<CoreTypeId>,
281
    pub(crate) gc: bool,
282
}
283
284
impl CanonicalOptions {
285
2.02k
    pub(crate) fn require_sync(&self, offset: u64, where_: &str) -> Result<&Self> {
286
2.02k
        if !self.concurrency.is_sync() {
287
0
            bail!(offset, "cannot specify `async` option on `{where_}`")
288
2.02k
        }
289
2.02k
        Ok(self)
290
2.02k
    }
291
292
1.21k
    pub(crate) fn require_memory(&self, offset: u64) -> Result<&Self> {
293
1.21k
        if self.memory.is_none() {
294
0
            bail!(offset, "canonical option `memory` is required");
295
1.21k
        }
296
1.21k
        Ok(self)
297
1.21k
    }
298
299
165
    pub(crate) fn require_realloc(&self, offset: u64) -> Result<&Self> {
300
        // Memory is always required when `realloc` is required.
301
165
        self.require_memory(offset)?;
302
303
165
        if self.realloc.is_none() {
304
0
            bail!(offset, "canonical option `realloc` is required")
305
165
        }
306
307
165
        Ok(self)
308
165
    }
309
310
8.31k
    pub(crate) fn require_memory_if(&self, offset: u64, when: impl Fn() -> bool) -> Result<&Self> {
311
8.31k
        if self.memory.is_none() && when() {
312
0
            self.require_memory(offset)?;
313
8.31k
        }
314
8.31k
        Ok(self)
315
8.31k
    }
<wasmparser::validator::component::CanonicalOptions>::require_memory_if::<<wasmparser::validator::component::ComponentState>::future_read::{closure#0}>
Line
Count
Source
310
21
    pub(crate) fn require_memory_if(&self, offset: u64, when: impl Fn() -> bool) -> Result<&Self> {
311
21
        if self.memory.is_none() && when() {
312
0
            self.require_memory(offset)?;
313
21
        }
314
21
        Ok(self)
315
21
    }
<wasmparser::validator::component::CanonicalOptions>::require_memory_if::<<wasmparser::validator::component::ComponentState>::stream_read::{closure#0}>
Line
Count
Source
310
15
    pub(crate) fn require_memory_if(&self, offset: u64, when: impl Fn() -> bool) -> Result<&Self> {
311
15
        if self.memory.is_none() && when() {
312
0
            self.require_memory(offset)?;
313
15
        }
314
15
        Ok(self)
315
15
    }
<wasmparser::validator::component::CanonicalOptions>::require_memory_if::<<wasmparser::validator::component::ComponentState>::future_write::{closure#0}>
Line
Count
Source
310
21
    pub(crate) fn require_memory_if(&self, offset: u64, when: impl Fn() -> bool) -> Result<&Self> {
311
21
        if self.memory.is_none() && when() {
312
0
            self.require_memory(offset)?;
313
21
        }
314
21
        Ok(self)
315
21
    }
<wasmparser::validator::component::CanonicalOptions>::require_memory_if::<<wasmparser::validator::component::ComponentState>::stream_write::{closure#0}>
Line
Count
Source
310
15
    pub(crate) fn require_memory_if(&self, offset: u64, when: impl Fn() -> bool) -> Result<&Self> {
311
15
        if self.memory.is_none() && when() {
312
0
            self.require_memory(offset)?;
313
15
        }
314
15
        Ok(self)
315
15
    }
<wasmparser::validator::component::CanonicalOptions>::require_memory_if::<<wasmparser::validator::component_types::ComponentFuncType>::lower::{closure#0}>
Line
Count
Source
310
6.26k
    pub(crate) fn require_memory_if(&self, offset: u64, when: impl Fn() -> bool) -> Result<&Self> {
311
6.26k
        if self.memory.is_none() && when() {
312
0
            self.require_memory(offset)?;
313
6.26k
        }
314
6.26k
        Ok(self)
315
6.26k
    }
<wasmparser::validator::component::CanonicalOptions>::require_memory_if::<<wasmparser::validator::component_types::ComponentFuncType>::lower::{closure#3}>
Line
Count
Source
310
1.97k
    pub(crate) fn require_memory_if(&self, offset: u64, when: impl Fn() -> bool) -> Result<&Self> {
311
1.97k
        if self.memory.is_none() && when() {
312
0
            self.require_memory(offset)?;
313
1.97k
        }
314
1.97k
        Ok(self)
315
1.97k
    }
316
317
17.0k
    pub(crate) fn require_realloc_if(&self, offset: u64, when: impl Fn() -> bool) -> Result<&Self> {
318
17.0k
        if self.realloc.is_none() && when() {
319
0
            self.require_realloc(offset)?;
320
17.0k
        }
321
17.0k
        Ok(self)
322
17.0k
    }
<wasmparser::validator::component::CanonicalOptions>::require_realloc_if::<<wasmparser::validator::component::ComponentState>::future_read::{closure#1}>
Line
Count
Source
317
21
    pub(crate) fn require_realloc_if(&self, offset: u64, when: impl Fn() -> bool) -> Result<&Self> {
318
21
        if self.realloc.is_none() && when() {
319
0
            self.require_realloc(offset)?;
320
21
        }
321
21
        Ok(self)
322
21
    }
<wasmparser::validator::component::CanonicalOptions>::require_realloc_if::<<wasmparser::validator::component::ComponentState>::stream_read::{closure#1}>
Line
Count
Source
317
15
    pub(crate) fn require_realloc_if(&self, offset: u64, when: impl Fn() -> bool) -> Result<&Self> {
318
15
        if self.realloc.is_none() && when() {
319
0
            self.require_realloc(offset)?;
320
15
        }
321
15
        Ok(self)
322
15
    }
<wasmparser::validator::component::CanonicalOptions>::require_realloc_if::<<wasmparser::validator::component_types::ComponentFuncType>::lower::{closure#2}>
Line
Count
Source
317
7.84k
    pub(crate) fn require_realloc_if(&self, offset: u64, when: impl Fn() -> bool) -> Result<&Self> {
318
7.84k
        if self.realloc.is_none() && when() {
319
0
            self.require_realloc(offset)?;
320
7.84k
        }
321
7.84k
        Ok(self)
322
7.84k
    }
<wasmparser::validator::component::CanonicalOptions>::require_realloc_if::<<wasmparser::validator::component_types::ComponentFuncType>::lower::{closure#1}>
Line
Count
Source
317
9.12k
    pub(crate) fn require_realloc_if(&self, offset: u64, when: impl Fn() -> bool) -> Result<&Self> {
318
9.12k
        if self.realloc.is_none() && when() {
319
0
            self.require_realloc(offset)?;
320
9.12k
        }
321
9.12k
        Ok(self)
322
9.12k
    }
323
324
4.17k
    pub(crate) fn check_lower(&self, offset: u64) -> Result<&Self> {
325
4.17k
        if self.post_return.is_some() {
326
0
            bail!(
327
0
                offset,
328
                "canonical option `post-return` cannot be specified for lowerings"
329
            );
330
4.17k
        }
331
332
222
        if let Concurrency::Async { callback: Some(_) } = self.concurrency {
333
0
            bail!(
334
0
                offset,
335
                "canonical option `callback` cannot be specified for lowerings"
336
            );
337
4.17k
        }
338
339
4.17k
        if self.gc && self.core_type.is_none() {
340
0
            bail!(
341
0
                offset,
342
                "cannot specify `gc` without also specifying a `core-type` for lowerings"
343
            )
344
4.17k
        }
345
346
4.17k
        Ok(self)
347
4.17k
    }
348
349
6.30k
    pub(crate) fn check_lift(
350
6.30k
        &mut self,
351
6.30k
        types: &TypeList,
352
6.30k
        state: &ComponentState,
353
6.30k
        core_ty_id: CoreTypeId,
354
6.30k
        offset: u64,
355
6.30k
    ) -> Result<&Self> {
356
6.30k
        debug_assert!(matches!(
357
0
            types[core_ty_id].composite_type.inner,
358
            CompositeInnerType::Func(_)
359
        ));
360
361
6.30k
        if let Some(idx) = self.post_return {
362
4.33k
            let post_return_func_ty = types[state.core_function_at(idx, offset)?].unwrap_func();
363
4.33k
            let core_ty = types[core_ty_id].unwrap_func();
364
4.33k
            if post_return_func_ty.params() != core_ty.results()
365
4.33k
                || !post_return_func_ty.results().is_empty()
366
            {
367
0
                bail!(
368
0
                    offset,
369
                    "canonical option `post-return` uses a core function with an incorrect signature"
370
                );
371
4.33k
            }
372
1.97k
        }
373
374
1.97k
        match self.concurrency {
375
4.33k
            Concurrency::Sync => {}
376
377
            Concurrency::Async { callback: None } => {
378
6
                require_feature::cm_async_stackful(
379
6
                    state.features,
380
                    "requires the component model async stackful feature",
381
6
                    offset,
382
0
                )?;
383
            }
384
385
            Concurrency::Async {
386
1.96k
                callback: Some(idx),
387
            } => {
388
1.96k
                let func_ty = types[state.core_function_at(idx, offset)?].unwrap_func();
389
1.96k
                if func_ty.params() != [ValType::I32; 3] && func_ty.params() != [ValType::I32] {
390
0
                    return Err(Error::new(
391
0
                        "canonical option `callback` uses a core function with an incorrect signature",
392
0
                        offset,
393
0
                    ));
394
1.96k
                }
395
            }
396
        }
397
398
6.30k
        if self.core_type.is_some() {
399
0
            bail!(
400
0
                offset,
401
                "canonical option `core-type` is not allowed in `canon lift`"
402
            )
403
6.30k
        }
404
6.30k
        self.core_type = Some(core_ty_id);
405
406
6.30k
        Ok(self)
407
6.30k
    }
408
409
8.40k
    fn check_asyncness(&self, ty: &ComponentFuncType, offset: u64) -> Result<()> {
410
        // The `async` canonical ABI option is only allowed with `async`-typed
411
        // functions.
412
8.40k
        if self.concurrency.is_async() && !ty.async_ {
413
0
            bail!(
414
0
                offset,
415
                "the `async` canonical option requires an async function type",
416
            );
417
8.40k
        }
418
8.40k
        Ok(())
419
8.40k
    }
420
421
72
    pub(crate) fn check_core_type(
422
72
        &self,
423
72
        types: &mut TypeAlloc,
424
72
        actual: FuncType,
425
72
        offset: u64,
426
72
    ) -> Result<CoreTypeId> {
427
72
        if let Some(declared_id) = self.core_type {
428
0
            let declared = types[declared_id].unwrap_func();
429
430
0
            if actual.params() != declared.params() {
431
0
                bail!(
432
0
                    offset,
433
                    "declared core type has `{:?}` parameter types, but actual lowering has \
434
                     `{:?}` parameter types",
435
0
                    declared.params(),
436
0
                    actual.params(),
437
                );
438
0
            }
439
440
0
            if actual.results() != declared.results() {
441
0
                bail!(
442
0
                    offset,
443
                    "declared core type has `{:?}` result types, but actual lowering has \
444
                     `{:?}` result types",
445
0
                    declared.results(),
446
0
                    actual.results(),
447
                );
448
0
            }
449
450
0
            Ok(declared_id)
451
        } else {
452
72
            Ok(types.intern_func_type(actual, offset))
453
        }
454
72
    }
455
}
456
457
impl ComponentState {
458
32.0k
    pub fn new(kind: ComponentKind, features: WasmFeatures) -> Self {
459
32.0k
        Self {
460
32.0k
            kind,
461
32.0k
            features,
462
32.0k
            core_types: Default::default(),
463
32.0k
            core_modules: Default::default(),
464
32.0k
            core_instances: Default::default(),
465
32.0k
            core_funcs: Default::default(),
466
32.0k
            core_memories: Default::default(),
467
32.0k
            core_tables: Default::default(),
468
32.0k
            core_globals: Default::default(),
469
32.0k
            core_tags: Default::default(),
470
32.0k
            types: Default::default(),
471
32.0k
            funcs: Default::default(),
472
32.0k
            values: Default::default(),
473
32.0k
            instances: Default::default(),
474
32.0k
            components: Default::default(),
475
32.0k
            imports: Default::default(),
476
32.0k
            exports: Default::default(),
477
32.0k
            import_names: Default::default(),
478
32.0k
            export_names: Default::default(),
479
32.0k
            has_start: Default::default(),
480
32.0k
            type_info: TypeInfo::new(),
481
32.0k
            imported_resources: Default::default(),
482
32.0k
            defined_resources: Default::default(),
483
32.0k
            explicit_resources: Default::default(),
484
32.0k
            exported_types: Default::default(),
485
32.0k
            imported_types: Default::default(),
486
32.0k
            toplevel_exported_resources: Default::default(),
487
32.0k
            toplevel_imported_resources: Default::default(),
488
32.0k
            context_type: None,
489
32.0k
        }
490
32.0k
    }
491
492
159k
    pub fn type_count(&self) -> usize {
493
159k
        self.core_types.len() + self.types.len()
494
159k
    }
495
496
27.0k
    pub fn instance_count(&self) -> usize {
497
27.0k
        self.core_instances.len() + self.instances.len()
498
27.0k
    }
499
500
57.0k
    pub fn function_count(&self) -> usize {
501
57.0k
        self.core_funcs.len() + self.funcs.len()
502
57.0k
    }
503
504
0
    pub fn add_core_type(
505
0
        components: &mut [Self],
506
0
        ty: crate::CoreType,
507
0
        types: &mut TypeAlloc,
508
0
        offset: u64,
509
0
        check_limit: bool,
510
0
    ) -> Result<()> {
511
0
        let current = components.last_mut().unwrap();
512
0
        if check_limit {
513
0
            check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
514
0
        }
515
0
        match ty {
516
0
            crate::CoreType::Rec(rec) => {
517
0
                current.canonicalize_and_intern_rec_group(types, rec, offset)?;
518
            }
519
0
            crate::CoreType::Module(decls) => {
520
0
                let mod_ty = Self::create_module_type(components, decls.into_vec(), types, offset)?;
521
0
                let id = ComponentCoreTypeId::Module(types.push_ty(mod_ty));
522
0
                components.last_mut().unwrap().core_types.push(id);
523
            }
524
        }
525
526
0
        Ok(())
527
0
    }
528
529
4.27k
    pub fn add_core_module(
530
4.27k
        &mut self,
531
4.27k
        module: &Module,
532
4.27k
        types: &mut TypeAlloc,
533
4.27k
        offset: u64,
534
4.27k
    ) -> Result<()> {
535
4.27k
        let imports = module.imports_for_module_type(offset)?;
536
537
        // We have to clone the module's imports and exports here
538
        // because we cannot take the data out of the `MaybeOwned`
539
        // as it might be shared with a function validator.
540
4.27k
        let mod_ty = ModuleType {
541
4.27k
            info: TypeInfo::core(module.type_size),
542
4.27k
            imports,
543
4.27k
            exports: module.exports.clone(),
544
4.27k
        };
545
546
4.27k
        let mod_id = types.push_ty(mod_ty);
547
4.27k
        self.core_modules.push(mod_id);
548
549
4.27k
        Ok(())
550
4.27k
    }
551
552
7.08k
    pub fn add_core_instance(
553
7.08k
        &mut self,
554
7.08k
        instance: crate::Instance,
555
7.08k
        types: &mut TypeAlloc,
556
7.08k
        offset: u64,
557
7.08k
    ) -> Result<()> {
558
7.08k
        let instance = match instance {
559
4.27k
            crate::Instance::Instantiate { module_index, args } => {
560
4.27k
                self.instantiate_core_module(module_index, args.into_vec(), types, offset)?
561
            }
562
2.80k
            crate::Instance::FromExports(exports) => {
563
2.80k
                self.instantiate_core_exports(exports.into_vec(), types, offset)?
564
            }
565
        };
566
567
7.08k
        self.core_instances.push(instance);
568
569
7.08k
        Ok(())
570
7.08k
    }
571
572
201k
    pub fn add_type(
573
201k
        components: &mut Vec<Self>,
574
201k
        ty: crate::ComponentType,
575
201k
        types: &mut TypeAlloc,
576
201k
        offset: u64,
577
201k
        check_limit: bool,
578
201k
    ) -> Result<()> {
579
201k
        assert!(!components.is_empty());
580
581
378k
        fn current(components: &mut Vec<ComponentState>) -> &mut ComponentState {
582
378k
            components.last_mut().unwrap()
583
378k
        }
584
585
201k
        let id = match ty {
586
155k
            crate::ComponentType::Defined(ty) => {
587
155k
                let ty = current(components).create_defined_type(ty, types, offset)?;
588
155k
                let depth = ty.type_info(types).depth();
589
155k
                if depth > MAX_WASM_COMPONENT_TYPE_DEPTH {
590
0
                    bail!(offset, "type nesting is too deep");
591
155k
                }
592
155k
                types.push(ty).into()
593
            }
594
20.2k
            crate::ComponentType::Func(ty) => {
595
20.2k
                let ty = current(components).create_function_type(ty, types, offset)?;
596
20.2k
                types.push(ty).into()
597
            }
598
10.4k
            crate::ComponentType::Component(decls) => {
599
10.4k
                let ty = Self::create_component_type(components, decls.into_vec(), types, offset)?;
600
10.3k
                types.push(ty).into()
601
            }
602
14.8k
            crate::ComponentType::Instance(decls) => {
603
14.8k
                let ty = Self::create_instance_type(components, decls.into_vec(), types, offset)?;
604
14.7k
                types.push(ty).into()
605
            }
606
315
            crate::ComponentType::Resource { rep, dtor } => {
607
315
                let component = current(components);
608
609
                // Resource types cannot be declared in a type context, only
610
                // within a component context.
611
315
                if component.kind != ComponentKind::Component {
612
0
                    bail!(
613
0
                        offset,
614
                        "resources can only be defined within a concrete component"
615
                    );
616
315
                }
617
618
                // Current MVP restriction of the component model.
619
315
                if rep == ValType::I64 {
620
0
                    require_feature::cm64(
621
0
                        component.features,
622
                        "resources with `i64` require the `cm64` feature to be enabled",
623
0
                        offset,
624
0
                    )?;
625
315
                }
626
315
                if rep != ValType::I32 && rep != ValType::I64 {
627
0
                    bail!(
628
0
                        offset,
629
                        "resources can only be represented by `i32` or `i64`"
630
                    );
631
315
                }
632
633
                // If specified validate that the destructor is both a valid
634
                // function and has the correct signature.
635
315
                if let Some(dtor) = dtor {
636
315
                    let ty = component.core_function_at(dtor, offset)?;
637
315
                    let ty = types[ty].composite_type.unwrap_func();
638
315
                    if ty.params() != [rep] || ty.results() != [] {
639
0
                        bail!(
640
0
                            offset,
641
                            "core function {dtor} has wrong signature for a destructor"
642
                        );
643
315
                    }
644
0
                }
645
646
                // As this is the introduction of a resource create a fresh new
647
                // identifier for the resource. This is then added into the
648
                // list of defined resources for this component, notably with a
649
                // rep listed to enable getting access to various intrinsics
650
                // such as `resource.rep`.
651
315
                let id = types.alloc_resource_id();
652
315
                component.defined_resources.insert(id.resource(), Some(rep));
653
315
                id.into()
654
            }
655
        };
656
657
201k
        let current = current(components);
658
201k
        if check_limit {
659
116k
            check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
660
85.2k
        }
661
201k
        current.types.push(id);
662
663
201k
        Ok(())
664
201k
    }
665
666
17.4k
    pub fn add_import(
667
17.4k
        &mut self,
668
17.4k
        import: crate::ComponentImport<'_>,
669
17.4k
        types: &mut TypeAlloc,
670
17.4k
        offset: u64,
671
17.4k
    ) -> Result<()> {
672
17.4k
        let mut entity = self.check_type_ref(&import.ty, types, offset)?;
673
17.4k
        self.add_entity(
674
17.4k
            &mut entity,
675
17.4k
            Some((import.name.name, ExternKind::Import)),
676
17.4k
            types,
677
17.4k
            offset,
678
0
        )?;
679
17.4k
        self.toplevel_imported_resources.validate_extern(
680
17.4k
            &import.name,
681
17.4k
            ExternKind::Import,
682
17.4k
            &entity,
683
17.4k
            types,
684
17.4k
            offset,
685
17.4k
            &mut self.import_names,
686
17.4k
            &mut self.imports,
687
17.4k
            &mut self.type_info,
688
17.4k
            &self.features,
689
0
        )?;
690
17.4k
        Ok(())
691
17.4k
    }
692
693
142k
    fn add_entity(
694
142k
        &mut self,
695
142k
        ty: &mut ComponentEntityType,
696
142k
        name_and_kind: Option<(&str, ExternKind)>,
697
142k
        types: &mut TypeAlloc,
698
142k
        offset: u64,
699
142k
    ) -> Result<()> {
700
142k
        let kind = name_and_kind.map(|(_, k)| k);
701
142k
        let (len, max, desc) = match ty {
702
0
            ComponentEntityType::Module(id) => {
703
0
                self.core_modules.push(*id);
704
0
                (self.core_modules.len(), MAX_WASM_MODULES, "modules")
705
            }
706
2.56k
            ComponentEntityType::Component(id) => {
707
2.56k
                self.components.push(*id);
708
2.56k
                (self.components.len(), MAX_WASM_COMPONENTS, "components")
709
            }
710
18.2k
            ComponentEntityType::Instance(id) => {
711
18.2k
                match kind {
712
4.89k
                    Some(ExternKind::Import) => self.prepare_instance_import(id, types),
713
13.3k
                    Some(ExternKind::Export) => self.prepare_instance_export(id, types),
714
0
                    None => {}
715
                }
716
18.2k
                self.instances.push(*id);
717
18.2k
                (self.instance_count(), MAX_WASM_INSTANCES, "instances")
718
            }
719
31.1k
            ComponentEntityType::Func(id) => {
720
31.1k
                self.funcs.push(*id);
721
31.1k
                (self.function_count(), MAX_WASM_FUNCTIONS, "functions")
722
            }
723
0
            ComponentEntityType::Value(ty) => {
724
0
                self.check_value_support(offset)?;
725
0
                let value_used = match kind {
726
0
                    Some(ExternKind::Import) | None => false,
727
0
                    Some(ExternKind::Export) => true,
728
                };
729
0
                self.values.push((*ty, value_used));
730
0
                (self.values.len(), MAX_WASM_VALUES, "values")
731
            }
732
            ComponentEntityType::Type {
733
90.9k
                created,
734
90.9k
                referenced,
735
            } => {
736
90.9k
                self.types.push(*created);
737
738
                // Extra logic here for resources being imported and exported.
739
                // Note that if `created` is the same as `referenced` then this
740
                // is the original introduction of the resource which is where
741
                // `self.{imported,defined}_resources` are updated.
742
90.9k
                if let ComponentAnyTypeId::Resource(id) = *created {
743
2.53k
                    match kind {
744
                        Some(ExternKind::Import) => {
745
                            // A fresh new resource is being imported into a
746
                            // component. This arises from the import section of
747
                            // a component or from the import declaration in a
748
                            // component type. In both cases a new imported
749
                            // resource is injected with a fresh new identifier
750
                            // into our state.
751
576
                            if created == referenced {
752
534
                                self.imported_resources
753
534
                                    .insert(id.resource(), vec![self.imports.len()]);
754
534
                            }
755
                        }
756
757
                        Some(ExternKind::Export) => {
758
                            // A fresh resource is being exported from this
759
                            // component. This arises as part of the
760
                            // declaration of a component type, for example. In
761
                            // this situation brand new resource identifier is
762
                            // allocated and a definition is added, unlike the
763
                            // import case where an imported resource is added.
764
                            // Notably the representation of this new resource
765
                            // is unknown so it's listed as `None`.
766
1.95k
                            if created == referenced {
767
1.20k
                                self.defined_resources.insert(id.resource(), None);
768
1.20k
                            }
769
770
                            // If this is a type export of a resource type then
771
                            // update the `explicit_resources` list. A new
772
                            // export path is about to be created for this
773
                            // resource and this keeps track of that.
774
1.95k
                            self.explicit_resources
775
1.95k
                                .insert(id.resource(), vec![self.exports.len()]);
776
                        }
777
778
397
                        None => {}
779
                    }
780
88.0k
                }
781
90.9k
                (self.types.len(), MAX_WASM_TYPES, "types")
782
            }
783
        };
784
785
142k
        check_max(len, 0, max, desc, offset)?;
786
787
        // Before returning perform the final validation of the type of the item
788
        // being imported/exported. This will ensure that everything is
789
        // appropriately named with respect to type definitions, resources, etc.
790
142k
        if let Some((name, kind)) = name_and_kind {
791
135k
            if !self.validate_and_register_named_types(Some(name), kind, ty, types) {
792
0
                bail!(
793
0
                    offset,
794
                    "{} not valid to be used as {}",
795
0
                    ty.desc(),
796
0
                    kind.desc()
797
                );
798
135k
            }
799
7.12k
        }
800
142k
        Ok(())
801
142k
    }
802
803
    /// Validates that the `ty` referenced only refers to named types internally
804
    /// and then inserts anything necessary, if applicable, to the defined sets
805
    /// within this component.
806
    ///
807
    /// This function will validate that `ty` only refers to named types. For
808
    /// example if it's a record then all of its fields must refer to named
809
    /// types. This consults either `self.imported_types` or
810
    /// `self.exported_types` as specified by `kind`. Note that this is not
811
    /// inherently recursive itself but it ends up being recursive since if
812
    /// recursive members were named then all their components must also be
813
    /// named. Consequently this check stops at the "one layer deep" position,
814
    /// or more accurately the position where types must be named (e.g. tuples
815
    /// aren't required to be named).
816
229k
    fn validate_and_register_named_types(
817
229k
        &mut self,
818
229k
        toplevel_name: Option<&str>,
819
229k
        kind: ExternKind,
820
229k
        ty: &ComponentEntityType,
821
229k
        types: &TypeAlloc,
822
229k
    ) -> bool {
823
229k
        if let ComponentEntityType::Type { created, .. } = ty {
824
            // If this is a top-level resource then register it in the
825
            // appropriate context so later validation of method-like-names
826
            // works out.
827
157k
            if let Some(name) = toplevel_name {
828
85.4k
                if let ComponentAnyTypeId::Resource(id) = *created {
829
2.53k
                    let cx = match kind {
830
576
                        ExternKind::Import => &mut self.toplevel_imported_resources,
831
1.95k
                        ExternKind::Export => &mut self.toplevel_exported_resources,
832
                    };
833
2.53k
                    cx.register(name, id);
834
82.8k
                }
835
72.3k
            }
836
72.0k
        }
837
838
229k
        match self.kind {
839
157k
            ComponentKind::Component | ComponentKind::ComponentType => {}
840
71.8k
            ComponentKind::InstanceType => return true,
841
        }
842
157k
        let set = match kind {
843
47.2k
            ExternKind::Import => &self.imported_types,
844
110k
            ExternKind::Export => &self.exported_types,
845
        };
846
157k
        match ty {
847
            // When a type is imported or exported than any recursive type
848
            // referred to by that import/export must additionally be exported
849
            // or imported. Here this walks the "first layer" of the type which
850
            // delegates to `TypeAlloc::type_named_type_id` to determine whether
851
            // the components of the type being named here are indeed all they
852
            // themselves named.
853
            ComponentEntityType::Type {
854
101k
                created,
855
101k
                referenced,
856
            } => {
857
101k
                if !self.all_valtypes_named(types, *referenced, set) {
858
0
                    return false;
859
101k
                }
860
101k
                match kind {
861
                    // Imported types are both valid for import and valid for
862
                    // export.
863
31.3k
                    ExternKind::Import => {
864
31.3k
                        self.imported_types.insert(*created);
865
31.3k
                        self.exported_types.insert(*created);
866
31.3k
                    }
867
70.1k
                    ExternKind::Export => {
868
70.1k
                        self.exported_types.insert(*created);
869
70.1k
                    }
870
                }
871
872
101k
                true
873
            }
874
875
            // Instances are slightly nuanced here. The general idea is that if
876
            // an instance is imported, then any type exported by the instance
877
            // is then also exported. Additionally for exports. To get this to
878
            // work out this arm will recursively call
879
            // `validate_and_register_named_types` which means that types are
880
            // inserted into `self.{imported,exported}_types` as-we-go rather
881
            // than all at once.
882
            //
883
            // This then recursively validates that all items in the instance
884
            // itself are valid to import/export, recursive instances are
885
            // captured, and everything is appropriately added to the right
886
            // imported/exported set.
887
94.0k
            ComponentEntityType::Instance(i) => types[*i].exports.iter().all(|(_name, ty)| {
888
94.0k
                self.validate_and_register_named_types(None, kind, &ty.ty, types)
889
94.0k
            }),
890
891
            // All types referred to by a function must be named.
892
35.6k
            ComponentEntityType::Func(id) => self.all_valtypes_named_in_func(types, *id, set),
893
894
0
            ComponentEntityType::Value(ty) => types.type_named_valtype(ty, set),
895
896
            // Components/modules are always "closed" or "standalone" and don't
897
            // need validation with respect to their named types.
898
2.56k
            ComponentEntityType::Component(_) | ComponentEntityType::Module(_) => true,
899
        }
900
229k
    }
901
902
101k
    fn all_valtypes_named(
903
101k
        &self,
904
101k
        types: &TypeAlloc,
905
101k
        id: ComponentAnyTypeId,
906
101k
        set: &Set<ComponentAnyTypeId>,
907
101k
    ) -> bool {
908
101k
        match id {
909
            // Resource types, in isolation, are always valid to import or
910
            // export since they're either attached to an import or being
911
            // exported.
912
            //
913
            // Note that further validation of this happens in `finish`, too.
914
2.84k
            ComponentAnyTypeId::Resource(_) => true,
915
916
            // Component types are validated as they are constructed,
917
            // so all component types are valid to export if they've
918
            // already been constructed.
919
7.82k
            ComponentAnyTypeId::Component(_) => true,
920
921
90.8k
            ComponentAnyTypeId::Defined(id) => self.all_valtypes_named_in_defined(types, id, set),
922
0
            ComponentAnyTypeId::Func(id) => self.all_valtypes_named_in_func(types, id, set),
923
0
            ComponentAnyTypeId::Instance(id) => self.all_valtypes_named_in_instance(types, id, set),
924
        }
925
101k
    }
926
927
0
    fn all_valtypes_named_in_instance(
928
0
        &self,
929
0
        types: &TypeAlloc,
930
0
        id: ComponentInstanceTypeId,
931
0
        set: &Set<ComponentAnyTypeId>,
932
0
    ) -> bool {
933
        // Instances must recursively have all referenced types named.
934
0
        let ty = &types[id];
935
0
        ty.exports.values().all(|ty| match ty.ty {
936
0
            ComponentEntityType::Module(_) => true,
937
0
            ComponentEntityType::Func(id) => self.all_valtypes_named_in_func(types, id, set),
938
0
            ComponentEntityType::Type { created: id, .. } => {
939
0
                self.all_valtypes_named(types, id, set)
940
            }
941
0
            ComponentEntityType::Value(ComponentValType::Type(id)) => {
942
0
                self.all_valtypes_named_in_defined(types, id, set)
943
            }
944
0
            ComponentEntityType::Instance(id) => {
945
0
                self.all_valtypes_named_in_instance(types, id, set)
946
            }
947
            ComponentEntityType::Component(_)
948
0
            | ComponentEntityType::Value(ComponentValType::Primitive(_)) => return true,
949
0
        })
950
0
    }
951
952
90.8k
    fn all_valtypes_named_in_defined(
953
90.8k
        &self,
954
90.8k
        types: &TypeAlloc,
955
90.8k
        id: ComponentDefinedTypeId,
956
90.8k
        set: &Set<ComponentAnyTypeId>,
957
90.8k
    ) -> bool {
958
90.8k
        let ty = &types[id];
959
90.8k
        match ty {
960
            // These types do not contain anything which must be
961
            // named.
962
            ComponentDefinedType::Primitive(_)
963
            | ComponentDefinedType::Flags(_)
964
64.7k
            | ComponentDefinedType::Enum(_) => true,
965
966
            // Referenced types of all these aggregates must all be
967
            // named.
968
9.25k
            ComponentDefinedType::Record(r) => {
969
39.3k
                r.fields.values().all(|t| types.type_named_valtype(t, set))
970
            }
971
252
            ComponentDefinedType::Tuple(r) => {
972
448
                r.types.iter().all(|t| types.type_named_valtype(t, set))
973
            }
974
16.2k
            ComponentDefinedType::Variant(r) => r
975
16.2k
                .cases
976
16.2k
                .values()
977
62.0k
                .filter_map(|t| t.ty.as_ref())
978
52.8k
                .all(|t| types.type_named_valtype(t, set)),
979
93
            ComponentDefinedType::Result { ok, err, .. } => {
980
93
                ok.as_ref()
981
93
                    .map(|t| types.type_named_valtype(t, set))
982
93
                    .unwrap_or(true)
983
93
                    && err
984
93
                        .as_ref()
985
93
                        .map(|t| types.type_named_valtype(t, set))
986
93
                        .unwrap_or(true)
987
            }
988
27
            ComponentDefinedType::List { element: ty, .. }
989
0
            | ComponentDefinedType::FixedLengthList { element: ty, .. }
990
261
            | ComponentDefinedType::Option { ty, .. } => types.type_named_valtype(ty, set),
991
0
            ComponentDefinedType::Map { key, value, .. } => {
992
0
                types.type_named_valtype(key, set) && types.type_named_valtype(value, set)
993
            }
994
995
            // The resource referred to by own/borrow must be named.
996
0
            ComponentDefinedType::Own(id) | ComponentDefinedType::Borrow(id) => {
997
0
                set.contains(&ComponentAnyTypeId::from(*id))
998
            }
999
1000
18
            ComponentDefinedType::Future { ty, .. } | ComponentDefinedType::Stream { ty, .. } => ty
1001
18
                .as_ref()
1002
18
                .map(|ty| types.type_named_valtype(ty, set))
1003
18
                .unwrap_or(true),
1004
        }
1005
90.8k
    }
1006
1007
35.6k
    fn all_valtypes_named_in_func(
1008
35.6k
        &self,
1009
35.6k
        types: &TypeAlloc,
1010
35.6k
        id: ComponentFuncTypeId,
1011
35.6k
        set: &Set<ComponentAnyTypeId>,
1012
35.6k
    ) -> bool {
1013
35.6k
        let ty = &types[id];
1014
        // Function types must have all their parameters/results named.
1015
35.6k
        ty.params
1016
35.6k
            .iter()
1017
35.6k
            .map(|(_, ty)| ty)
1018
35.6k
            .chain(&ty.result)
1019
93.4k
            .all(|ty| types.type_named_valtype(ty, set))
1020
35.6k
    }
1021
1022
    /// Updates the type `id` specified, an identifier for a component instance
1023
    /// type, to be imported into this component.
1024
    ///
1025
    /// Importing an instance type into a component specially handles the
1026
    /// defined resources registered in the instance type. Notably all
1027
    /// defined resources are "freshened" into brand new type variables and
1028
    /// these new variables are substituted within the type. This is what
1029
    /// creates a new `TypeId` and may update the `id` specified.
1030
    ///
1031
    /// One side effect of this operation, for example, is that if an instance
1032
    /// type is used twice to import two different instances then the instances
1033
    /// do not share resource types despite sharing the same original instance
1034
    /// type.
1035
4.89k
    fn prepare_instance_import(&mut self, id: &mut ComponentInstanceTypeId, types: &mut TypeAlloc) {
1036
4.89k
        let ty = &types[*id];
1037
1038
        // No special treatment for imports of instances which themselves have
1039
        // no defined resources
1040
4.89k
        if ty.defined_resources.is_empty() {
1041
4.47k
            return;
1042
418
        }
1043
1044
418
        let mut new_ty = ComponentInstanceType {
1045
418
            // Copied from the input verbatim
1046
418
            info: ty.info,
1047
418
1048
418
            // Copied over as temporary storage for now, and both of these are
1049
418
            // filled out and expanded below.
1050
418
            exports: ty.exports.clone(),
1051
418
            explicit_resources: ty.explicit_resources.clone(),
1052
418
1053
418
            // Explicitly discard this field since the
1054
418
            // defined resources are lifted into `self`
1055
418
            defined_resources: Default::default(),
1056
418
        };
1057
1058
        // Create brand new resources for all defined ones in the instance.
1059
418
        let resources = (0..ty.defined_resources.len())
1060
577
            .map(|_| types.alloc_resource_id())
1061
418
            .collect::<IndexSet<_>>();
1062
1063
        // Build a map from the defined resources in `ty` to those in `new_ty`.
1064
        //
1065
        // As part of this same loop the new resources, which were previously
1066
        // defined in `ty`, now become imported variables in `self`. Their
1067
        // path for where they're imported is updated as well with
1068
        // `self.next_import_index` as the import-to-be soon.
1069
418
        let mut mapping = Remapping::default();
1070
418
        let ty = &types[*id];
1071
577
        for (old, new) in ty.defined_resources.iter().zip(&resources) {
1072
577
            let prev = mapping.resources.insert(*old, new.resource());
1073
577
            assert!(prev.is_none());
1074
1075
577
            let mut base = vec![self.imports.len()];
1076
577
            base.extend(ty.explicit_resources[old].iter().copied());
1077
577
            self.imported_resources.insert(new.resource(), base);
1078
        }
1079
1080
        // Using the old-to-new resource mapping perform a substitution on
1081
        // the `exports` and `explicit_resources` fields of `new_ty`
1082
3.62k
        for ty in new_ty.exports.values_mut() {
1083
3.62k
            types.remap_component_entity(&mut ty.ty, &mut mapping);
1084
3.62k
        }
1085
603
        for (id, path) in mem::take(&mut new_ty.explicit_resources) {
1086
603
            let id = *mapping.resources.get(&id).unwrap_or(&id);
1087
603
            new_ty.explicit_resources.insert(id, path);
1088
603
        }
1089
1090
        // Now that `new_ty` is complete finish its registration and then
1091
        // update `id` on the way out.
1092
418
        *id = types.push_ty(new_ty);
1093
4.89k
    }
1094
1095
    /// Prepares an instance type, pointed to `id`, for being exported as a
1096
    /// concrete instance from `self`.
1097
    ///
1098
    /// This will internally perform any resource "freshening" as required and
1099
    /// then additionally update metadata within `self` about resources being
1100
    /// exported or defined.
1101
13.3k
    fn prepare_instance_export(&mut self, id: &mut ComponentInstanceTypeId, types: &mut TypeAlloc) {
1102
        // Exports of an instance mean that the enclosing context
1103
        // is inheriting the resources that the instance
1104
        // encapsulates. This means that the instance type
1105
        // recorded for this export will itself have no
1106
        // defined resources.
1107
13.3k
        let ty = &types[*id];
1108
1109
        // Check to see if `defined_resources` is non-empty, and if so then
1110
        // "freshen" all the resources and inherit them to our own defined
1111
        // resources, updating `id` in the process.
1112
        //
1113
        // Note though that this specifically is not rewriting the resources of
1114
        // exported instances. The `defined_resources` set on instance types is
1115
        // a little subtle (see its documentation for more info), but the
1116
        // general idea is that for a concrete instance it's always empty. Only
1117
        // for instance type definitions does it ever have elements in it.
1118
        //
1119
        // That means that if this set is non-empty then what's happening is
1120
        // that we're in a type context an exporting an instance of a previously
1121
        // specified type. In this case all resources are required to be
1122
        // "freshened" to ensure that multiple exports of the same type all
1123
        // export different types of resources.
1124
        //
1125
        // And finally note that this operation empties out the
1126
        // `defined_resources` set of the type that is registered for the
1127
        // instance, as this export is modeled as producing a concrete instance.
1128
13.3k
        if !ty.defined_resources.is_empty() {
1129
564
            let mut new_ty = ty.clone();
1130
564
            let mut mapping = Remapping::default();
1131
628
            for old in mem::take(&mut new_ty.defined_resources) {
1132
628
                let new = types.alloc_resource_id();
1133
628
                mapping.resources.insert(old, new.resource());
1134
628
                self.defined_resources.insert(new.resource(), None);
1135
628
            }
1136
6.46k
            for ty in new_ty.exports.values_mut() {
1137
6.46k
                types.remap_component_entity(&mut ty.ty, &mut mapping);
1138
6.46k
            }
1139
646
            for (id, path) in mem::take(&mut new_ty.explicit_resources) {
1140
646
                let id = mapping.resources.get(&id).copied().unwrap_or(id);
1141
646
                new_ty.explicit_resources.insert(id, path);
1142
646
            }
1143
564
            *id = types.push_ty(new_ty);
1144
12.7k
        }
1145
1146
        // Any explicit resources in the instance are now additionally explicit
1147
        // in this component since it's exported.
1148
        //
1149
        // The path to each explicit resources gets one element prepended which
1150
        // is `self.next_export_index`, the index of the export about to be
1151
        // generated.
1152
13.3k
        let ty = &types[*id];
1153
13.3k
        for (id, path) in ty.explicit_resources.iter() {
1154
1.07k
            let mut new_path = vec![self.exports.len()];
1155
1.07k
            new_path.extend(path);
1156
1.07k
            self.explicit_resources.insert(*id, new_path);
1157
1.07k
        }
1158
13.3k
    }
1159
1160
118k
    pub fn add_export(
1161
118k
        &mut self,
1162
118k
        name: ComponentExternName<'_>,
1163
118k
        mut ty: ComponentEntityType,
1164
118k
        types: &mut TypeAlloc,
1165
118k
        offset: u64,
1166
118k
        check_limit: bool,
1167
118k
    ) -> Result<()> {
1168
118k
        if check_limit {
1169
84.6k
            check_max(self.exports.len(), 1, MAX_WASM_EXPORTS, "exports", offset)?;
1170
33.6k
        }
1171
118k
        self.add_entity(
1172
118k
            &mut ty,
1173
118k
            Some((name.name, ExternKind::Export)),
1174
118k
            types,
1175
118k
            offset,
1176
0
        )?;
1177
118k
        self.toplevel_exported_resources.validate_extern(
1178
118k
            &name,
1179
118k
            ExternKind::Export,
1180
118k
            &ty,
1181
118k
            types,
1182
118k
            offset,
1183
118k
            &mut self.export_names,
1184
118k
            &mut self.exports,
1185
118k
            &mut self.type_info,
1186
118k
            &self.features,
1187
0
        )?;
1188
118k
        Ok(())
1189
118k
    }
1190
1191
20.0k
    pub fn canonical_function(
1192
20.0k
        &mut self,
1193
20.0k
        func: CanonicalFunction,
1194
20.0k
        types: &mut TypeAlloc,
1195
20.0k
        offset: u64,
1196
20.0k
    ) -> Result<()> {
1197
20.0k
        match func {
1198
            CanonicalFunction::Lift {
1199
6.30k
                core_func_index,
1200
6.30k
                type_index,
1201
6.30k
                options,
1202
6.30k
            } => self.lift_function(core_func_index, type_index, &options, types, offset),
1203
            CanonicalFunction::Lower {
1204
2.09k
                func_index,
1205
2.09k
                options,
1206
2.09k
            } => self.lower_function(func_index, &options, types, offset),
1207
315
            CanonicalFunction::ResourceNew { resource } => {
1208
315
                self.resource_new(resource, types, offset)
1209
            }
1210
537
            CanonicalFunction::ResourceDrop { resource } => {
1211
537
                self.resource_drop(resource, types, offset)
1212
            }
1213
315
            CanonicalFunction::ResourceRep { resource } => {
1214
315
                self.resource_rep(resource, types, offset)
1215
            }
1216
0
            CanonicalFunction::ThreadSpawnRef { func_ty_index } => {
1217
0
                self.thread_spawn_ref(func_ty_index, types, offset)
1218
            }
1219
            CanonicalFunction::ThreadSpawnIndirect {
1220
0
                func_ty_index,
1221
0
                table_index,
1222
0
            } => self.thread_spawn_indirect(func_ty_index, table_index, types, offset),
1223
            CanonicalFunction::ThreadAvailableParallelism => {
1224
0
                self.thread_available_parallelism(types, offset)
1225
            }
1226
498
            CanonicalFunction::BackpressureInc => self.backpressure_inc(types, offset),
1227
498
            CanonicalFunction::BackpressureDec => self.backpressure_dec(types, offset),
1228
2.02k
            CanonicalFunction::TaskReturn { result, options } => {
1229
2.02k
                self.task_return(&result, &options, types, offset)
1230
            }
1231
498
            CanonicalFunction::TaskCancel => self.task_cancel(types, offset),
1232
498
            CanonicalFunction::ContextGet { ty, slot } => self.context_get(ty, slot, types, offset),
1233
498
            CanonicalFunction::ContextSet { ty, slot } => self.context_set(ty, slot, types, offset),
1234
498
            CanonicalFunction::SubtaskDrop => self.subtask_drop(types, offset),
1235
498
            CanonicalFunction::SubtaskCancel { async_ } => {
1236
498
                self.subtask_cancel(async_, types, offset)
1237
            }
1238
15
            CanonicalFunction::StreamNew { ty } => self.stream_new(ty, types, offset),
1239
15
            CanonicalFunction::StreamRead { ty, options } => {
1240
15
                self.stream_read(ty, &options, types, offset)
1241
            }
1242
15
            CanonicalFunction::StreamWrite { ty, options } => {
1243
15
                self.stream_write(ty, &options, types, offset)
1244
            }
1245
15
            CanonicalFunction::StreamCancelRead { ty, async_ } => {
1246
15
                self.stream_cancel_read(ty, async_, types, offset)
1247
            }
1248
15
            CanonicalFunction::StreamCancelWrite { ty, async_ } => {
1249
15
                self.stream_cancel_write(ty, async_, types, offset)
1250
            }
1251
15
            CanonicalFunction::StreamDropReadable { ty } => {
1252
15
                self.stream_drop_readable(ty, types, offset)
1253
            }
1254
15
            CanonicalFunction::StreamDropWritable { ty } => {
1255
15
                self.stream_drop_writable(ty, types, offset)
1256
            }
1257
363
            CanonicalFunction::FutureNew { ty } => self.future_new(ty, types, offset),
1258
21
            CanonicalFunction::FutureRead { ty, options } => {
1259
21
                self.future_read(ty, &options, types, offset)
1260
            }
1261
21
            CanonicalFunction::FutureWrite { ty, options } => {
1262
21
                self.future_write(ty, &options, types, offset)
1263
            }
1264
363
            CanonicalFunction::FutureCancelRead { ty, async_ } => {
1265
363
                self.future_cancel_read(ty, async_, types, offset)
1266
            }
1267
363
            CanonicalFunction::FutureCancelWrite { ty, async_ } => {
1268
363
                self.future_cancel_write(ty, async_, types, offset)
1269
            }
1270
363
            CanonicalFunction::FutureDropReadable { ty } => {
1271
363
                self.future_drop_readable(ty, types, offset)
1272
            }
1273
363
            CanonicalFunction::FutureDropWritable { ty } => {
1274
363
                self.future_drop_writable(ty, types, offset)
1275
            }
1276
0
            CanonicalFunction::ErrorContextNew { options } => {
1277
0
                self.error_context_new(options.into_vec(), types, offset)
1278
            }
1279
0
            CanonicalFunction::ErrorContextDebugMessage { options } => {
1280
0
                self.error_context_debug_message(options.into_vec(), types, offset)
1281
            }
1282
0
            CanonicalFunction::ErrorContextDrop => self.error_context_drop(types, offset),
1283
498
            CanonicalFunction::WaitableSetNew => self.waitable_set_new(types, offset),
1284
            CanonicalFunction::WaitableSetWait {
1285
                cancellable: _,
1286
498
                memory,
1287
498
            } => self.waitable_set_wait(memory, types, offset),
1288
            CanonicalFunction::WaitableSetPoll {
1289
                cancellable: _,
1290
498
                memory,
1291
498
            } => self.waitable_set_poll(memory, types, offset),
1292
498
            CanonicalFunction::WaitableSetDrop => self.waitable_set_drop(types, offset),
1293
498
            CanonicalFunction::WaitableJoin => self.waitable_join(types, offset),
1294
0
            CanonicalFunction::ThreadIndex => self.thread_index(types, offset),
1295
            CanonicalFunction::ThreadNewIndirect {
1296
0
                func_ty_index,
1297
0
                table_index,
1298
0
            } => self.thread_new_indirect(func_ty_index, table_index, types, offset),
1299
0
            CanonicalFunction::ThreadResumeLater => self.thread_resume_later(types, offset),
1300
0
            CanonicalFunction::ThreadSuspend { cancellable } => {
1301
0
                self.thread_suspend(cancellable, types, offset)
1302
            }
1303
498
            CanonicalFunction::ThreadYield { cancellable: _ } => self.thread_yield(types, offset),
1304
0
            CanonicalFunction::ThreadSuspendThenResume { cancellable } => {
1305
0
                self.thread_suspend_then_resume(cancellable, types, offset)
1306
            }
1307
0
            CanonicalFunction::ThreadYieldThenResume { cancellable } => {
1308
0
                self.thread_yield_then_resume(cancellable, types, offset)
1309
            }
1310
0
            CanonicalFunction::ThreadSuspendThenPromote { cancellable } => {
1311
0
                self.thread_suspend_then_promote(cancellable, types, offset)
1312
            }
1313
0
            CanonicalFunction::ThreadYieldThenPromote { cancellable } => {
1314
0
                self.thread_yield_then_promote(cancellable, types, offset)
1315
            }
1316
        }
1317
20.0k
    }
1318
1319
6.30k
    fn lift_function(
1320
6.30k
        &mut self,
1321
6.30k
        core_func_index: u32,
1322
6.30k
        type_index: u32,
1323
6.30k
        options: &[CanonicalOption],
1324
6.30k
        types: &mut TypeAlloc,
1325
6.30k
        offset: u64,
1326
6.30k
    ) -> Result<()> {
1327
6.30k
        let ty = self.function_type_at(type_index, types, offset)?;
1328
6.30k
        let core_ty_id = self.core_function_at(core_func_index, offset)?;
1329
1330
        // Lifting a function is for an export, so match the expected canonical ABI
1331
        // export signature
1332
6.30k
        let mut options = self.check_options(types, options, offset)?;
1333
6.30k
        options.check_lift(types, self, core_ty_id, offset)?;
1334
6.30k
        options.check_asyncness(ty, offset)?;
1335
6.30k
        let func_ty = ty.lower(types, &options, Abi::Lift, offset)?;
1336
6.30k
        let lowered_core_ty_id = func_ty.intern(types, offset);
1337
1338
6.30k
        if core_ty_id == lowered_core_ty_id {
1339
6.30k
            self.funcs
1340
6.30k
                .push(self.types[type_index as usize].unwrap_func());
1341
6.30k
            return Ok(());
1342
0
        }
1343
1344
0
        let ty = types[core_ty_id].unwrap_func();
1345
0
        let lowered_ty = types[lowered_core_ty_id].unwrap_func();
1346
1347
0
        if lowered_ty.params() != ty.params() {
1348
0
            bail!(
1349
0
                offset,
1350
                "lowered parameter types `{:?}` do not match parameter types `{:?}` of \
1351
                     core function {core_func_index}",
1352
0
                lowered_ty.params(),
1353
0
                ty.params()
1354
            );
1355
0
        }
1356
1357
0
        if lowered_ty.results() != ty.results() {
1358
0
            bail!(
1359
0
                offset,
1360
                "lowered result types `{:?}` do not match result types `{:?}` of \
1361
                     core function {core_func_index}",
1362
0
                lowered_ty.results(),
1363
0
                ty.results()
1364
            );
1365
0
        }
1366
1367
        // Otherwise, must be different rec groups or subtyping (which isn't
1368
        // supported yet) or something.
1369
0
        bail!(
1370
0
            offset,
1371
            "lowered function type `{:?}` does not match type `{:?}` of \
1372
                 core function {core_func_index}",
1373
0
            types[lowered_core_ty_id],
1374
0
            types[core_ty_id],
1375
        );
1376
6.30k
    }
1377
1378
2.09k
    fn lower_function(
1379
2.09k
        &mut self,
1380
2.09k
        func_index: u32,
1381
2.09k
        options: &[CanonicalOption],
1382
2.09k
        types: &mut TypeAlloc,
1383
2.09k
        offset: u64,
1384
2.09k
    ) -> Result<()> {
1385
2.09k
        let ty = &types[self.function_at(func_index, offset)?];
1386
1387
        // Lowering a function is for an import, so use a function type that matches
1388
        // the expected canonical ABI import signature.
1389
2.09k
        let options = self.check_options(types, options, offset)?;
1390
2.09k
        options.check_lower(offset)?;
1391
2.09k
        options.check_asyncness(ty, offset)?;
1392
1393
2.09k
        let func_ty = ty.lower(types, &options, Abi::Lower, offset)?;
1394
2.09k
        let ty_id = func_ty.intern(types, offset);
1395
1396
2.09k
        self.core_funcs.push(ty_id);
1397
2.09k
        Ok(())
1398
2.09k
    }
1399
1400
315
    fn resource_new(&mut self, resource: u32, types: &mut TypeAlloc, offset: u64) -> Result<()> {
1401
315
        let rep = self.check_local_resource(resource, types, offset)?;
1402
315
        let id = types.intern_func_type(FuncType::new([rep], [ValType::I32]), offset);
1403
315
        self.core_funcs.push(id);
1404
315
        Ok(())
1405
315
    }
1406
1407
537
    fn resource_drop(&mut self, resource: u32, types: &mut TypeAlloc, offset: u64) -> Result<()> {
1408
537
        self.resource_at(resource, types, offset)?;
1409
537
        let id = types.intern_func_type(FuncType::new([ValType::I32], []), offset);
1410
537
        self.core_funcs.push(id);
1411
537
        Ok(())
1412
537
    }
1413
1414
315
    fn resource_rep(&mut self, resource: u32, types: &mut TypeAlloc, offset: u64) -> Result<()> {
1415
315
        let rep = self.check_local_resource(resource, types, offset)?;
1416
315
        let id = types.intern_func_type(FuncType::new([ValType::I32], [rep]), offset);
1417
315
        self.core_funcs.push(id);
1418
315
        Ok(())
1419
315
    }
1420
1421
498
    fn backpressure_inc(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> {
1422
498
        require_feature::cm_async(
1423
498
            self.features,
1424
            "`backpressure.inc` requires the component model async feature",
1425
498
            offset,
1426
0
        )?;
1427
1428
498
        self.core_funcs
1429
498
            .push(types.intern_func_type(FuncType::new([], []), offset));
1430
498
        Ok(())
1431
498
    }
1432
1433
498
    fn backpressure_dec(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> {
1434
498
        require_feature::cm_async(
1435
498
            self.features,
1436
            "`backpressure.dec` requires the component model async feature",
1437
498
            offset,
1438
0
        )?;
1439
1440
498
        self.core_funcs
1441
498
            .push(types.intern_func_type(FuncType::new([], []), offset));
1442
498
        Ok(())
1443
498
    }
1444
1445
2.02k
    fn task_return(
1446
2.02k
        &mut self,
1447
2.02k
        result: &Option<crate::ComponentValType>,
1448
2.02k
        options: &[CanonicalOption],
1449
2.02k
        types: &mut TypeAlloc,
1450
2.02k
        offset: u64,
1451
2.02k
    ) -> Result<()> {
1452
2.02k
        require_feature::cm_async(
1453
2.02k
            self.features,
1454
            "`task.return` requires the component model async feature",
1455
2.02k
            offset,
1456
0
        )?;
1457
1458
2.02k
        let func_ty = ComponentFuncType {
1459
            async_: false,
1460
2.02k
            info: TypeInfo::new(),
1461
2.02k
            params: result
1462
2.02k
                .iter()
1463
2.02k
                .map(|ty| {
1464
                    Ok((
1465
2.01k
                        KebabString::new("v").unwrap(),
1466
2.01k
                        match ty {
1467
2.01k
                            crate::ComponentValType::Primitive(ty) => {
1468
2.01k
                                ComponentValType::Primitive(*ty)
1469
                            }
1470
0
                            crate::ComponentValType::Type(index) => {
1471
0
                                ComponentValType::Type(self.defined_type_at(*index, offset)?)
1472
                            }
1473
                        },
1474
                    ))
1475
2.01k
                })
1476
2.02k
                .collect::<Result<_>>()?,
1477
2.02k
            result: None,
1478
        };
1479
1480
2.02k
        let options = self.check_options(types, options, offset)?;
1481
2.02k
        if options.realloc.is_some() {
1482
0
            bail!(offset, "cannot specify `realloc` option on `task.return`")
1483
2.02k
        }
1484
2.02k
        if options.post_return.is_some() {
1485
0
            bail!(
1486
0
                offset,
1487
                "cannot specify `post-return` option on `task.return`"
1488
            )
1489
2.02k
        }
1490
2.02k
        options.check_lower(offset)?;
1491
2.02k
        options.require_sync(offset, "task.return")?;
1492
1493
2.02k
        let func_ty = func_ty.lower(types, &options, Abi::Lower, offset)?;
1494
2.02k
        let ty_id = func_ty.intern(types, offset);
1495
1496
2.02k
        self.core_funcs.push(ty_id);
1497
2.02k
        Ok(())
1498
2.02k
    }
1499
1500
498
    fn task_cancel(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> {
1501
498
        require_feature::cm_async(
1502
498
            self.features,
1503
            "`task.cancel` requires the component model async feature",
1504
498
            offset,
1505
0
        )?;
1506
1507
498
        self.core_funcs
1508
498
            .push(types.intern_func_type(FuncType::new([], []), offset));
1509
498
        Ok(())
1510
498
    }
1511
1512
996
    fn validate_context_immediate(
1513
996
        &self,
1514
996
        immediate: u32,
1515
996
        operation: &str,
1516
996
        offset: u64,
1517
996
    ) -> Result<()> {
1518
996
        if immediate > 0 {
1519
0
            require_feature::cm_threading(
1520
0
                self.features,
1521
0
                format_args!("`{operation}` immediate must be zero: {immediate}"),
1522
0
                offset,
1523
0
            )?;
1524
0
            if immediate > 1 {
1525
0
                bail!(
1526
0
                    offset,
1527
                    "`{operation}` immediate must be zero or one: {immediate}"
1528
                )
1529
0
            }
1530
996
        }
1531
996
        Ok(())
1532
996
    }
1533
1534
498
    fn context_get(
1535
498
        &mut self,
1536
498
        ty: ValType,
1537
498
        i: u32,
1538
498
        types: &mut TypeAlloc,
1539
498
        offset: u64,
1540
498
    ) -> Result<()> {
1541
498
        require_feature::cm_async(
1542
498
            self.features,
1543
            "`context.get` requires the component model async feature",
1544
498
            offset,
1545
0
        )?;
1546
498
        self.validate_context_type(ty, "context.get", offset)?;
1547
498
        self.validate_context_immediate(i, "context.get", offset)?;
1548
1549
498
        self.core_funcs
1550
498
            .push(types.intern_func_type(FuncType::new([], [ty]), offset));
1551
498
        Ok(())
1552
498
    }
1553
1554
498
    fn context_set(
1555
498
        &mut self,
1556
498
        ty: ValType,
1557
498
        i: u32,
1558
498
        types: &mut TypeAlloc,
1559
498
        offset: u64,
1560
498
    ) -> Result<()> {
1561
498
        require_feature::cm_async(
1562
498
            self.features,
1563
            "`context.set` requires the component model async feature",
1564
498
            offset,
1565
0
        )?;
1566
498
        self.validate_context_type(ty, "context.set", offset)?;
1567
498
        self.validate_context_immediate(i, "context.set", offset)?;
1568
1569
498
        self.core_funcs
1570
498
            .push(types.intern_func_type(FuncType::new([ty], []), offset));
1571
498
        Ok(())
1572
498
    }
1573
1574
996
    fn validate_context_type(&mut self, ty: ValType, intrinsic: &str, offset: u64) -> Result<()> {
1575
996
        match ty {
1576
996
            ValType::I32 => {}
1577
            ValType::I64 => {
1578
0
                require_feature::cm64(
1579
0
                    self.features,
1580
0
                    format_args!(
1581
                        "64-bit `{intrinsic}` requires the component model 64-bit feature"
1582
                    ),
1583
0
                    offset,
1584
0
                )?;
1585
0
                {}
1586
            }
1587
0
            _ => bail!(offset, "`{intrinsic}` only supports `i32` or `i64`"),
1588
        }
1589
1590
996
        match self.context_type {
1591
498
            None => self.context_type = Some(ty),
1592
498
            Some(other) => {
1593
498
                if other != ty {
1594
0
                    bail!(
1595
0
                        offset,
1596
                        "`{intrinsic}` type must match previous context type"
1597
                    )
1598
498
                }
1599
            }
1600
        }
1601
996
        Ok(())
1602
996
    }
1603
1604
498
    fn subtask_drop(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> {
1605
498
        require_feature::cm_async(
1606
498
            self.features,
1607
            "`subtask.drop` requires the component model async feature",
1608
498
            offset,
1609
0
        )?;
1610
1611
498
        self.core_funcs
1612
498
            .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
1613
498
        Ok(())
1614
498
    }
1615
1616
498
    fn subtask_cancel(&mut self, async_: bool, types: &mut TypeAlloc, offset: u64) -> Result<()> {
1617
498
        require_feature::cm_async(
1618
498
            self.features,
1619
            "`subtask.cancel` requires the component model async feature",
1620
498
            offset,
1621
0
        )?;
1622
498
        if async_ {
1623
0
            require_feature::cm_more_async_builtins(
1624
0
                self.features,
1625
                "async `subtask.cancel` requires the component model more async builtins feature",
1626
0
                offset,
1627
0
            )?;
1628
498
        }
1629
1630
498
        self.core_funcs
1631
498
            .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
1632
498
        Ok(())
1633
498
    }
1634
1635
15
    fn stream_new(&mut self, ty: u32, types: &mut TypeAlloc, offset: u64) -> Result<()> {
1636
15
        require_feature::cm_async(
1637
15
            self.features,
1638
            "`stream.new` requires the component model async feature",
1639
15
            offset,
1640
0
        )?;
1641
1642
15
        let ty = self.defined_type_at(ty, offset)?;
1643
15
        let ComponentDefinedType::Stream { .. } = &types[ty] else {
1644
0
            bail!(offset, "`stream.new` requires a stream type")
1645
        };
1646
1647
15
        self.core_funcs
1648
15
            .push(types.intern_func_type(FuncType::new([], [ValType::I64]), offset));
1649
15
        Ok(())
1650
15
    }
1651
1652
15
    fn stream_read(
1653
15
        &mut self,
1654
15
        ty: u32,
1655
15
        options: &[CanonicalOption],
1656
15
        types: &mut TypeAlloc,
1657
15
        offset: u64,
1658
15
    ) -> Result<()> {
1659
15
        require_feature::cm_async(
1660
15
            self.features,
1661
            "`stream.read` requires the component model async feature",
1662
15
            offset,
1663
0
        )?;
1664
1665
15
        let ty = self.defined_type_at(ty, offset)?;
1666
15
        let ComponentDefinedType::Stream { ty: elem_ty, .. } = &types[ty] else {
1667
0
            bail!(offset, "`stream.read` requires a stream type")
1668
        };
1669
1670
15
        let options = self.check_options(types, options, offset)?;
1671
15
        if options.concurrency.is_sync() {
1672
0
            require_feature::cm_more_async_builtins(
1673
0
                self.features,
1674
                "synchronous `stream.read` requires the component model more async builtins feature",
1675
0
                offset,
1676
0
            )?;
1677
15
        }
1678
15
        let ty_id = options
1679
15
            .require_memory_if(offset, || elem_ty.is_some())?
1680
15
            .require_realloc_if(offset, || elem_ty.is_some_and(|ty| ty.contains_ptr(types)))?
1681
15
            .check_lower(offset)?
1682
15
            .check_core_type(
1683
15
                types,
1684
15
                FuncType::new([ValType::I32; 3], [ValType::I32]),
1685
15
                offset,
1686
0
            )?;
1687
1688
15
        self.core_funcs.push(ty_id);
1689
15
        Ok(())
1690
15
    }
1691
1692
15
    fn stream_write(
1693
15
        &mut self,
1694
15
        ty: u32,
1695
15
        options: &[CanonicalOption],
1696
15
        types: &mut TypeAlloc,
1697
15
        offset: u64,
1698
15
    ) -> Result<()> {
1699
15
        require_feature::cm_async(
1700
15
            self.features,
1701
            "`stream.write` requires the component model async feature",
1702
15
            offset,
1703
0
        )?;
1704
1705
15
        let ty = self.defined_type_at(ty, offset)?;
1706
15
        let ComponentDefinedType::Stream { ty: elem_ty, .. } = &types[ty] else {
1707
0
            bail!(offset, "`stream.write` requires a stream type")
1708
        };
1709
1710
15
        let options = self.check_options(types, options, offset)?;
1711
15
        if options.concurrency.is_sync() {
1712
0
            require_feature::cm_more_async_builtins(
1713
0
                self.features,
1714
                "synchronous `stream.write` requires the component model more async builtins feature",
1715
0
                offset,
1716
0
            )?;
1717
15
        }
1718
15
        let ty_id = options
1719
15
            .require_memory_if(offset, || elem_ty.is_some())?
1720
15
            .check_lower(offset)?
1721
15
            .check_core_type(
1722
15
                types,
1723
15
                FuncType::new([ValType::I32; 3], [ValType::I32]),
1724
15
                offset,
1725
0
            )?;
1726
1727
15
        self.core_funcs.push(ty_id);
1728
15
        Ok(())
1729
15
    }
1730
1731
15
    fn stream_cancel_read(
1732
15
        &mut self,
1733
15
        ty: u32,
1734
15
        cancellable: bool,
1735
15
        types: &mut TypeAlloc,
1736
15
        offset: u64,
1737
15
    ) -> Result<()> {
1738
15
        require_feature::cm_async(
1739
15
            self.features,
1740
            "`stream.cancel-read` requires the component model async feature",
1741
15
            offset,
1742
0
        )?;
1743
15
        if cancellable {
1744
0
            require_feature::cm_more_async_builtins(
1745
0
                self.features,
1746
                "async `stream.cancel-read` requires the component model more async builtins feature",
1747
0
                offset,
1748
0
            )?;
1749
15
        }
1750
1751
15
        let ty = self.defined_type_at(ty, offset)?;
1752
15
        let ComponentDefinedType::Stream { .. } = &types[ty] else {
1753
0
            bail!(offset, "`stream.cancel-read` requires a stream type")
1754
        };
1755
1756
15
        self.core_funcs
1757
15
            .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
1758
15
        Ok(())
1759
15
    }
1760
1761
15
    fn stream_cancel_write(
1762
15
        &mut self,
1763
15
        ty: u32,
1764
15
        cancellable: bool,
1765
15
        types: &mut TypeAlloc,
1766
15
        offset: u64,
1767
15
    ) -> Result<()> {
1768
15
        require_feature::cm_async(
1769
15
            self.features,
1770
            "`stream.cancel-write` requires the component model async feature",
1771
15
            offset,
1772
0
        )?;
1773
15
        if cancellable {
1774
0
            require_feature::cm_more_async_builtins(
1775
0
                self.features,
1776
                "async `stream.cancel-write` requires the component model more async builtins feature",
1777
0
                offset,
1778
0
            )?;
1779
15
        }
1780
1781
15
        let ty = self.defined_type_at(ty, offset)?;
1782
15
        let ComponentDefinedType::Stream { .. } = &types[ty] else {
1783
0
            bail!(offset, "`stream.cancel-write` requires a stream type")
1784
        };
1785
1786
15
        self.core_funcs
1787
15
            .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
1788
15
        Ok(())
1789
15
    }
1790
1791
15
    fn stream_drop_readable(&mut self, ty: u32, types: &mut TypeAlloc, offset: u64) -> Result<()> {
1792
15
        require_feature::cm_async(
1793
15
            self.features,
1794
            "`stream.drop-readable` requires the component model async feature",
1795
15
            offset,
1796
0
        )?;
1797
1798
15
        let ty = self.defined_type_at(ty, offset)?;
1799
15
        let ComponentDefinedType::Stream { .. } = &types[ty] else {
1800
0
            bail!(offset, "`stream.drop-readable` requires a stream type")
1801
        };
1802
1803
15
        self.core_funcs
1804
15
            .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
1805
15
        Ok(())
1806
15
    }
1807
1808
15
    fn stream_drop_writable(&mut self, ty: u32, types: &mut TypeAlloc, offset: u64) -> Result<()> {
1809
15
        require_feature::cm_async(
1810
15
            self.features,
1811
            "`stream.drop-writable` requires the component model async feature",
1812
15
            offset,
1813
0
        )?;
1814
1815
15
        let ty = self.defined_type_at(ty, offset)?;
1816
15
        let ComponentDefinedType::Stream { .. } = &types[ty] else {
1817
0
            bail!(offset, "`stream.drop-writable` requires a stream type")
1818
        };
1819
1820
15
        self.core_funcs
1821
15
            .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
1822
15
        Ok(())
1823
15
    }
1824
1825
363
    fn future_new(&mut self, ty: u32, types: &mut TypeAlloc, offset: u64) -> Result<()> {
1826
363
        require_feature::cm_async(
1827
363
            self.features,
1828
            "`future.new` requires the component model async feature",
1829
363
            offset,
1830
0
        )?;
1831
1832
363
        let ty = self.defined_type_at(ty, offset)?;
1833
363
        let ComponentDefinedType::Future { .. } = &types[ty] else {
1834
0
            bail!(offset, "`future.new` requires a future type")
1835
        };
1836
1837
363
        self.core_funcs
1838
363
            .push(types.intern_func_type(FuncType::new([], [ValType::I64]), offset));
1839
363
        Ok(())
1840
363
    }
1841
1842
21
    fn future_read(
1843
21
        &mut self,
1844
21
        ty: u32,
1845
21
        options: &[CanonicalOption],
1846
21
        types: &mut TypeAlloc,
1847
21
        offset: u64,
1848
21
    ) -> Result<()> {
1849
21
        require_feature::cm_async(
1850
21
            self.features,
1851
            "`future.read` requires the component model async feature",
1852
21
            offset,
1853
0
        )?;
1854
1855
21
        let ty = self.defined_type_at(ty, offset)?;
1856
21
        let ComponentDefinedType::Future { ty: elem_ty, .. } = &types[ty] else {
1857
0
            bail!(offset, "`future.read` requires a future type")
1858
        };
1859
1860
21
        let options = self.check_options(types, options, offset)?;
1861
21
        if options.concurrency.is_sync() {
1862
0
            require_feature::cm_more_async_builtins(
1863
0
                self.features,
1864
                "synchronous `future.read` requires the component model more async builtins feature",
1865
0
                offset,
1866
0
            )?;
1867
21
        }
1868
21
        let ty_id = options
1869
21
            .require_memory_if(offset, || elem_ty.is_some())?
1870
21
            .require_realloc_if(offset, || elem_ty.is_some_and(|ty| ty.contains_ptr(types)))?
1871
21
            .check_lower(offset)?
1872
21
            .check_core_type(
1873
21
                types,
1874
21
                FuncType::new([ValType::I32; 2], [ValType::I32]),
1875
21
                offset,
1876
0
            )?;
1877
1878
21
        self.core_funcs.push(ty_id);
1879
21
        Ok(())
1880
21
    }
1881
1882
21
    fn future_write(
1883
21
        &mut self,
1884
21
        ty: u32,
1885
21
        options: &[CanonicalOption],
1886
21
        types: &mut TypeAlloc,
1887
21
        offset: u64,
1888
21
    ) -> Result<()> {
1889
21
        require_feature::cm_async(
1890
21
            self.features,
1891
            "`future.write` requires the component model async feature",
1892
21
            offset,
1893
0
        )?;
1894
1895
21
        let ty = self.defined_type_at(ty, offset)?;
1896
21
        let ComponentDefinedType::Future { ty: elem_ty, .. } = &types[ty] else {
1897
0
            bail!(offset, "`future.write` requires a future type")
1898
        };
1899
1900
21
        let options = self.check_options(types, &options, offset)?;
1901
21
        if options.concurrency.is_sync() {
1902
0
            require_feature::cm_more_async_builtins(
1903
0
                self.features,
1904
                "synchronous `future.write` requires the component model more async builtins feature",
1905
0
                offset,
1906
0
            )?;
1907
21
        }
1908
21
        let ty_id = options
1909
21
            .require_memory_if(offset, || elem_ty.is_some())?
1910
21
            .check_core_type(
1911
21
                types,
1912
21
                FuncType::new([ValType::I32; 2], [ValType::I32]),
1913
21
                offset,
1914
0
            )?;
1915
1916
21
        self.core_funcs.push(ty_id);
1917
21
        Ok(())
1918
21
    }
1919
1920
363
    fn future_cancel_read(
1921
363
        &mut self,
1922
363
        ty: u32,
1923
363
        cancellable: bool,
1924
363
        types: &mut TypeAlloc,
1925
363
        offset: u64,
1926
363
    ) -> Result<()> {
1927
363
        require_feature::cm_async(
1928
363
            self.features,
1929
            "`future.cancel-read` requires the component model async feature",
1930
363
            offset,
1931
0
        )?;
1932
363
        if cancellable {
1933
0
            require_feature::cm_more_async_builtins(
1934
0
                self.features,
1935
                "async `future.cancel-read` requires the component model more async builtins feature",
1936
0
                offset,
1937
0
            )?;
1938
363
        }
1939
1940
363
        let ty = self.defined_type_at(ty, offset)?;
1941
363
        let ComponentDefinedType::Future { .. } = &types[ty] else {
1942
0
            bail!(offset, "`future.cancel-read` requires a future type")
1943
        };
1944
1945
363
        self.core_funcs
1946
363
            .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
1947
363
        Ok(())
1948
363
    }
1949
1950
363
    fn future_cancel_write(
1951
363
        &mut self,
1952
363
        ty: u32,
1953
363
        cancellable: bool,
1954
363
        types: &mut TypeAlloc,
1955
363
        offset: u64,
1956
363
    ) -> Result<()> {
1957
363
        require_feature::cm_async(
1958
363
            self.features,
1959
            "`future.cancel-write` requires the component model async feature",
1960
363
            offset,
1961
0
        )?;
1962
363
        if cancellable {
1963
0
            require_feature::cm_more_async_builtins(
1964
0
                self.features,
1965
                "async `future.cancel-write` requires the component model more async builtins feature",
1966
0
                offset,
1967
0
            )?;
1968
363
        }
1969
1970
363
        let ty = self.defined_type_at(ty, offset)?;
1971
363
        let ComponentDefinedType::Future { .. } = &types[ty] else {
1972
0
            bail!(offset, "`future.cancel-write` requires a future type")
1973
        };
1974
1975
363
        self.core_funcs
1976
363
            .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
1977
363
        Ok(())
1978
363
    }
1979
1980
363
    fn future_drop_readable(&mut self, ty: u32, types: &mut TypeAlloc, offset: u64) -> Result<()> {
1981
363
        require_feature::cm_async(
1982
363
            self.features,
1983
            "`future.drop-readable` requires the component model async feature",
1984
363
            offset,
1985
0
        )?;
1986
1987
363
        let ty = self.defined_type_at(ty, offset)?;
1988
363
        let ComponentDefinedType::Future { .. } = &types[ty] else {
1989
0
            bail!(offset, "`future.drop-readable` requires a future type")
1990
        };
1991
1992
363
        self.core_funcs
1993
363
            .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
1994
363
        Ok(())
1995
363
    }
1996
1997
363
    fn future_drop_writable(&mut self, ty: u32, types: &mut TypeAlloc, offset: u64) -> Result<()> {
1998
363
        require_feature::cm_async(
1999
363
            self.features,
2000
            "`future.drop-writable` requires the component model async feature",
2001
363
            offset,
2002
0
        )?;
2003
2004
363
        let ty = self.defined_type_at(ty, offset)?;
2005
363
        let ComponentDefinedType::Future { .. } = &types[ty] else {
2006
0
            bail!(offset, "`future.drop-writable` requires a future type")
2007
        };
2008
2009
363
        self.core_funcs
2010
363
            .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
2011
363
        Ok(())
2012
363
    }
2013
2014
0
    fn error_context_new(
2015
0
        &mut self,
2016
0
        options: Vec<CanonicalOption>,
2017
0
        types: &mut TypeAlloc,
2018
0
        offset: u64,
2019
0
    ) -> Result<()> {
2020
0
        require_feature::cm_error_context(
2021
0
            self.features,
2022
            "`error-context.new` requires the component model error-context feature",
2023
0
            offset,
2024
0
        )?;
2025
2026
0
        let ty_id = self
2027
0
            .check_options(types, &options, offset)?
2028
0
            .require_memory(offset)?
2029
0
            .require_sync(offset, "error-context.new")?
2030
0
            .check_lower(offset)?
2031
0
            .check_core_type(
2032
0
                types,
2033
0
                FuncType::new([ValType::I32; 2], [ValType::I32]),
2034
0
                offset,
2035
0
            )?;
2036
2037
0
        self.core_funcs.push(ty_id);
2038
0
        Ok(())
2039
0
    }
2040
2041
0
    fn error_context_debug_message(
2042
0
        &mut self,
2043
0
        options: Vec<CanonicalOption>,
2044
0
        types: &mut TypeAlloc,
2045
0
        offset: u64,
2046
0
    ) -> Result<()> {
2047
0
        require_feature::cm_error_context(
2048
0
            self.features,
2049
            "`error-context.debug-message` requires the component model error-context feature",
2050
0
            offset,
2051
0
        )?;
2052
2053
0
        let ty_id = self
2054
0
            .check_options(types, &options, offset)?
2055
0
            .require_memory(offset)?
2056
0
            .require_realloc(offset)?
2057
0
            .require_sync(offset, "error-context.debug-message")?
2058
0
            .check_lower(offset)?
2059
0
            .check_core_type(types, FuncType::new([ValType::I32; 2], []), offset)?;
2060
2061
0
        self.core_funcs.push(ty_id);
2062
0
        Ok(())
2063
0
    }
2064
2065
0
    fn error_context_drop(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> {
2066
0
        require_feature::cm_error_context(
2067
0
            self.features,
2068
            "`error-context.drop` requires the component model error-context feature",
2069
0
            offset,
2070
0
        )?;
2071
2072
0
        self.core_funcs
2073
0
            .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
2074
0
        Ok(())
2075
0
    }
2076
2077
498
    fn waitable_set_new(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> {
2078
498
        require_feature::cm_async(
2079
498
            self.features,
2080
            "`waitable-set.new` requires the component model async feature",
2081
498
            offset,
2082
0
        )?;
2083
2084
498
        self.core_funcs
2085
498
            .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset));
2086
498
        Ok(())
2087
498
    }
2088
2089
498
    fn waitable_set_wait(&mut self, memory: u32, types: &mut TypeAlloc, offset: u64) -> Result<()> {
2090
498
        require_feature::cm_async(
2091
498
            self.features,
2092
            "`waitable-set.wait` requires the component model async feature",
2093
498
            offset,
2094
0
        )?;
2095
2096
498
        self.cabi_memory_at(memory, offset)?;
2097
498
        let memory64 = self.memory_at(memory, offset)?.memory64;
2098
498
        let ty = if memory64 { ValType::I64 } else { ValType::I32 };
2099
498
        self.core_funcs.push(
2100
498
            types.intern_func_type(FuncType::new([ValType::I32, ty], [ValType::I32]), offset),
2101
        );
2102
498
        Ok(())
2103
498
    }
2104
2105
498
    fn waitable_set_poll(&mut self, memory: u32, types: &mut TypeAlloc, offset: u64) -> Result<()> {
2106
498
        require_feature::cm_async(
2107
498
            self.features,
2108
            "`waitable-set.poll` requires the component model async feature",
2109
498
            offset,
2110
0
        )?;
2111
2112
498
        self.cabi_memory_at(memory, offset)?;
2113
498
        let memory64 = self.memory_at(memory, offset)?.memory64;
2114
498
        let ty = if memory64 { ValType::I64 } else { ValType::I32 };
2115
498
        self.core_funcs.push(
2116
498
            types.intern_func_type(FuncType::new([ValType::I32, ty], [ValType::I32]), offset),
2117
        );
2118
498
        Ok(())
2119
498
    }
2120
2121
498
    fn waitable_set_drop(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> {
2122
498
        require_feature::cm_async(
2123
498
            self.features,
2124
            "`waitable-set.drop` requires the component model async feature",
2125
498
            offset,
2126
0
        )?;
2127
2128
498
        self.core_funcs
2129
498
            .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
2130
498
        Ok(())
2131
498
    }
2132
2133
498
    fn waitable_join(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> {
2134
498
        require_feature::cm_async(
2135
498
            self.features,
2136
            "`waitable.join` requires the component model async feature",
2137
498
            offset,
2138
0
        )?;
2139
2140
498
        self.core_funcs
2141
498
            .push(types.intern_func_type(FuncType::new([ValType::I32; 2], []), offset));
2142
498
        Ok(())
2143
498
    }
2144
2145
0
    fn thread_index(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> {
2146
0
        require_feature::cm_threading(
2147
0
            self.features,
2148
            "`thread.index` requires the component model threading feature",
2149
0
            offset,
2150
0
        )?;
2151
2152
0
        self.core_funcs
2153
0
            .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset));
2154
0
        Ok(())
2155
0
    }
2156
2157
0
    fn thread_new_indirect(
2158
0
        &mut self,
2159
0
        func_ty_index: u32,
2160
0
        table_index: u32,
2161
0
        types: &mut TypeAlloc,
2162
0
        offset: u64,
2163
0
    ) -> Result<()> {
2164
0
        require_feature::cm_threading(
2165
0
            self.features,
2166
            "`thread.new-indirect` requires the component model threading feature",
2167
0
            offset,
2168
0
        )?;
2169
2170
0
        let core_type_id = match self.core_type_at(func_ty_index, offset)? {
2171
0
            ComponentCoreTypeId::Sub(c) => c,
2172
0
            ComponentCoreTypeId::Module(_) => bail!(offset, "expected a core function type"),
2173
        };
2174
0
        let sub_ty = &types[core_type_id];
2175
0
        match &sub_ty.composite_type.inner {
2176
0
            CompositeInnerType::Func(func_ty) => {
2177
0
                if func_ty.params() != [ValType::I32] {
2178
0
                    bail!(
2179
0
                        offset,
2180
                        "start function must take a single `i32` argument (currently)"
2181
                    );
2182
0
                }
2183
0
                if func_ty.results() != [] {
2184
0
                    bail!(offset, "start function must not return any values");
2185
0
                }
2186
            }
2187
0
            _ => bail!(offset, "start type must be a function"),
2188
        }
2189
2190
0
        let table = self.table_at(table_index, offset)?;
2191
2192
0
        SubtypeCx::table_type(
2193
0
            table,
2194
0
            &TableType {
2195
0
                initial: 0,
2196
0
                maximum: None,
2197
0
                table64: false,
2198
0
                shared: false,
2199
0
                element_type: RefType::FUNCREF,
2200
0
            },
2201
0
            offset,
2202
        )
2203
0
        .map_err(|mut e| {
2204
0
            e.add_context("table is not a 32-bit table of (ref null (func))".into());
2205
0
            e
2206
0
        })?;
2207
2208
0
        self.core_funcs.push(types.intern_func_type(
2209
0
            FuncType::new([ValType::I32, ValType::I32], [ValType::I32]),
2210
0
            offset,
2211
0
        ));
2212
0
        Ok(())
2213
0
    }
2214
2215
0
    fn thread_resume_later(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> {
2216
0
        require_feature::cm_threading(
2217
0
            self.features,
2218
            "`thread.resume-later` requires the component model threading feature",
2219
0
            offset,
2220
0
        )?;
2221
0
        self.core_funcs
2222
0
            .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
2223
0
        Ok(())
2224
0
    }
2225
2226
0
    fn thread_suspend(
2227
0
        &mut self,
2228
0
        _cancellable: bool,
2229
0
        types: &mut TypeAlloc,
2230
0
        offset: u64,
2231
0
    ) -> Result<()> {
2232
0
        require_feature::cm_threading(
2233
0
            self.features,
2234
            "`thread.suspend` requires the component model threading feature",
2235
0
            offset,
2236
0
        )?;
2237
0
        self.core_funcs
2238
0
            .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset));
2239
0
        Ok(())
2240
0
    }
2241
2242
498
    fn thread_yield(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> {
2243
498
        require_feature::cm_async(
2244
498
            self.features,
2245
            "`thread.yield` requires the component model async feature",
2246
498
            offset,
2247
0
        )?;
2248
2249
498
        self.core_funcs
2250
498
            .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset));
2251
498
        Ok(())
2252
498
    }
2253
2254
0
    fn thread_suspend_then_resume(
2255
0
        &mut self,
2256
0
        _cancellable: bool,
2257
0
        types: &mut TypeAlloc,
2258
0
        offset: u64,
2259
0
    ) -> Result<()> {
2260
0
        require_feature::cm_threading(
2261
0
            self.features,
2262
            "`thread.suspend-then-resume` requires the component model threading feature",
2263
0
            offset,
2264
0
        )?;
2265
2266
0
        self.core_funcs
2267
0
            .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
2268
0
        Ok(())
2269
0
    }
2270
2271
0
    fn thread_yield_then_resume(
2272
0
        &mut self,
2273
0
        _cancellable: bool,
2274
0
        types: &mut TypeAlloc,
2275
0
        offset: u64,
2276
0
    ) -> Result<()> {
2277
0
        require_feature::cm_threading(
2278
0
            self.features,
2279
            "`thread.yield-then-resume` requires the component model threading feature",
2280
0
            offset,
2281
0
        )?;
2282
0
        self.core_funcs
2283
0
            .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
2284
0
        Ok(())
2285
0
    }
2286
2287
0
    fn thread_suspend_then_promote(
2288
0
        &mut self,
2289
0
        _cancellable: bool,
2290
0
        types: &mut TypeAlloc,
2291
0
        offset: u64,
2292
0
    ) -> Result<()> {
2293
0
        require_feature::cm_threading(
2294
0
            self.features,
2295
            "`thread.suspend-then-promote` requires the component model threading feature",
2296
0
            offset,
2297
0
        )?;
2298
0
        self.core_funcs
2299
0
            .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
2300
0
        Ok(())
2301
0
    }
2302
2303
0
    fn thread_yield_then_promote(
2304
0
        &mut self,
2305
0
        _cancellable: bool,
2306
0
        types: &mut TypeAlloc,
2307
0
        offset: u64,
2308
0
    ) -> Result<()> {
2309
0
        require_feature::cm_threading(
2310
0
            self.features,
2311
            "`thread.yield-then-promote` requires the component model threading feature",
2312
0
            offset,
2313
0
        )?;
2314
0
        self.core_funcs
2315
0
            .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
2316
0
        Ok(())
2317
0
    }
2318
2319
630
    fn check_local_resource(&self, idx: u32, types: &TypeList, offset: u64) -> Result<ValType> {
2320
630
        let resource = self.resource_at(idx, types, offset)?;
2321
630
        match self
2322
630
            .defined_resources
2323
630
            .get(&resource.resource())
2324
630
            .and_then(|rep| *rep)
2325
        {
2326
630
            Some(ty) => Ok(ty),
2327
0
            None => bail!(offset, "type {idx} is not a local resource"),
2328
        }
2329
630
    }
2330
2331
2.96k
    fn resource_at<'a>(
2332
2.96k
        &self,
2333
2.96k
        idx: u32,
2334
2.96k
        _types: &'a TypeList,
2335
2.96k
        offset: u64,
2336
2.96k
    ) -> Result<AliasableResourceId> {
2337
2.96k
        if let ComponentAnyTypeId::Resource(id) = self.component_type_at(idx, offset)? {
2338
2.96k
            return Ok(id);
2339
0
        }
2340
0
        bail!(offset, "type index {} is not a resource type", idx)
2341
2.96k
    }
2342
2343
0
    fn thread_spawn_ref(
2344
0
        &mut self,
2345
0
        func_ty_index: u32,
2346
0
        types: &mut TypeAlloc,
2347
0
        offset: u64,
2348
0
    ) -> Result<()> {
2349
0
        require_feature::shared_everything_threads(
2350
0
            self.features,
2351
            "`thread.spawn-ref` requires the shared-everything-threads proposal",
2352
0
            offset,
2353
0
        )?;
2354
0
        let core_type_id = self.validate_spawn_type(func_ty_index, types, offset)?;
2355
2356
        // Insert the core function.
2357
0
        let packed_index = PackedIndex::from_id(core_type_id).ok_or_else(|| {
2358
0
            format_err!(offset, "implementation limit: too many types in `TypeList`")
2359
0
        })?;
2360
0
        let start_func_ref = RefType::concrete(true, packed_index);
2361
0
        let func_ty = FuncType::new([ValType::Ref(start_func_ref), ValType::I32], [ValType::I32]);
2362
0
        let core_ty = SubType::func(func_ty, true);
2363
0
        let id = types.intern_sub_type(core_ty, offset);
2364
0
        self.core_funcs.push(id);
2365
2366
0
        Ok(())
2367
0
    }
2368
2369
0
    fn thread_spawn_indirect(
2370
0
        &mut self,
2371
0
        func_ty_index: u32,
2372
0
        table_index: u32,
2373
0
        types: &mut TypeAlloc,
2374
0
        offset: u64,
2375
0
    ) -> Result<()> {
2376
0
        require_feature::shared_everything_threads(
2377
0
            self.features,
2378
            "`thread.spawn-indirect` requires the shared-everything-threads proposal",
2379
0
            offset,
2380
0
        )?;
2381
0
        let _ = self.validate_spawn_type(func_ty_index, types, offset)?;
2382
2383
        // Check this much like `call_indirect` (see
2384
        // `OperatorValidatorTemp::check_call_indirect_ty`), but loosen the
2385
        // table type restrictions to just a `funcref`. See the component model
2386
        // for more details:
2387
        // https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md#-canon-threadspawn-indirect.
2388
0
        let table = self.table_at(table_index, offset)?;
2389
2390
0
        SubtypeCx::table_type(
2391
0
            table,
2392
0
            &TableType {
2393
0
                initial: 0,
2394
0
                maximum: None,
2395
0
                table64: false,
2396
0
                shared: true,
2397
0
                element_type: RefType::FUNCREF
2398
0
                    .shared()
2399
0
                    .expect("a funcref can always be shared"),
2400
0
            },
2401
0
            offset,
2402
        )
2403
0
        .map_err(|mut e| {
2404
0
            e.add_context("table is not a 32-bit shared table of (ref null (shared func))".into());
2405
0
            e
2406
0
        })?;
2407
2408
        // Insert the core function.
2409
0
        let func_ty = FuncType::new([ValType::I32, ValType::I32], [ValType::I32]);
2410
0
        let core_ty = SubType::func(func_ty, true);
2411
0
        let id = types.intern_sub_type(core_ty, offset);
2412
0
        self.core_funcs.push(id);
2413
2414
0
        Ok(())
2415
0
    }
2416
2417
    /// Validates the type of a `thread.spawn*` instruction.
2418
    ///
2419
    /// This is currently limited to shared functions with the signature `[i32]
2420
    /// -> []`. See component model [explanation] for more details.
2421
    ///
2422
    /// [explanation]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md#-canon-threadspawn-ref
2423
0
    fn validate_spawn_type(
2424
0
        &self,
2425
0
        func_ty_index: u32,
2426
0
        types: &TypeAlloc,
2427
0
        offset: u64,
2428
0
    ) -> Result<CoreTypeId> {
2429
0
        let core_type_id = match self.core_type_at(func_ty_index, offset)? {
2430
0
            ComponentCoreTypeId::Sub(c) => c,
2431
0
            ComponentCoreTypeId::Module(_) => bail!(offset, "expected a core function type"),
2432
        };
2433
0
        let sub_ty = &types[core_type_id];
2434
0
        if !sub_ty.composite_type.shared {
2435
0
            bail!(offset, "spawn type must be shared");
2436
0
        }
2437
0
        match &sub_ty.composite_type.inner {
2438
0
            CompositeInnerType::Func(func_ty) => {
2439
0
                if func_ty.params() != [ValType::I32] {
2440
0
                    bail!(
2441
0
                        offset,
2442
                        "spawn function must take a single `i32` argument (currently)"
2443
                    );
2444
0
                }
2445
0
                if func_ty.results() != [] {
2446
0
                    bail!(offset, "spawn function must not return any values");
2447
0
                }
2448
            }
2449
0
            _ => bail!(offset, "spawn type must be a function"),
2450
        }
2451
0
        Ok(core_type_id)
2452
0
    }
2453
2454
0
    fn thread_available_parallelism(&mut self, types: &mut TypeAlloc, offset: u64) -> Result<()> {
2455
0
        require_feature::shared_everything_threads(
2456
0
            self.features,
2457
            "`thread.available_parallelism` requires the shared-everything-threads proposal",
2458
0
            offset,
2459
0
        )?;
2460
2461
0
        let func_ty = FuncType::new([], [ValType::I32]);
2462
0
        let core_ty = SubType::func(func_ty, true);
2463
0
        let id = types.intern_sub_type(core_ty, offset);
2464
0
        self.core_funcs.push(id);
2465
2466
0
        Ok(())
2467
0
    }
2468
2469
3.41k
    pub fn add_component(&mut self, component: ComponentType, types: &mut TypeAlloc) -> Result<()> {
2470
3.41k
        let id = types.push_ty(component);
2471
3.41k
        self.components.push(id);
2472
3.41k
        Ok(())
2473
3.41k
    }
2474
2475
3.41k
    pub fn add_instance(
2476
3.41k
        &mut self,
2477
3.41k
        instance: crate::ComponentInstance,
2478
3.41k
        types: &mut TypeAlloc,
2479
3.41k
        offset: u64,
2480
3.41k
    ) -> Result<()> {
2481
3.41k
        let instance = match instance {
2482
            crate::ComponentInstance::Instantiate {
2483
3.41k
                component_index,
2484
3.41k
                args,
2485
3.41k
            } => self.instantiate_component(component_index, args.into_vec(), types, offset)?,
2486
0
            crate::ComponentInstance::FromExports(exports) => {
2487
0
                self.instantiate_component_exports(exports.into_vec(), types, offset)?
2488
            }
2489
        };
2490
2491
3.41k
        self.instances.push(instance);
2492
2493
3.41k
        Ok(())
2494
3.41k
    }
2495
2496
30.8k
    pub fn add_alias(
2497
30.8k
        components: &mut [Self],
2498
30.8k
        alias: crate::ComponentAlias,
2499
30.8k
        types: &mut TypeAlloc,
2500
30.8k
        offset: u64,
2501
30.8k
    ) -> Result<()> {
2502
30.8k
        let component = components.last_mut().unwrap();
2503
2504
30.8k
        match component.kind {
2505
            // For a component itself all alias kind are allowed.
2506
18.6k
            ComponentKind::Component => {}
2507
2508
            // For instance/component types only aliases to `type` or `instance`
2509
            // items are allowed, and all other aliases are rejected.
2510
5.18k
            ComponentKind::InstanceType | ComponentKind::ComponentType => match &alias {
2511
                crate::ComponentAlias::InstanceExport {
2512
                    kind: ComponentExternalKind::Type | ComponentExternalKind::Instance,
2513
                    ..
2514
                }
2515
                | crate::ComponentAlias::Outer {
2516
                    kind: ComponentOuterAliasKind::Type | ComponentOuterAliasKind::CoreType,
2517
                    ..
2518
12.1k
                } => {}
2519
2520
0
                _ => bail!(
2521
0
                    offset,
2522
                    "aliases in a component or instance type may only refer to types or instances"
2523
                ),
2524
            },
2525
        }
2526
2527
30.8k
        match alias {
2528
            crate::ComponentAlias::InstanceExport {
2529
7.12k
                instance_index,
2530
7.12k
                kind,
2531
7.12k
                name,
2532
7.12k
            } => component.alias_instance_export(instance_index, kind, name, types, offset),
2533
            crate::ComponentAlias::CoreInstanceExport {
2534
16.7k
                instance_index,
2535
16.7k
                kind,
2536
16.7k
                name,
2537
16.7k
            } => component.alias_core_instance_export(instance_index, kind, name, types, offset),
2538
7.01k
            crate::ComponentAlias::Outer { kind, count, index } => match kind {
2539
                ComponentOuterAliasKind::CoreModule => {
2540
0
                    Self::alias_module(components, count, index, offset)
2541
                }
2542
                ComponentOuterAliasKind::CoreType => {
2543
0
                    Self::alias_core_type(components, count, index, offset)
2544
                }
2545
                ComponentOuterAliasKind::Type => {
2546
7.01k
                    Self::alias_type(components, count, index, types, offset)
2547
                }
2548
                ComponentOuterAliasKind::Component => {
2549
0
                    Self::alias_component(components, count, index, offset)
2550
                }
2551
            },
2552
        }
2553
30.8k
    }
2554
2555
0
    pub fn add_start(
2556
0
        &mut self,
2557
0
        func_index: u32,
2558
0
        args: &[u32],
2559
0
        results: u32,
2560
0
        types: &mut TypeList,
2561
0
        offset: u64,
2562
0
    ) -> Result<()> {
2563
0
        require_feature::cm_values(
2564
0
            self.features,
2565
            "support for component model `value`s is not enabled",
2566
0
            offset,
2567
0
        )?;
2568
0
        if self.has_start {
2569
0
            return Err(Error::new(
2570
0
                "component cannot have more than one start function",
2571
0
                offset,
2572
0
            ));
2573
0
        }
2574
2575
0
        let ft = &types[self.function_at(func_index, offset)?];
2576
2577
0
        if ft.params.len() != args.len() {
2578
0
            bail!(
2579
0
                offset,
2580
                "component start function requires {} arguments but was given {}",
2581
0
                ft.params.len(),
2582
0
                args.len()
2583
            );
2584
0
        }
2585
2586
0
        if u32::from(ft.result.is_some()) != results {
2587
0
            bail!(
2588
0
                offset,
2589
                "component start function has a result count of {results} \
2590
                 but the function type has a result count of {type_results}",
2591
0
                type_results = u32::from(ft.result.is_some()),
2592
            );
2593
0
        }
2594
2595
0
        let cx = SubtypeCx::new(types, types);
2596
0
        for (i, ((_, ty), arg)) in ft.params.iter().zip(args).enumerate() {
2597
            // Ensure the value's type is a subtype of the parameter type
2598
0
            cx.component_val_type(self.value_at(*arg, offset)?, ty, offset)
2599
0
                .with_context(|| {
2600
0
                    format!("value type mismatch for component start function argument {i}")
2601
0
                })?;
2602
        }
2603
2604
0
        if let Some(ty) = ft.result {
2605
0
            self.values.push((ty, false));
2606
0
        }
2607
2608
0
        self.has_start = true;
2609
2610
0
        Ok(())
2611
0
    }
2612
2613
10.5k
    fn check_options(
2614
10.5k
        &self,
2615
10.5k
        types: &TypeList,
2616
10.5k
        options: &[CanonicalOption],
2617
10.5k
        offset: u64,
2618
10.5k
    ) -> Result<CanonicalOptions> {
2619
0
        fn display(option: CanonicalOption) -> &'static str {
2620
0
            match option {
2621
0
                CanonicalOption::UTF8 => "utf8",
2622
0
                CanonicalOption::UTF16 => "utf16",
2623
0
                CanonicalOption::CompactUTF16 => "latin1-utf16",
2624
0
                CanonicalOption::Memory(_) => "memory",
2625
0
                CanonicalOption::Realloc(_) => "realloc",
2626
0
                CanonicalOption::PostReturn(_) => "post-return",
2627
0
                CanonicalOption::Async => "async",
2628
0
                CanonicalOption::Callback(_) => "callback",
2629
0
                CanonicalOption::CoreType(_) => "core-type",
2630
0
                CanonicalOption::Gc => "gc",
2631
            }
2632
0
        }
2633
2634
10.5k
        let mut encoding = None;
2635
10.5k
        let mut memory = None;
2636
10.5k
        let mut realloc = None;
2637
10.5k
        let mut post_return = None;
2638
10.5k
        let mut is_async = false;
2639
10.5k
        let mut callback = None;
2640
10.5k
        let mut core_type = None;
2641
10.5k
        let mut gc = false;
2642
2643
10.8k
        for option in options {
2644
10.8k
            match option {
2645
                CanonicalOption::UTF8 | CanonicalOption::UTF16 | CanonicalOption::CompactUTF16 => {
2646
510
                    match encoding {
2647
0
                        Some(existing) => {
2648
0
                            bail!(
2649
0
                                offset,
2650
                                "canonical encoding option `{existing}` conflicts with option `{}`",
2651
0
                                display(*option),
2652
                            )
2653
                        }
2654
                        None => {
2655
510
                            encoding = Some(match option {
2656
510
                                CanonicalOption::UTF8 => StringEncoding::Utf8,
2657
0
                                CanonicalOption::UTF16 => StringEncoding::Utf16,
2658
0
                                CanonicalOption::CompactUTF16 => StringEncoding::CompactUtf16,
2659
0
                                _ => unreachable!(),
2660
                            });
2661
                        }
2662
                    }
2663
                }
2664
1.23k
                CanonicalOption::Memory(idx) => {
2665
1.23k
                    memory = match memory {
2666
                        None => {
2667
1.23k
                            let ptr_size = self.cabi_memory_at(*idx, offset)?;
2668
1.23k
                            Some((*idx, ptr_size))
2669
                        }
2670
                        Some(_) => {
2671
0
                            return Err(Error::new(
2672
0
                                "canonical option `memory` is specified more than once",
2673
0
                                offset,
2674
0
                            ));
2675
                        }
2676
                    }
2677
                }
2678
621
                CanonicalOption::Realloc(idx) => {
2679
621
                    realloc = match realloc {
2680
                        None => {
2681
                            // Validation deferred because it may depend on the memory option.
2682
621
                            Some(*idx)
2683
                        }
2684
                        Some(_) => {
2685
0
                            return Err(Error::new(
2686
0
                                "canonical option `realloc` is specified more than once",
2687
0
                                offset,
2688
0
                            ));
2689
                        }
2690
                    }
2691
                }
2692
4.33k
                CanonicalOption::PostReturn(idx) => {
2693
4.33k
                    post_return = match post_return {
2694
4.33k
                        None => Some(*idx),
2695
                        Some(_) => {
2696
0
                            return Err(Error::new(
2697
0
                                "canonical option `post-return` is specified more than once",
2698
0
                                offset,
2699
0
                            ));
2700
                        }
2701
                    }
2702
                }
2703
                CanonicalOption::Async => {
2704
2.21k
                    if is_async {
2705
0
                        return Err(Error::new(
2706
0
                            "canonical option `async` is specified more than once",
2707
0
                            offset,
2708
0
                        ));
2709
                    } else {
2710
2.21k
                        require_feature::cm_async(
2711
2.21k
                            self.features,
2712
                            "canonical option `async` requires the component model async feature",
2713
2.21k
                            offset,
2714
0
                        )?;
2715
2716
2.21k
                        is_async = true;
2717
                    }
2718
                }
2719
1.96k
                CanonicalOption::Callback(idx) => {
2720
1.96k
                    callback = match callback {
2721
1.96k
                        None => Some(*idx),
2722
                        Some(_) => {
2723
0
                            return Err(Error::new(
2724
0
                                "canonical option `callback` is specified more than once",
2725
0
                                offset,
2726
0
                            ));
2727
                        }
2728
                    }
2729
                }
2730
0
                CanonicalOption::CoreType(idx) => {
2731
0
                    core_type = match core_type {
2732
                        None => {
2733
0
                            require_feature::cm_gc(
2734
0
                                self.features,
2735
                                "canonical option `core type` requires the component model gc feature",
2736
0
                                offset,
2737
0
                            )?;
2738
0
                            let ty = match self.core_type_at(*idx, offset)? {
2739
0
                                ComponentCoreTypeId::Sub(ty) => ty,
2740
                                ComponentCoreTypeId::Module(_) => {
2741
0
                                    return Err(Error::new(
2742
0
                                        "canonical option `core type` must reference a core function \
2743
0
                                     type",
2744
0
                                        offset,
2745
0
                                    ));
2746
                                }
2747
                            };
2748
0
                            match &types[ty].composite_type.inner {
2749
0
                                CompositeInnerType::Func(_) => {}
2750
                                CompositeInnerType::Array(_)
2751
                                | CompositeInnerType::Struct(_)
2752
                                | CompositeInnerType::Cont(_) => {
2753
0
                                    return Err(Error::new(
2754
0
                                        "canonical option `core type` must reference a core function \
2755
0
                                     type",
2756
0
                                        offset,
2757
0
                                    ));
2758
                                }
2759
                            }
2760
0
                            Some(ty)
2761
                        }
2762
                        Some(_) => {
2763
0
                            return Err(Error::new(
2764
0
                                "canonical option `core type` is specified more than once",
2765
0
                                offset,
2766
0
                            ));
2767
                        }
2768
                    };
2769
                }
2770
                CanonicalOption::Gc => {
2771
0
                    if gc {
2772
0
                        return Err(Error::new(
2773
0
                            "canonical option `gc` is specified more than once",
2774
0
                            offset,
2775
0
                        ));
2776
0
                    }
2777
0
                    require_feature::cm_gc(
2778
0
                        self.features,
2779
                        "canonical option `gc` requires the `cm-gc` feature",
2780
0
                        offset,
2781
0
                    )?;
2782
0
                    gc = true;
2783
                }
2784
            }
2785
        }
2786
2787
10.5k
        let string_encoding = encoding.unwrap_or_default();
2788
2789
10.5k
        let concurrency = match (is_async, callback, post_return.is_some()) {
2790
            (false, Some(_), _) => {
2791
0
                bail!(offset, "cannot specify callback without async")
2792
            }
2793
            (true, _, true) => {
2794
0
                bail!(offset, "cannot specify post-return function in async")
2795
            }
2796
8.28k
            (false, None, _) => Concurrency::Sync,
2797
2.21k
            (true, callback, false) => Concurrency::Async { callback },
2798
        };
2799
2800
10.5k
        if !gc && core_type.is_some() {
2801
0
            bail!(offset, "cannot specify `core-type` without `gc`")
2802
10.5k
        }
2803
2804
        // Validate `realloc`
2805
10.5k
        if let Some(realloc_idx) = realloc {
2806
621
            let addr_type = match memory {
2807
621
                Some((_, ptr_size)) => ptr_size.core_type(),
2808
                None => {
2809
0
                    return Err(Error::new(
2810
0
                        "canonical option `realloc` requires `memory` to also be specified",
2811
0
                        offset,
2812
0
                    ));
2813
                }
2814
            };
2815
621
            let ty_id = self.core_function_at(realloc_idx, offset)?;
2816
621
            let func_ty = types[ty_id].unwrap_func();
2817
621
            if func_ty.params() != [addr_type, addr_type, addr_type, addr_type]
2818
621
                || func_ty.results() != [addr_type]
2819
            {
2820
0
                return Err(Error::new(
2821
0
                    "canonical option `realloc` uses a core function with an incorrect signature",
2822
0
                    offset,
2823
0
                ));
2824
621
            }
2825
9.88k
        }
2826
2827
10.5k
        Ok(CanonicalOptions {
2828
10.5k
            string_encoding,
2829
10.5k
            memory,
2830
10.5k
            realloc,
2831
10.5k
            post_return,
2832
10.5k
            concurrency,
2833
10.5k
            core_type,
2834
10.5k
            gc,
2835
10.5k
        })
2836
10.5k
    }
2837
2838
108k
    fn check_type_ref(
2839
108k
        &mut self,
2840
108k
        ty: &ComponentTypeRef,
2841
108k
        types: &mut TypeAlloc,
2842
108k
        offset: u64,
2843
108k
    ) -> Result<ComponentEntityType> {
2844
61.5k
        Ok(match ty {
2845
0
            ComponentTypeRef::Module(index) => {
2846
0
                let id = self.core_type_at(*index, offset)?;
2847
0
                match id {
2848
                    ComponentCoreTypeId::Sub(_) => {
2849
0
                        bail!(offset, "core type index {index} is not a module type")
2850
                    }
2851
0
                    ComponentCoreTypeId::Module(id) => ComponentEntityType::Module(id),
2852
                }
2853
            }
2854
29.3k
            ComponentTypeRef::Func(index) => {
2855
29.3k
                let id = self.component_type_at(*index, offset)?;
2856
29.3k
                match id {
2857
29.3k
                    ComponentAnyTypeId::Func(id) => ComponentEntityType::Func(id),
2858
0
                    _ => bail!(offset, "type index {index} is not a function type"),
2859
                }
2860
            }
2861
0
            ComponentTypeRef::Value(ty) => {
2862
0
                self.check_value_support(offset)?;
2863
0
                let ty = match ty {
2864
0
                    crate::ComponentValType::Primitive(ty) => ComponentValType::Primitive(*ty),
2865
0
                    crate::ComponentValType::Type(index) => {
2866
0
                        ComponentValType::Type(self.defined_type_at(*index, offset)?)
2867
                    }
2868
                };
2869
0
                ComponentEntityType::Value(ty)
2870
            }
2871
59.7k
            ComponentTypeRef::Type(TypeBounds::Eq(index)) => {
2872
59.7k
                let referenced = self.component_type_at(*index, offset)?;
2873
59.7k
                let created = types.with_unique(referenced);
2874
59.7k
                ComponentEntityType::Type {
2875
59.7k
                    referenced,
2876
59.7k
                    created,
2877
59.7k
                }
2878
            }
2879
            ComponentTypeRef::Type(TypeBounds::SubResource) => {
2880
1.74k
                let id = types.alloc_resource_id();
2881
1.74k
                ComponentEntityType::Type {
2882
1.74k
                    referenced: id.into(),
2883
1.74k
                    created: id.into(),
2884
1.74k
                }
2885
            }
2886
14.7k
            ComponentTypeRef::Instance(index) => {
2887
14.7k
                let id = self.component_type_at(*index, offset)?;
2888
14.7k
                match id {
2889
14.7k
                    ComponentAnyTypeId::Instance(id) => ComponentEntityType::Instance(id),
2890
0
                    _ => bail!(offset, "type index {index} is not an instance type"),
2891
                }
2892
            }
2893
2.56k
            ComponentTypeRef::Component(index) => {
2894
2.56k
                let id = self.component_type_at(*index, offset)?;
2895
2.56k
                match id {
2896
2.56k
                    ComponentAnyTypeId::Component(id) => ComponentEntityType::Component(id),
2897
0
                    _ => bail!(offset, "type index {index} is not a component type"),
2898
                }
2899
            }
2900
        })
2901
108k
    }
2902
2903
33.6k
    pub fn export_to_entity_type(
2904
33.6k
        &mut self,
2905
33.6k
        export: &crate::ComponentExport,
2906
33.6k
        types: &mut TypeAlloc,
2907
33.6k
        offset: u64,
2908
33.6k
    ) -> Result<ComponentEntityType> {
2909
33.6k
        let actual = match export.kind {
2910
            ComponentExternalKind::Module => {
2911
0
                ComponentEntityType::Module(self.module_at(export.index, offset)?)
2912
            }
2913
            ComponentExternalKind::Func => {
2914
6.30k
                ComponentEntityType::Func(self.function_at(export.index, offset)?)
2915
            }
2916
            ComponentExternalKind::Value => {
2917
0
                self.check_value_support(offset)?;
2918
0
                ComponentEntityType::Value(*self.value_at(export.index, offset)?)
2919
            }
2920
            ComponentExternalKind::Type => {
2921
23.9k
                let referenced = self.component_type_at(export.index, offset)?;
2922
23.9k
                let created = types.with_unique(referenced);
2923
23.9k
                ComponentEntityType::Type {
2924
23.9k
                    referenced,
2925
23.9k
                    created,
2926
23.9k
                }
2927
            }
2928
            ComponentExternalKind::Instance => {
2929
3.41k
                ComponentEntityType::Instance(self.instance_at(export.index, offset)?)
2930
            }
2931
            ComponentExternalKind::Component => {
2932
0
                ComponentEntityType::Component(self.component_at(export.index, offset)?)
2933
            }
2934
        };
2935
2936
33.6k
        let ascribed = match &export.ty {
2937
6.09k
            Some(ty) => self.check_type_ref(ty, types, offset)?,
2938
27.5k
            None => return Ok(actual),
2939
        };
2940
2941
6.09k
        SubtypeCx::new(types, types)
2942
6.09k
            .component_entity_type(&actual, &ascribed, offset)
2943
6.09k
            .with_context(|| "ascribed type of export is not compatible with item's type")?;
2944
2945
6.09k
        Ok(ascribed)
2946
33.6k
    }
2947
2948
0
    fn create_module_type(
2949
0
        components: &[Self],
2950
0
        decls: Vec<crate::ModuleTypeDeclaration>,
2951
0
        types: &mut TypeAlloc,
2952
0
        offset: u64,
2953
0
    ) -> Result<ModuleType> {
2954
0
        let mut state = Module::new(components[0].features);
2955
2956
0
        for decl in decls {
2957
0
            match decl {
2958
0
                crate::ModuleTypeDeclaration::Type(rec) => {
2959
0
                    state.add_types(rec, types, offset, true)?;
2960
                }
2961
0
                crate::ModuleTypeDeclaration::Export { name, mut ty } => {
2962
0
                    let ty = state.check_type_ref(&mut ty, types, offset)?;
2963
0
                    state.add_export(name, ty, offset, true, types)?;
2964
                }
2965
0
                crate::ModuleTypeDeclaration::OuterAlias { kind, count, index } => {
2966
0
                    match kind {
2967
                        crate::OuterAliasKind::Type => {
2968
0
                            let ty = if count == 0 {
2969
                                // Local alias, check the local module state
2970
0
                                ComponentCoreTypeId::Sub(state.type_id_at(index, offset)?)
2971
                            } else {
2972
                                // Otherwise, check the enclosing component state
2973
0
                                let component =
2974
0
                                    Self::check_alias_count(components, count - 1, offset)?;
2975
0
                                component.core_type_at(index, offset)?
2976
                            };
2977
2978
0
                            check_max(state.types.len(), 1, MAX_WASM_TYPES, "types", offset)?;
2979
2980
0
                            match ty {
2981
0
                                ComponentCoreTypeId::Sub(ty) => state.types.push(ty),
2982
                                // TODO https://github.com/WebAssembly/component-model/issues/265
2983
0
                                ComponentCoreTypeId::Module(_) => bail!(
2984
0
                                    offset,
2985
                                    "not implemented: aliasing core module types into a core \
2986
                                     module's types index space"
2987
                                ),
2988
                            }
2989
                        }
2990
                    }
2991
                }
2992
0
                crate::ModuleTypeDeclaration::Import(import) => {
2993
0
                    state.add_import(import, types, offset)?;
2994
                }
2995
            }
2996
        }
2997
2998
0
        let imports = state.imports_for_module_type(offset)?;
2999
3000
0
        Ok(ModuleType {
3001
0
            info: TypeInfo::core(state.type_size),
3002
0
            imports,
3003
0
            exports: state.exports,
3004
0
        })
3005
0
    }
3006
3007
10.4k
    fn create_component_type(
3008
10.4k
        components: &mut Vec<Self>,
3009
10.4k
        decls: Vec<crate::ComponentTypeDeclaration>,
3010
10.4k
        types: &mut TypeAlloc,
3011
10.4k
        offset: u64,
3012
10.4k
    ) -> Result<ComponentType> {
3013
10.4k
        let features = components[0].features;
3014
10.4k
        components.push(ComponentState::new(ComponentKind::ComponentType, features));
3015
3016
53.8k
        for decl in decls {
3017
53.8k
            match decl {
3018
0
                crate::ComponentTypeDeclaration::CoreType(ty) => {
3019
0
                    Self::add_core_type(components, ty, types, offset, true)?;
3020
                }
3021
27.9k
                crate::ComponentTypeDeclaration::Type(ty) => {
3022
27.9k
                    Self::add_type(components, ty, types, offset, true)?;
3023
                }
3024
12.7k
                crate::ComponentTypeDeclaration::Export { name, ty } => {
3025
12.7k
                    let current = components.last_mut().unwrap();
3026
12.7k
                    let ty = current.check_type_ref(&ty, types, offset)?;
3027
12.7k
                    current.add_export(name, ty, types, offset, true)?;
3028
                }
3029
7.98k
                crate::ComponentTypeDeclaration::Import(import) => {
3030
7.98k
                    components
3031
7.98k
                        .last_mut()
3032
7.98k
                        .unwrap()
3033
7.98k
                        .add_import(import, types, offset)?;
3034
                }
3035
5.18k
                crate::ComponentTypeDeclaration::Alias(alias) => {
3036
5.18k
                    Self::add_alias(components, alias, types, offset)?;
3037
                }
3038
            };
3039
        }
3040
3041
10.3k
        components.pop().unwrap().finish(types, offset)
3042
10.4k
    }
3043
3044
14.8k
    fn create_instance_type(
3045
14.8k
        components: &mut Vec<Self>,
3046
14.8k
        decls: Vec<crate::InstanceTypeDeclaration>,
3047
14.8k
        types: &mut TypeAlloc,
3048
14.8k
        offset: u64,
3049
14.8k
    ) -> Result<ComponentInstanceType> {
3050
14.8k
        let features = components[0].features;
3051
14.8k
        components.push(ComponentState::new(ComponentKind::InstanceType, features));
3052
3053
167k
        for decl in decls {
3054
167k
            match decl {
3055
0
                crate::InstanceTypeDeclaration::CoreType(ty) => {
3056
0
                    Self::add_core_type(components, ty, types, offset, true)?;
3057
                }
3058
88.5k
                crate::InstanceTypeDeclaration::Type(ty) => {
3059
88.5k
                    Self::add_type(components, ty, types, offset, true)?;
3060
                }
3061
71.8k
                crate::InstanceTypeDeclaration::Export { name, ty } => {
3062
71.8k
                    let current = components.last_mut().unwrap();
3063
71.8k
                    let ty = current.check_type_ref(&ty, types, offset)?;
3064
71.8k
                    current.add_export(name, ty, types, offset, true)?;
3065
                }
3066
7.01k
                crate::InstanceTypeDeclaration::Alias(alias) => {
3067
7.01k
                    Self::add_alias(components, alias, types, offset)?;
3068
                }
3069
            };
3070
        }
3071
3072
14.7k
        let mut state = components.pop().unwrap();
3073
3074
14.7k
        assert!(state.imported_resources.is_empty());
3075
3076
        Ok(ComponentInstanceType {
3077
14.7k
            info: state.type_info,
3078
3079
            // The defined resources for this instance type are those listed on
3080
            // the component state. The path to each defined resource is
3081
            // guaranteed to live within the `explicit_resources` map since,
3082
            // when in the type context, the introduction of any defined
3083
            // resource must have been done with `(export "x" (type (sub
3084
            // resource)))` which, in a sense, "fuses" the introduction of the
3085
            // variable with the export. This means that all defined resources,
3086
            // if any, should be guaranteed to have an `explicit_resources` path
3087
            // listed.
3088
14.7k
            defined_resources: mem::take(&mut state.defined_resources)
3089
14.7k
                .into_iter()
3090
14.7k
                .map(|(id, rep)| {
3091
1.20k
                    assert!(rep.is_none());
3092
1.20k
                    id
3093
1.20k
                })
3094
14.7k
                .collect(),
3095
3096
            // The map of what resources are explicitly exported and where
3097
            // they're exported is plumbed through as-is.
3098
14.7k
            explicit_resources: mem::take(&mut state.explicit_resources),
3099
3100
14.7k
            exports: mem::take(&mut state.exports),
3101
        })
3102
14.8k
    }
3103
3104
20.2k
    fn create_function_type(
3105
20.2k
        &self,
3106
20.2k
        ty: crate::ComponentFuncType,
3107
20.2k
        types: &TypeList,
3108
20.2k
        offset: u64,
3109
20.2k
    ) -> Result<ComponentFuncType> {
3110
20.2k
        let mut info = TypeInfo::new();
3111
3112
20.2k
        if ty.async_ {
3113
16.6k
            require_feature::cm_async(
3114
16.6k
                self.features,
3115
                "async component functions require the component model async feature",
3116
16.6k
                offset,
3117
0
            )?;
3118
3.63k
        }
3119
3120
20.2k
        let mut set = Set::default();
3121
20.2k
        set.reserve(core::cmp::max(
3122
20.2k
            ty.params.len(),
3123
20.2k
            usize::from(ty.result.is_some()),
3124
        ));
3125
3126
20.2k
        let params = ty
3127
20.2k
            .params
3128
20.2k
            .iter()
3129
47.2k
            .map(|(name, ty)| {
3130
47.2k
                let name = to_kebab_string(name, "function parameter", offset)?;
3131
47.2k
                if !set.insert(name.clone()) {
3132
0
                    bail!(
3133
0
                        offset,
3134
                        "function parameter name `{name}` conflicts with previous parameter name `{prev}`",
3135
0
                        prev = set.get(&name).unwrap(),
3136
                    );
3137
47.2k
                }
3138
3139
47.2k
                let ty = self.create_component_val_type(*ty, offset)?;
3140
47.2k
                info.combine(ty.info(types), offset)?;
3141
47.2k
                Ok((name, ty))
3142
47.2k
            })
3143
20.2k
            .collect::<Result<_>>()?;
3144
3145
20.2k
        set.clear();
3146
3147
20.2k
        let result = ty
3148
20.2k
            .result
3149
20.2k
            .map(|ty| {
3150
18.4k
                let ty = self.create_component_val_type(ty, offset)?;
3151
18.4k
                if ty.abi(types).contains_borrow() {
3152
0
                    bail!(offset, "function result cannot contain a `borrow` type");
3153
18.4k
                }
3154
18.4k
                info.combine(ty.info(types), offset)?;
3155
18.4k
                Ok(ty)
3156
18.4k
            })
3157
20.2k
            .transpose()?;
3158
3159
20.2k
        Ok(ComponentFuncType {
3160
20.2k
            async_: ty.async_,
3161
20.2k
            info,
3162
20.2k
            params,
3163
20.2k
            result,
3164
20.2k
        })
3165
20.2k
    }
3166
3167
4.27k
    fn instantiate_core_module(
3168
4.27k
        &self,
3169
4.27k
        module_index: u32,
3170
4.27k
        module_args: Vec<crate::InstantiationArg>,
3171
4.27k
        types: &mut TypeAlloc,
3172
4.27k
        offset: u64,
3173
4.27k
    ) -> Result<ComponentCoreInstanceTypeId> {
3174
5.30k
        fn insert_arg<'a>(
3175
5.30k
            name: &'a str,
3176
5.30k
            arg: &'a InstanceType,
3177
5.30k
            args: &mut IndexMap<&'a str, &'a InstanceType>,
3178
5.30k
            offset: u64,
3179
5.30k
        ) -> Result<()> {
3180
5.30k
            if args.insert(name, arg).is_some() {
3181
0
                bail!(
3182
0
                    offset,
3183
                    "duplicate module instantiation argument named `{name}`"
3184
                );
3185
5.30k
            }
3186
3187
5.30k
            Ok(())
3188
5.30k
        }
3189
3190
4.27k
        let module_type_id = self.module_at(module_index, offset)?;
3191
4.27k
        let mut args = IndexMap::default();
3192
3193
        // Populate the arguments
3194
5.30k
        for module_arg in module_args {
3195
5.30k
            match module_arg.kind {
3196
                InstantiationArgKind::Instance => {
3197
5.30k
                    let instance_type = &types[self.core_instance_at(module_arg.index, offset)?];
3198
5.30k
                    insert_arg(module_arg.name, instance_type, &mut args, offset)?;
3199
                }
3200
            }
3201
        }
3202
3203
        // Validate the arguments
3204
4.27k
        let module_type = &types[module_type_id];
3205
4.27k
        let cx = SubtypeCx::new(types, types);
3206
19.2k
        for ((module, name), expected) in module_type.imports.iter() {
3207
19.2k
            let instance = args.get(module.as_str()).ok_or_else(|| {
3208
0
                format_err!(
3209
0
                    offset,
3210
                    "missing module instantiation argument named `{module}`"
3211
                )
3212
0
            })?;
3213
3214
19.2k
            let arg = instance
3215
19.2k
                .internal_exports(types)
3216
19.2k
                .get(name.as_str())
3217
19.2k
                .ok_or_else(|| {
3218
0
                    format_err!(
3219
0
                        offset,
3220
                        "module instantiation argument `{module}` does not \
3221
                         export an item named `{name}`",
3222
                    )
3223
0
                })?;
3224
3225
19.2k
            cx.entity_type(arg, expected, offset).with_context(|| {
3226
0
                format!(
3227
                    "type mismatch for export `{name}` of module \
3228
                     instantiation argument `{module}`"
3229
                )
3230
0
            })?;
3231
        }
3232
3233
4.27k
        let mut info = TypeInfo::new();
3234
21.3k
        for (_, ty) in module_type.exports.iter() {
3235
21.3k
            info.combine(ty.info(types), offset)?;
3236
        }
3237
3238
4.27k
        Ok(types.push_ty(InstanceType {
3239
4.27k
            info,
3240
4.27k
            kind: CoreInstanceTypeKind::Instantiated(module_type_id),
3241
4.27k
        }))
3242
4.27k
    }
3243
3244
3.41k
    fn instantiate_component(
3245
3.41k
        &mut self,
3246
3.41k
        component_index: u32,
3247
3.41k
        component_args: Vec<crate::ComponentInstantiationArg>,
3248
3.41k
        types: &mut TypeAlloc,
3249
3.41k
        offset: u64,
3250
3.41k
    ) -> Result<ComponentInstanceTypeId> {
3251
3.41k
        let component_type_id = self.component_at(component_index, offset)?;
3252
3.41k
        let mut args = IndexMap::default();
3253
3254
        // Populate the arguments
3255
6.67k
        for component_arg in component_args {
3256
6.67k
            let ty = match component_arg.kind {
3257
                ComponentExternalKind::Module => {
3258
0
                    ComponentEntityType::Module(self.module_at(component_arg.index, offset)?)
3259
                }
3260
                ComponentExternalKind::Component => {
3261
0
                    ComponentEntityType::Component(self.component_at(component_arg.index, offset)?)
3262
                }
3263
                ComponentExternalKind::Instance => {
3264
0
                    ComponentEntityType::Instance(self.instance_at(component_arg.index, offset)?)
3265
                }
3266
                ComponentExternalKind::Func => {
3267
6.09k
                    ComponentEntityType::Func(self.function_at(component_arg.index, offset)?)
3268
                }
3269
                ComponentExternalKind::Value => {
3270
0
                    self.check_value_support(offset)?;
3271
0
                    ComponentEntityType::Value(*self.value_at(component_arg.index, offset)?)
3272
                }
3273
                ComponentExternalKind::Type => {
3274
579
                    let ty = self.component_type_at(component_arg.index, offset)?;
3275
579
                    ComponentEntityType::Type {
3276
579
                        referenced: ty,
3277
579
                        created: ty,
3278
579
                    }
3279
                }
3280
            };
3281
6.67k
            match args.entry(component_arg.name.to_string()) {
3282
0
                Entry::Occupied(e) => {
3283
0
                    bail!(
3284
0
                        offset,
3285
                        "instantiation argument `{name}` conflicts with previous argument `{prev}`",
3286
0
                        prev = e.key(),
3287
                        name = component_arg.name
3288
                    );
3289
                }
3290
6.67k
                Entry::Vacant(e) => {
3291
6.67k
                    e.insert(ty);
3292
6.67k
                }
3293
            }
3294
        }
3295
3296
        // Here comes the fun part of the component model, we're instantiating
3297
        // the component with type `component_type_id` with the `args`
3298
        // specified. Easy enough!
3299
        //
3300
        // This operation, however, is one of the lynchpins of safety in the
3301
        // component model. Additionally what this ends up implementing ranges
3302
        // from "well just check the types are equal" to "let's have a
3303
        // full-blown ML-style module type system in the component model". There
3304
        // are primarily two major tricky pieces to the component model which
3305
        // make this operation, instantiating components, hard:
3306
        //
3307
        // 1. Components can import and exports other components. This means
3308
        //    that arguments to instantiation are along the lines of functions
3309
        //    being passed to functions or similar. Effectively this means that
3310
        //    the term "variance" comes into play with either contravariance
3311
        //    or covariance depending on where you are in typechecking. This is
3312
        //    one of the main rationales, however, that this check below is a
3313
        //    check for subtyping as opposed to exact type equivalence. For
3314
        //    example an instance that exports something is a subtype of an
3315
        //    instance that exports nothing. Components get a bit trick since
3316
        //    they both have imports and exports. My way of thinking about it
3317
        //    is "who's asking for what". If you're asking for imports then
3318
        //    I need to at least supply those imports, but I can possibly
3319
        //    supply more. If you're asking for a thing which you'll give a set
3320
        //    of imports, then I can give you something which takes less imports
3321
        //    because what you give still suffices. (things like that). The
3322
        //    real complication with components, however, comes with...
3323
        //
3324
        // 2. Resources. Resources in the component model are akin to "abstract
3325
        //    types". They're not abstract in the sense that they have no
3326
        //    representation, they're always backed by a 32-bit integer right
3327
        //    now. Instead they're abstract in the sense that some components
3328
        //    aren't allowed to understand the representation of a resource.
3329
        //    For example if you import a resource you can't get the underlying
3330
        //    internals of it. Furthermore the resource is strictly tracked
3331
        //    within the component with `own` and `borrow` runtime semantics.
3332
        //    The hardest part about resources, though, is handling them as
3333
        //    part of instantiation and subtyping.
3334
        //
3335
        //    For example one major aspect of resources is that if a component
3336
        //    exports a resource then each instantiation of the component
3337
        //    produces a fresh resource type. This means that the type recorded
3338
        //    for the instantiation here can't simply be "I instantiated
3339
        //    component X" since in such a situation the type of all
3340
        //    instantiations would be the same, which they aren't.
3341
        //
3342
        //    This sort of subtlety comes up quite frequently for resources.
3343
        //    This file contains references to `imported_resources` and
3344
        //    `defined_resources` for example which refer to the formal
3345
        //    nature of components and their abstract variables. Specifically
3346
        //    for instantiation though we're eventually faced with the problem
3347
        //    of subtype checks where resource subtyping is defined as "does
3348
        //    your id equal mine". Naively implemented that means anything with
3349
        //    resources isn't subtypes of anything else since resource ids are
3350
        //    unique between components. Instead what actually needs to happen
3351
        //    is types need to be substituted.
3352
        //
3353
        // Much of the complexity here is not actually apparent here in this
3354
        // literal one function. Instead it's spread out across validation
3355
        // in this file and type-checking in the `types.rs` module. Note that
3356
        // the "spread out" nature isn't because we're bad maintainers
3357
        // (hopefully), but rather it's quite infectious how many parts need
3358
        // to handle resources and account for defined/imported variables.
3359
        //
3360
        // For example only one subtyping method is called here where `args` is
3361
        // passed in. This method is quite recursive in its nature though and
3362
        // will internally touch all the fields that this file maintains to
3363
        // end up putting into various bits and pieces of type information.
3364
        //
3365
        // Unfortunately there's probably not really a succinct way to read
3366
        // this method and understand everything. If you've written ML module
3367
        // type systems this will probably look quite familiar, but otherwise
3368
        // the whole system is not really easily approachable at this time. It's
3369
        // hoped in the future that there's a formalism to refer to which will
3370
        // make things more clear as the code would be able to reference this
3371
        // hypothetical formalism. Until that's the case, though, these
3372
        // comments are hopefully enough when augmented with communication with
3373
        // the authors.
3374
3375
3.41k
        let component_type = &types[component_type_id];
3376
3.41k
        let mut exports = component_type.exports.clone();
3377
3.41k
        let mut info = TypeInfo::new();
3378
22.1k
        for (_, ty) in component_type.exports.iter() {
3379
22.1k
            info.combine(ty.ty.info(types), offset)?;
3380
        }
3381
3382
        // Perform the subtype check that `args` matches the imports of
3383
        // `component_type_id`. The result of this subtype check is the
3384
        // production of a mapping of resource types from the imports to the
3385
        // arguments provided. This is a substitution map which is then used
3386
        // below to perform a substitution into the exports of the instance
3387
        // since the types of the exports are now in terms of whatever was
3388
        // supplied as imports.
3389
3.41k
        let mut mapping = SubtypeCx::new(types, types).open_instance_type(
3390
3.41k
            &args,
3391
3.41k
            component_type_id,
3392
3.41k
            ExternKind::Import,
3393
3.41k
            offset,
3394
0
        )?;
3395
3396
        // Part of the instantiation of a component is that all of its
3397
        // defined resources become "fresh" on each instantiation. This
3398
        // means that each instantiation of a component gets brand new type
3399
        // variables representing its defined resources, modeling that each
3400
        // instantiation produces distinct types. The freshening is performed
3401
        // here by allocating new ids and inserting them into `mapping`.
3402
        //
3403
        // Note that technically the `mapping` from subtyping should be applied
3404
        // first and then the mapping for freshening should be applied
3405
        // afterwards. The keys of the map from subtyping are the imported
3406
        // resources from this component which are disjoint from its defined
3407
        // resources. That means it should be possible to place everything
3408
        // into one large map which maps from:
3409
        //
3410
        // * the component's imported resources go to whatever was explicitly
3411
        //   supplied in the import map
3412
        // * the component's defined resources go to fresh new resources
3413
        //
3414
        // These two remapping operations can then get folded into one by
3415
        // placing everything in the same `mapping` and using that for a remap
3416
        // only once.
3417
3.41k
        let fresh_defined_resources = (0..component_type.defined_resources.len())
3418
3.41k
            .map(|_| types.alloc_resource_id().resource())
3419
3.41k
            .collect::<IndexSet<_>>();
3420
3.41k
        let component_type = &types[component_type_id];
3421
3.41k
        for ((old, _path), new) in component_type
3422
3.41k
            .defined_resources
3423
3.41k
            .iter()
3424
3.41k
            .zip(&fresh_defined_resources)
3425
        {
3426
0
            let prev = mapping.resources.insert(*old, *new);
3427
0
            assert!(prev.is_none());
3428
        }
3429
3430
        // Perform the remapping operation over all the exports that will be
3431
        // listed for the final instance type. Note that this is performed
3432
        // both for all the export types in addition to the explicitly exported
3433
        // resources list.
3434
        //
3435
        // Note that this is a crucial step of the instantiation process which
3436
        // is intentionally transforming the type of a component based on the
3437
        // variables provided by imports and additionally ensuring that all
3438
        // references to the component's defined resources are rebound to the
3439
        // fresh ones introduced just above.
3440
22.1k
        for entity in exports.values_mut() {
3441
22.1k
            types.remap_component_entity(&mut entity.ty, &mut mapping);
3442
22.1k
        }
3443
3.41k
        let component_type = &types[component_type_id];
3444
3.41k
        let explicit_resources = component_type
3445
3.41k
            .explicit_resources
3446
3.41k
            .iter()
3447
3.41k
            .map(|(id, path)| {
3448
321
                (
3449
321
                    mapping.resources.get(id).copied().unwrap_or(*id),
3450
321
                    path.clone(),
3451
321
                )
3452
321
            })
3453
3.41k
            .collect::<IndexMap<_, _>>();
3454
3455
        // Technically in the last formalism that was consulted in writing this
3456
        // implementation there are two further steps that are part of the
3457
        // instantiation process:
3458
        //
3459
        // 1. The set of defined resources from the instance created, which are
3460
        //    added to the outer component, is the subset of the instance's
3461
        //    original defined resources and the free variables of the exports.
3462
        //
3463
        // 2. Each element of this subset is required to be "explicit in" the
3464
        //    instance, or otherwise explicitly exported somewhere within the
3465
        //    instance.
3466
        //
3467
        // With the syntactic structure of the component model, however, neither
3468
        // of these conditions should be necessary. The main reason for this is
3469
        // that this function is specifically dealing with instantiation of
3470
        // components which should already have these properties validated
3471
        // about them. Subsequently we shouldn't have to re-check them.
3472
        //
3473
        // In debug mode, however, do a sanity check.
3474
3.41k
        if cfg!(debug_assertions) {
3475
0
            let mut free = IndexSet::default();
3476
0
            for ty in exports.values() {
3477
0
                types.free_variables_component_entity(&ty.ty, &mut free);
3478
0
            }
3479
0
            assert!(fresh_defined_resources.is_subset(&free));
3480
0
            for resource in fresh_defined_resources.iter() {
3481
0
                assert!(explicit_resources.contains_key(resource));
3482
            }
3483
3.41k
        }
3484
3485
        // And as the final step of the instantiation process all of the
3486
        // new defined resources from this component instantiation are moved
3487
        // onto `self`. Note that concrete instances never have defined
3488
        // resources (see more comments in `instantiate_exports`) so the
3489
        // `defined_resources` listing in the final type is always empty. This
3490
        // represents how by having a concrete instance the definitions
3491
        // referred to in that instance are now problems for the outer
3492
        // component rather than the inner instance since the instance is bound
3493
        // to the component.
3494
        //
3495
        // All defined resources here have no known representation, so they're
3496
        // all listed with `None`. Also note that none of the resources were
3497
        // exported yet so `self.explicit_resources` is not updated yet. If
3498
        // this instance is exported, however, it'll consult the type's
3499
        // `explicit_resources` array and use that appropriately.
3500
3.41k
        for resource in fresh_defined_resources {
3501
0
            self.defined_resources.insert(resource, None);
3502
0
        }
3503
3504
3.41k
        Ok(types.push_ty(ComponentInstanceType {
3505
3.41k
            info,
3506
3.41k
            defined_resources: Default::default(),
3507
3.41k
            explicit_resources,
3508
3.41k
            exports,
3509
3.41k
        }))
3510
3.41k
    }
3511
3512
0
    fn instantiate_component_exports(
3513
0
        &mut self,
3514
0
        exports: Vec<crate::ComponentExport>,
3515
0
        types: &mut TypeAlloc,
3516
0
        offset: u64,
3517
0
    ) -> Result<ComponentInstanceTypeId> {
3518
0
        let mut info = TypeInfo::new();
3519
0
        let mut inst_exports = IndexMap::default();
3520
0
        let mut explicit_resources = IndexMap::default();
3521
0
        let mut export_names = IndexSet::default();
3522
3523
        // NB: It's intentional that this context is empty since no indices are
3524
        // introduced in the bag-of-exports construct which means there's no
3525
        // way syntactically to register something inside of this.
3526
0
        let names = ComponentNameContext::default();
3527
3528
0
        for export in exports {
3529
0
            assert!(export.ty.is_none());
3530
0
            let ty = match export.kind {
3531
                ComponentExternalKind::Module => {
3532
0
                    ComponentEntityType::Module(self.module_at(export.index, offset)?)
3533
                }
3534
                ComponentExternalKind::Component => {
3535
0
                    ComponentEntityType::Component(self.component_at(export.index, offset)?)
3536
                }
3537
                ComponentExternalKind::Instance => {
3538
0
                    let ty = self.instance_at(export.index, offset)?;
3539
3540
                    // When an instance is exported from an instance then
3541
                    // all explicitly exported resources on the sub-instance are
3542
                    // now also listed as exported resources on the outer
3543
                    // instance, just with one more element in their path.
3544
0
                    explicit_resources.extend(types[ty].explicit_resources.iter().map(
3545
0
                        |(id, path)| {
3546
0
                            let mut new_path = vec![inst_exports.len()];
3547
0
                            new_path.extend(path);
3548
0
                            (*id, new_path)
3549
0
                        },
3550
                    ));
3551
0
                    ComponentEntityType::Instance(ty)
3552
                }
3553
                ComponentExternalKind::Func => {
3554
0
                    ComponentEntityType::Func(self.function_at(export.index, offset)?)
3555
                }
3556
                ComponentExternalKind::Value => {
3557
0
                    self.check_value_support(offset)?;
3558
0
                    ComponentEntityType::Value(*self.value_at(export.index, offset)?)
3559
                }
3560
                ComponentExternalKind::Type => {
3561
0
                    let ty = self.component_type_at(export.index, offset)?;
3562
                    // If this is an export of a resource type be sure to
3563
                    // record that in the explicit list with the appropriate
3564
                    // path because if this instance ends up getting used
3565
                    // it'll count towards the "explicit in" check.
3566
0
                    if let ComponentAnyTypeId::Resource(id) = ty {
3567
0
                        explicit_resources.insert(id.resource(), vec![inst_exports.len()]);
3568
0
                    }
3569
0
                    ComponentEntityType::Type {
3570
0
                        referenced: ty,
3571
0
                        // The created type index here isn't used anywhere
3572
0
                        // in index spaces because a "bag of exports"
3573
0
                        // doesn't build up its own index spaces. Just fill
3574
0
                        // in the same index here in this case as what's
3575
0
                        // referenced.
3576
0
                        created: ty,
3577
0
                    }
3578
                }
3579
            };
3580
3581
0
            names.validate_extern(
3582
0
                &export.name,
3583
0
                ExternKind::Export,
3584
0
                &ty,
3585
0
                types,
3586
0
                offset,
3587
0
                &mut export_names,
3588
0
                &mut inst_exports,
3589
0
                &mut info,
3590
0
                &self.features,
3591
0
            )?;
3592
        }
3593
3594
0
        Ok(types.push_ty(ComponentInstanceType {
3595
0
            info,
3596
0
            explicit_resources,
3597
0
            exports: inst_exports,
3598
0
3599
0
            // NB: the list of defined resources for this instance itself
3600
0
            // is always empty. Even if this instance exports resources,
3601
0
            // it's empty.
3602
0
            //
3603
0
            // The reason for this is a bit subtle. The general idea, though, is
3604
0
            // that the defined resources list here is only used for instance
3605
0
            // types that are sort of "floating around" and haven't actually
3606
0
            // been attached to something yet. For example when an instance type
3607
0
            // is simply declared it can have defined resources introduced
3608
0
            // through `(export "name" (type (sub resource)))`. These
3609
0
            // definitions, however, are local to the instance itself and aren't
3610
0
            // defined elsewhere.
3611
0
            //
3612
0
            // Here, though, no new definitions were introduced. The instance
3613
0
            // created here is a "bag of exports" which could only refer to
3614
0
            // preexisting items. This means that inherently no new resources
3615
0
            // were created so there's nothing to put in this list. Any
3616
0
            // resources referenced by the instance must be bound by the outer
3617
0
            // component context or further above.
3618
0
            //
3619
0
            // Furthermore, however, actual instances of instances, which this
3620
0
            // is, aren't allowed to have defined resources. Instead the
3621
0
            // resources would have to be injected into the outer component
3622
0
            // enclosing the instance. That means that even if bag-of-exports
3623
0
            // could declare a new resource then the resource would be moved
3624
0
            // from here to `self.defined_resources`. This doesn't exist at this
3625
0
            // time, though, so this still remains empty and
3626
0
            // `self.defined_resources` remains unperturbed.
3627
0
            defined_resources: Default::default(),
3628
0
        }))
3629
0
    }
3630
3631
2.80k
    fn instantiate_core_exports(
3632
2.80k
        &mut self,
3633
2.80k
        exports: Vec<crate::Export>,
3634
2.80k
        types: &mut TypeAlloc,
3635
2.80k
        offset: u64,
3636
2.80k
    ) -> Result<ComponentCoreInstanceTypeId> {
3637
16.2k
        fn insert_export(
3638
16.2k
            types: &TypeList,
3639
16.2k
            name: &str,
3640
16.2k
            export: EntityType,
3641
16.2k
            exports: &mut IndexMap<String, EntityType>,
3642
16.2k
            info: &mut TypeInfo,
3643
16.2k
            offset: u64,
3644
16.2k
        ) -> Result<()> {
3645
16.2k
            info.combine(export.info(types), offset)?;
3646
3647
16.2k
            if exports.insert(name.to_string(), export).is_some() {
3648
0
                bail!(
3649
0
                    offset,
3650
                    "duplicate instantiation export name `{name}` already defined",
3651
                )
3652
16.2k
            }
3653
3654
16.2k
            Ok(())
3655
16.2k
        }
3656
3657
2.80k
        let mut info = TypeInfo::new();
3658
2.80k
        let mut inst_exports = IndexMap::default();
3659
16.2k
        for export in exports {
3660
16.2k
            match export.kind {
3661
                ExternalKind::Func | ExternalKind::FuncExact => {
3662
16.2k
                    insert_export(
3663
16.2k
                        types,
3664
16.2k
                        export.name,
3665
16.2k
                        EntityType::Func(self.core_function_at(export.index, offset)?),
3666
16.2k
                        &mut inst_exports,
3667
16.2k
                        &mut info,
3668
16.2k
                        offset,
3669
0
                    )?;
3670
                }
3671
0
                ExternalKind::Table => insert_export(
3672
0
                    types,
3673
0
                    export.name,
3674
0
                    EntityType::Table(*self.table_at(export.index, offset)?),
3675
0
                    &mut inst_exports,
3676
0
                    &mut info,
3677
0
                    offset,
3678
0
                )?,
3679
0
                ExternalKind::Memory => insert_export(
3680
0
                    types,
3681
0
                    export.name,
3682
0
                    EntityType::Memory(*self.memory_at(export.index, offset)?),
3683
0
                    &mut inst_exports,
3684
0
                    &mut info,
3685
0
                    offset,
3686
0
                )?,
3687
                ExternalKind::Global => {
3688
0
                    insert_export(
3689
0
                        types,
3690
0
                        export.name,
3691
0
                        EntityType::Global(*self.global_at(export.index, offset)?),
3692
0
                        &mut inst_exports,
3693
0
                        &mut info,
3694
0
                        offset,
3695
0
                    )?;
3696
                }
3697
                ExternalKind::Tag => {
3698
0
                    require_feature::exceptions(
3699
0
                        self.features,
3700
                        "exceptions proposal not enabled",
3701
0
                        offset,
3702
0
                    )?;
3703
0
                    insert_export(
3704
0
                        types,
3705
0
                        export.name,
3706
0
                        EntityType::Tag(self.tag_at(export.index, offset)?),
3707
0
                        &mut inst_exports,
3708
0
                        &mut info,
3709
0
                        offset,
3710
0
                    )?
3711
                }
3712
            }
3713
        }
3714
3715
2.80k
        Ok(types.push_ty(InstanceType {
3716
2.80k
            info,
3717
2.80k
            kind: CoreInstanceTypeKind::Exports(inst_exports),
3718
2.80k
        }))
3719
2.80k
    }
3720
3721
16.7k
    fn alias_core_instance_export(
3722
16.7k
        &mut self,
3723
16.7k
        instance_index: u32,
3724
16.7k
        kind: ExternalKind,
3725
16.7k
        name: &str,
3726
16.7k
        types: &TypeList,
3727
16.7k
        offset: u64,
3728
16.7k
    ) -> Result<()> {
3729
        macro_rules! push_module_export {
3730
            ($expected:path, $collection:ident, $ty:literal) => {{
3731
                match self.core_instance_export(instance_index, name, types, offset)? {
3732
                    $expected(ty) => {
3733
                        self.$collection.push(*ty);
3734
                    }
3735
                    _ => {
3736
                        bail!(
3737
                            offset,
3738
                            "export `{name}` for core instance {instance_index} is not a {}",
3739
                            $ty
3740
                        )
3741
                    }
3742
                }
3743
            }};
3744
        }
3745
3746
16.7k
        match kind {
3747
            ExternalKind::Func | ExternalKind::FuncExact => {
3748
14.9k
                check_max(
3749
14.9k
                    self.function_count(),
3750
                    1,
3751
                    MAX_WASM_FUNCTIONS,
3752
14.9k
                    "functions",
3753
14.9k
                    offset,
3754
0
                )?;
3755
14.9k
                push_module_export!(EntityType::Func, core_funcs, "function");
3756
            }
3757
            ExternalKind::Table => {
3758
0
                check_max(
3759
0
                    self.core_tables.len(),
3760
                    1,
3761
                    MAX_CORE_INDEX_SPACE_ITEMS,
3762
0
                    "tables",
3763
0
                    offset,
3764
0
                )?;
3765
0
                push_module_export!(EntityType::Table, core_tables, "table");
3766
            }
3767
            ExternalKind::Memory => {
3768
1.77k
                check_max(
3769
1.77k
                    self.core_memories.len(),
3770
                    1,
3771
                    MAX_CORE_INDEX_SPACE_ITEMS,
3772
1.77k
                    "memories",
3773
1.77k
                    offset,
3774
0
                )?;
3775
1.77k
                push_module_export!(EntityType::Memory, core_memories, "memory");
3776
            }
3777
            ExternalKind::Global => {
3778
0
                check_max(
3779
0
                    self.core_globals.len(),
3780
                    1,
3781
                    MAX_CORE_INDEX_SPACE_ITEMS,
3782
0
                    "globals",
3783
0
                    offset,
3784
0
                )?;
3785
0
                push_module_export!(EntityType::Global, core_globals, "global");
3786
            }
3787
            ExternalKind::Tag => {
3788
0
                require_feature::exceptions(
3789
0
                    self.features,
3790
                    "exceptions proposal not enabled",
3791
0
                    offset,
3792
0
                )?;
3793
0
                check_max(
3794
0
                    self.core_tags.len(),
3795
                    1,
3796
                    MAX_CORE_INDEX_SPACE_ITEMS,
3797
0
                    "tags",
3798
0
                    offset,
3799
0
                )?;
3800
0
                push_module_export!(EntityType::Tag, core_tags, "tag");
3801
            }
3802
        }
3803
3804
16.7k
        Ok(())
3805
16.7k
    }
3806
3807
7.12k
    fn alias_instance_export(
3808
7.12k
        &mut self,
3809
7.12k
        instance_index: u32,
3810
7.12k
        kind: ComponentExternalKind,
3811
7.12k
        name: &str,
3812
7.12k
        types: &mut TypeAlloc,
3813
7.12k
        offset: u64,
3814
7.12k
    ) -> Result<()> {
3815
7.12k
        if let ComponentExternalKind::Value = kind {
3816
0
            self.check_value_support(offset)?;
3817
7.12k
        }
3818
7.12k
        let mut ty = match types[self.instance_at(instance_index, offset)?]
3819
            .exports
3820
7.12k
            .get(name)
3821
        {
3822
7.12k
            Some(ty) => ty.ty,
3823
0
            None => bail!(
3824
0
                offset,
3825
                "instance {instance_index} has no export named `{name}`"
3826
            ),
3827
        };
3828
3829
7.12k
        let ok = match (ty, kind) {
3830
0
            (ComponentEntityType::Module(_), ComponentExternalKind::Module) => true,
3831
0
            (ComponentEntityType::Module(_), _) => false,
3832
0
            (ComponentEntityType::Component(_), ComponentExternalKind::Component) => true,
3833
0
            (ComponentEntityType::Component(_), _) => false,
3834
1.57k
            (ComponentEntityType::Func(_), ComponentExternalKind::Func) => true,
3835
0
            (ComponentEntityType::Func(_), _) => false,
3836
0
            (ComponentEntityType::Instance(_), ComponentExternalKind::Instance) => true,
3837
0
            (ComponentEntityType::Instance(_), _) => false,
3838
0
            (ComponentEntityType::Value(_), ComponentExternalKind::Value) => true,
3839
0
            (ComponentEntityType::Value(_), _) => false,
3840
5.54k
            (ComponentEntityType::Type { .. }, ComponentExternalKind::Type) => true,
3841
0
            (ComponentEntityType::Type { .. }, _) => false,
3842
        };
3843
7.12k
        if !ok {
3844
0
            bail!(
3845
0
                offset,
3846
                "export `{name}` for instance {instance_index} is not a {}",
3847
0
                kind.desc(),
3848
            );
3849
7.12k
        }
3850
3851
7.12k
        self.add_entity(&mut ty, None, types, offset)?;
3852
7.12k
        Ok(())
3853
7.12k
    }
3854
3855
0
    fn alias_module(components: &mut [Self], count: u32, index: u32, offset: u64) -> Result<()> {
3856
0
        let component = Self::check_alias_count(components, count, offset)?;
3857
0
        let ty = component.module_at(index, offset)?;
3858
3859
0
        let current = components.last_mut().unwrap();
3860
0
        check_max(
3861
0
            current.core_modules.len(),
3862
            1,
3863
            MAX_WASM_MODULES,
3864
0
            "modules",
3865
0
            offset,
3866
0
        )?;
3867
3868
0
        current.core_modules.push(ty);
3869
0
        Ok(())
3870
0
    }
3871
3872
0
    fn alias_component(components: &mut [Self], count: u32, index: u32, offset: u64) -> Result<()> {
3873
0
        let component = Self::check_alias_count(components, count, offset)?;
3874
0
        let ty = component.component_at(index, offset)?;
3875
3876
0
        let current = components.last_mut().unwrap();
3877
0
        check_max(
3878
0
            current.components.len(),
3879
            1,
3880
            MAX_WASM_COMPONENTS,
3881
0
            "components",
3882
0
            offset,
3883
0
        )?;
3884
3885
0
        current.components.push(ty);
3886
0
        Ok(())
3887
0
    }
3888
3889
0
    fn alias_core_type(components: &mut [Self], count: u32, index: u32, offset: u64) -> Result<()> {
3890
0
        let component = Self::check_alias_count(components, count, offset)?;
3891
0
        let ty = component.core_type_at(index, offset)?;
3892
3893
0
        let current = components.last_mut().unwrap();
3894
0
        check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
3895
3896
0
        current.core_types.push(ty);
3897
3898
0
        Ok(())
3899
0
    }
3900
3901
7.01k
    fn alias_type(
3902
7.01k
        components: &mut [Self],
3903
7.01k
        count: u32,
3904
7.01k
        index: u32,
3905
7.01k
        types: &mut TypeAlloc,
3906
7.01k
        offset: u64,
3907
7.01k
    ) -> Result<()> {
3908
7.01k
        let component = Self::check_alias_count(components, count, offset)?;
3909
7.01k
        let ty = component.component_type_at(index, offset)?;
3910
3911
        // If `count` "crossed a component boundary", meaning that it went from
3912
        // one component to another, then this must additionally verify that
3913
        // `ty` has no free variables with respect to resources. This is
3914
        // intended to preserve the property for components where each component
3915
        // is an isolated unit that can theoretically be extracted from other
3916
        // components. If resources from other components were allowed to leak
3917
        // in then it would prevent that.
3918
        //
3919
        // This check is done by calculating the `pos` within `components` that
3920
        // our target `component` above was selected at. Once this is acquired
3921
        // the component to the "right" is checked, and if that's a component
3922
        // then it's considered as crossing a component boundary meaning the
3923
        // free variables check runs.
3924
        //
3925
        // The reason this works is that in the list of `ComponentState` types
3926
        // it's guaranteed that any `is_type` components are contiguous at the
3927
        // end of the array. This means that if state one level deeper than the
3928
        // target of this alias is a `!is_type` component, then the target must
3929
        // be a component as well. If the one-level deeper state `is_type` then
3930
        // the target is either a type or a component, both of which are valid
3931
        // (as aliases can reach the enclosing component and have as many free
3932
        // variables as they want).
3933
7.01k
        let pos_after_component = components.len() - (count as usize);
3934
7.01k
        if let Some(component) = components.get(pos_after_component) {
3935
7.01k
            if component.kind == ComponentKind::Component {
3936
0
                let mut free = IndexSet::default();
3937
0
                types.free_variables_any_type_id(ty, &mut free);
3938
0
                if !free.is_empty() {
3939
0
                    bail!(
3940
0
                        offset,
3941
                        "cannot alias outer type which transitively refers \
3942
                         to resources not defined in the current component"
3943
                    );
3944
0
                }
3945
7.01k
            }
3946
0
        }
3947
3948
7.01k
        let current = components.last_mut().unwrap();
3949
7.01k
        check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
3950
3951
7.01k
        current.types.push(ty);
3952
3953
7.01k
        Ok(())
3954
7.01k
    }
3955
3956
7.01k
    fn check_alias_count(components: &[Self], count: u32, offset: u64) -> Result<&Self> {
3957
7.01k
        let count = count as usize;
3958
7.01k
        if count >= components.len() {
3959
0
            bail!(offset, "invalid outer alias count of {count}");
3960
7.01k
        }
3961
3962
7.01k
        Ok(&components[components.len() - count - 1])
3963
7.01k
    }
3964
3965
155k
    fn create_defined_type(
3966
155k
        &self,
3967
155k
        ty: crate::ComponentDefinedType,
3968
155k
        types: &TypeList,
3969
155k
        offset: u64,
3970
155k
    ) -> Result<ComponentDefinedType> {
3971
155k
        match ty {
3972
957
            crate::ComponentDefinedType::Primitive(ty) => {
3973
957
                self.check_primitive_type(ty, offset)?;
3974
957
                Ok(ComponentDefinedType::Primitive(ty))
3975
            }
3976
2.64k
            crate::ComponentDefinedType::Record(fields) => {
3977
2.64k
                self.create_record_type(fields.as_ref(), types, offset)
3978
            }
3979
5.67k
            crate::ComponentDefinedType::Variant(cases) => {
3980
5.67k
                self.create_variant_type(cases.as_ref(), types, offset)
3981
            }
3982
2.50k
            crate::ComponentDefinedType::List(ty) => {
3983
2.50k
                let element = self.create_component_val_type(ty, offset)?;
3984
2.50k
                let mut info = TypeInfo::new();
3985
2.50k
                info.combine(element.info(types), offset)?;
3986
2.50k
                let abi = AbiInfo::list(element.abi(types));
3987
2.50k
                Ok(ComponentDefinedType::List { element, info, abi })
3988
            }
3989
0
            crate::ComponentDefinedType::Map(key, value) => {
3990
0
                require_feature::cm_map(
3991
0
                    self.features,
3992
                    "Maps require the component model map feature",
3993
0
                    offset,
3994
0
                )?;
3995
0
                let key = self.create_component_val_type(key, offset)?;
3996
0
                let value = self.create_component_val_type(value, offset)?;
3997
0
                let mut info = TypeInfo::new();
3998
0
                info.combine(key.info(types), offset)?;
3999
0
                info.combine(value.info(types), offset)?;
4000
0
                let abi = AbiInfo::map(key.abi(types), value.abi(types));
4001
0
                Ok(ComponentDefinedType::Map {
4002
0
                    key,
4003
0
                    value,
4004
0
                    info,
4005
0
                    abi,
4006
0
                })
4007
            }
4008
1.45k
            crate::ComponentDefinedType::FixedLengthList(ty, elements) => {
4009
1.45k
                require_feature::cm_fixed_length_lists(
4010
1.45k
                    self.features,
4011
                    "Fixed-length lists require the component model fixed-length lists feature",
4012
1.45k
                    offset,
4013
0
                )?;
4014
1.45k
                if elements < 1 {
4015
0
                    bail!(
4016
0
                        offset,
4017
                        "Fixed-length lists must have more than zero elements"
4018
                    )
4019
1.45k
                }
4020
1.45k
                check_max(
4021
                    0,
4022
1.45k
                    elements,
4023
                    MAX_WASM_FIXED_LENGTH_LIST_ELEMENTS,
4024
1.45k
                    "fixed-length list element",
4025
1.45k
                    offset,
4026
0
                )?;
4027
1.45k
                let element = self.create_component_val_type(ty, offset)?;
4028
1.45k
                let mut info = TypeInfo::new();
4029
1.45k
                info.combine(element.info(types), offset)?;
4030
1.45k
                let abi = AbiInfo::fixed_length_list(element.abi(types), elements, offset)?;
4031
1.44k
                Ok(ComponentDefinedType::FixedLengthList {
4032
1.44k
                    element,
4033
1.44k
                    length: elements,
4034
1.44k
                    info,
4035
1.44k
                    abi,
4036
1.44k
                })
4037
            }
4038
38.4k
            crate::ComponentDefinedType::Tuple(tys) => {
4039
38.4k
                self.create_tuple_type(tys.as_ref(), types, offset)
4040
            }
4041
788
            crate::ComponentDefinedType::Flags(names) => {
4042
788
                self.create_flags_type(names.as_ref(), offset)
4043
            }
4044
56.6k
            crate::ComponentDefinedType::Enum(cases) => {
4045
56.6k
                self.create_enum_type(cases.as_ref(), offset)
4046
            }
4047
10.3k
            crate::ComponentDefinedType::Option(ty) => {
4048
10.3k
                let ty = self.create_component_val_type(ty, offset)?;
4049
10.3k
                let mut info = TypeInfo::new();
4050
10.3k
                info.combine(ty.info(types), offset)?;
4051
10.3k
                let abis = [None, Some(ty.abi(types))];
4052
10.3k
                let abi = AbiInfo::variant(abis.into_iter(), offset)?;
4053
10.3k
                Ok(ComponentDefinedType::Option { ty, info, abi })
4054
            }
4055
28.3k
            crate::ComponentDefinedType::Result { ok, err } => {
4056
28.3k
                let ok = ok
4057
28.3k
                    .map(|ty| self.create_component_val_type(ty, offset))
4058
28.3k
                    .transpose()?;
4059
28.3k
                let err = err
4060
28.3k
                    .map(|ty| self.create_component_val_type(ty, offset))
4061
28.3k
                    .transpose()?;
4062
28.3k
                let mut info = TypeInfo::new();
4063
28.3k
                if let Some(ty) = &ok {
4064
27.1k
                    info.combine(ty.info(types), offset)?;
4065
1.22k
                }
4066
28.3k
                if let Some(ty) = &err {
4067
26.4k
                    info.combine(ty.info(types), offset)?;
4068
1.90k
                }
4069
28.3k
                let abis = [ok.map(|ty| ty.abi(types)), err.map(|ty| ty.abi(types))];
4070
28.3k
                let abi = AbiInfo::variant(abis.into_iter(), offset)?;
4071
28.3k
                Ok(ComponentDefinedType::Result { ok, err, info, abi })
4072
            }
4073
347
            crate::ComponentDefinedType::Own(idx) => Ok(ComponentDefinedType::Own(
4074
347
                self.resource_at(idx, types, offset)?,
4075
            )),
4076
1.44k
            crate::ComponentDefinedType::Borrow(idx) => Ok(ComponentDefinedType::Borrow(
4077
1.44k
                self.resource_at(idx, types, offset)?,
4078
            )),
4079
3.80k
            crate::ComponentDefinedType::Future(ty) => {
4080
3.80k
                require_feature::cm_async(
4081
3.80k
                    self.features,
4082
                    "`future` requires the component model async feature",
4083
3.80k
                    offset,
4084
0
                )?;
4085
3.80k
                let ty = ty
4086
3.80k
                    .map(|ty| self.create_component_val_type(ty, offset))
4087
3.80k
                    .transpose()?;
4088
3.80k
                let mut info = TypeInfo::new();
4089
3.80k
                if let Some(ty) = &ty {
4090
3.37k
                    info.combine(ty.info(types), offset)?;
4091
436
                }
4092
3.80k
                let abi = AbiInfo::future_or_stream(ty.map(|ty| ty.abi(types)));
4093
3.80k
                Ok(ComponentDefinedType::Future { ty, info, abi })
4094
            }
4095
2.62k
            crate::ComponentDefinedType::Stream(ty) => {
4096
2.62k
                require_feature::cm_async(
4097
2.62k
                    self.features,
4098
                    "`stream` requires the component model async feature",
4099
2.62k
                    offset,
4100
0
                )?;
4101
2.62k
                let ty = ty
4102
2.62k
                    .map(|ty| self.create_component_val_type(ty, offset))
4103
2.62k
                    .transpose()?;
4104
2.62k
                let prim = match ty {
4105
367
                    Some(ComponentValType::Primitive(p)) => Some(p),
4106
2.25k
                    Some(ComponentValType::Type(id)) => match types[id] {
4107
0
                        ComponentDefinedType::Primitive(p) => Some(p),
4108
2.25k
                        _ => None,
4109
                    },
4110
0
                    None => None,
4111
                };
4112
2.62k
                if prim == Some(crate::PrimitiveValType::Char) {
4113
9
                    bail!(
4114
9
                        offset,
4115
                        "`stream<char>` is not valid at this time, use `stream<u8>` \
4116
                         with a defined by encoding instead for now"
4117
                    )
4118
2.61k
                }
4119
2.61k
                let mut info = TypeInfo::new();
4120
2.61k
                if let Some(ty) = &ty {
4121
2.61k
                    info.combine(ty.info(types), offset)?;
4122
0
                }
4123
2.61k
                let abi = AbiInfo::future_or_stream(ty.map(|ty| ty.abi(types)));
4124
2.61k
                Ok(ComponentDefinedType::Stream { ty, info, abi })
4125
            }
4126
        }
4127
155k
    }
4128
4129
2.64k
    fn create_record_type(
4130
2.64k
        &self,
4131
2.64k
        fields: &[(&str, crate::ComponentValType)],
4132
2.64k
        types: &TypeList,
4133
2.64k
        offset: u64,
4134
2.64k
    ) -> Result<ComponentDefinedType> {
4135
2.64k
        let mut info = TypeInfo::new();
4136
2.64k
        let mut field_map = IndexMap::default();
4137
2.64k
        field_map.reserve(fields.len());
4138
4139
2.64k
        if fields.is_empty() {
4140
0
            bail!(offset, "record type must have at least one field");
4141
2.64k
        }
4142
4143
11.1k
        for (name, ty) in fields {
4144
11.1k
            let kebab = to_kebab_string(name, "record field", offset)?;
4145
11.1k
            let ty = self.create_component_val_type(*ty, offset)?;
4146
4147
11.1k
            match field_map.entry(kebab) {
4148
0
                Entry::Occupied(e) => bail!(
4149
0
                    offset,
4150
                    "record field name `{name}` conflicts with previous field name `{prev}`",
4151
0
                    prev = e.key()
4152
                ),
4153
11.1k
                Entry::Vacant(e) => {
4154
11.1k
                    info.combine(ty.info(types), offset)?;
4155
11.1k
                    e.insert(ty);
4156
                }
4157
            }
4158
        }
4159
4160
11.1k
        let abi = AbiInfo::record(field_map.values().map(|ty| ty.abi(types)), offset)?;
4161
2.64k
        Ok(ComponentDefinedType::Record(RecordType {
4162
2.64k
            info,
4163
2.64k
            abi,
4164
2.64k
            fields: field_map,
4165
2.64k
        }))
4166
2.64k
    }
4167
4168
5.67k
    fn create_variant_type(
4169
5.67k
        &self,
4170
5.67k
        cases: &[crate::VariantCase],
4171
5.67k
        types: &TypeList,
4172
5.67k
        offset: u64,
4173
5.67k
    ) -> Result<ComponentDefinedType> {
4174
5.67k
        let mut info = TypeInfo::new();
4175
5.67k
        let mut case_map: IndexMap<KebabString, VariantCase> = IndexMap::default();
4176
5.67k
        case_map.reserve(cases.len());
4177
4178
5.67k
        if cases.is_empty() {
4179
0
            bail!(offset, "variant type must have at least one case");
4180
5.67k
        }
4181
4182
5.67k
        if cases.len() > u32::MAX as usize {
4183
0
            return Err(Error::new(
4184
0
                "variant type cannot be represented with a 32-bit discriminant value",
4185
0
                offset,
4186
0
            ));
4187
5.67k
        }
4188
4189
27.1k
        for case in cases {
4190
27.1k
            let name = to_kebab_string(case.name, "variant case", offset)?;
4191
4192
27.1k
            let ty = case
4193
27.1k
                .ty
4194
27.1k
                .map(|ty| self.create_component_val_type(ty, offset))
4195
27.1k
                .transpose()?;
4196
4197
27.1k
            match case_map.entry(name) {
4198
0
                Entry::Occupied(e) => bail!(
4199
0
                    offset,
4200
                    "variant case name `{name}` conflicts with previous case name `{prev}`",
4201
                    name = case.name,
4202
0
                    prev = e.key()
4203
                ),
4204
27.1k
                Entry::Vacant(e) => {
4205
27.1k
                    if let Some(ty) = ty {
4206
25.9k
                        info.combine(ty.info(types), offset)?;
4207
1.20k
                    }
4208
27.1k
                    e.insert(VariantCase { ty });
4209
                }
4210
            }
4211
        }
4212
4213
5.67k
        let abi = AbiInfo::variant(
4214
27.1k
            case_map.values().map(|c| c.ty.map(|ty| ty.abi(types))),
4215
5.67k
            offset,
4216
0
        )?;
4217
5.67k
        Ok(ComponentDefinedType::Variant(VariantType {
4218
5.67k
            info,
4219
5.67k
            abi,
4220
5.67k
            cases: case_map,
4221
5.67k
        }))
4222
5.67k
    }
4223
4224
38.4k
    fn create_tuple_type(
4225
38.4k
        &self,
4226
38.4k
        tys: &[crate::ComponentValType],
4227
38.4k
        types: &TypeList,
4228
38.4k
        offset: u64,
4229
38.4k
    ) -> Result<ComponentDefinedType> {
4230
38.4k
        let mut info = TypeInfo::new();
4231
38.4k
        if tys.is_empty() {
4232
0
            bail!(offset, "tuple type must have at least one type");
4233
38.4k
        }
4234
38.4k
        let tuple_types: Box<[_]> = tys
4235
38.4k
            .iter()
4236
140k
            .map(|ty| {
4237
140k
                let ty = self.create_component_val_type(*ty, offset)?;
4238
140k
                info.combine(ty.info(types), offset)?;
4239
140k
                Ok(ty)
4240
140k
            })
4241
38.4k
            .collect::<Result<_>>()?;
4242
4243
140k
        let abi = AbiInfo::record(tuple_types.iter().map(|ty| ty.abi(types)), offset)?;
4244
38.4k
        Ok(ComponentDefinedType::Tuple(TupleType {
4245
38.4k
            info,
4246
38.4k
            abi,
4247
38.4k
            types: tuple_types,
4248
38.4k
        }))
4249
38.4k
    }
4250
4251
788
    fn create_flags_type(&self, names: &[&str], offset: u64) -> Result<ComponentDefinedType> {
4252
788
        let mut names_set = IndexSet::default();
4253
788
        names_set.reserve(names.len());
4254
4255
788
        if names.is_empty() {
4256
0
            bail!(offset, "flags must have at least one entry");
4257
788
        }
4258
4259
788
        if names.len() > 32 {
4260
0
            bail!(offset, "cannot have more than 32 flags");
4261
788
        }
4262
4263
2.02k
        for name in names {
4264
2.02k
            let kebab = to_kebab_string(name, "flag", offset)?;
4265
2.02k
            if let Some(prev) = names_set.replace(kebab) {
4266
0
                bail!(
4267
0
                    offset,
4268
                    "flag name `{name}` conflicts with previous flag name `{prev}`",
4269
                );
4270
2.02k
            }
4271
        }
4272
4273
788
        Ok(ComponentDefinedType::Flags(names_set))
4274
788
    }
4275
4276
56.6k
    fn create_enum_type(&self, cases: &[&str], offset: u64) -> Result<ComponentDefinedType> {
4277
56.6k
        if cases.len() > u32::MAX as usize {
4278
0
            return Err(Error::new(
4279
0
                "enumeration type cannot be represented with a 32-bit discriminant value",
4280
0
                offset,
4281
0
            ));
4282
56.6k
        }
4283
4284
56.6k
        if cases.is_empty() {
4285
0
            bail!(offset, "enum type must have at least one variant");
4286
56.6k
        }
4287
4288
56.6k
        let mut tags = IndexSet::default();
4289
56.6k
        tags.reserve(cases.len());
4290
4291
413k
        for tag in cases {
4292
413k
            let kebab = to_kebab_string(tag, "enum tag", offset)?;
4293
413k
            if let Some(prev) = tags.replace(kebab) {
4294
0
                bail!(
4295
0
                    offset,
4296
                    "enum tag name `{tag}` conflicts with previous tag name `{prev}`",
4297
                );
4298
413k
            }
4299
        }
4300
4301
56.6k
        Ok(ComponentDefinedType::Enum(tags))
4302
56.6k
    }
4303
4304
317k
    fn create_component_val_type(
4305
317k
        &self,
4306
317k
        ty: crate::ComponentValType,
4307
317k
        offset: u64,
4308
317k
    ) -> Result<ComponentValType> {
4309
317k
        Ok(match ty {
4310
203k
            crate::ComponentValType::Primitive(pt) => {
4311
203k
                self.check_primitive_type(pt, offset)?;
4312
203k
                ComponentValType::Primitive(pt)
4313
            }
4314
113k
            crate::ComponentValType::Type(idx) => {
4315
113k
                ComponentValType::Type(self.defined_type_at(idx, offset)?)
4316
            }
4317
        })
4318
317k
    }
4319
4320
0
    pub fn core_type_at(&self, idx: u32, offset: u64) -> Result<ComponentCoreTypeId> {
4321
0
        self.core_types
4322
0
            .get(idx as usize)
4323
0
            .copied()
4324
0
            .ok_or_else(|| format_err!(offset, "unknown type {idx}: type index out of bounds"))
4325
0
    }
4326
4327
262k
    pub fn component_type_at(&self, idx: u32, offset: u64) -> Result<ComponentAnyTypeId> {
4328
262k
        self.types
4329
262k
            .get(idx as usize)
4330
262k
            .copied()
4331
262k
            .ok_or_else(|| format_err!(offset, "unknown type {idx}: type index out of bounds"))
4332
262k
    }
4333
4334
6.30k
    fn function_type_at<'a>(
4335
6.30k
        &self,
4336
6.30k
        idx: u32,
4337
6.30k
        types: &'a TypeList,
4338
6.30k
        offset: u64,
4339
6.30k
    ) -> Result<&'a ComponentFuncType> {
4340
6.30k
        let id = self.component_type_at(idx, offset)?;
4341
6.30k
        match id {
4342
6.30k
            ComponentAnyTypeId::Func(id) => Ok(&types[id]),
4343
0
            _ => bail!(offset, "type index {idx} is not a function type"),
4344
        }
4345
6.30k
    }
4346
4347
14.5k
    fn function_at(&self, idx: u32, offset: u64) -> Result<ComponentFuncTypeId> {
4348
14.5k
        self.funcs.get(idx as usize).copied().ok_or_else(|| {
4349
0
            format_err!(
4350
0
                offset,
4351
                "unknown function {idx}: function index out of bounds"
4352
            )
4353
0
        })
4354
14.5k
    }
4355
4356
3.41k
    fn component_at(&self, idx: u32, offset: u64) -> Result<ComponentTypeId> {
4357
3.41k
        self.components.get(idx as usize).copied().ok_or_else(|| {
4358
0
            format_err!(
4359
0
                offset,
4360
                "unknown component {idx}: component index out of bounds"
4361
            )
4362
0
        })
4363
3.41k
    }
4364
4365
10.5k
    fn instance_at(&self, idx: u32, offset: u64) -> Result<ComponentInstanceTypeId> {
4366
10.5k
        self.instances.get(idx as usize).copied().ok_or_else(|| {
4367
0
            format_err!(
4368
0
                offset,
4369
                "unknown instance {idx}: instance index out of bounds"
4370
            )
4371
0
        })
4372
10.5k
    }
4373
4374
0
    fn value_at(&mut self, idx: u32, offset: u64) -> Result<&ComponentValType> {
4375
0
        match self.values.get_mut(idx as usize) {
4376
0
            Some((ty, used)) if !*used => {
4377
0
                *used = true;
4378
0
                Ok(ty)
4379
            }
4380
0
            Some(_) => bail!(offset, "value {idx} cannot be used more than once"),
4381
0
            None => bail!(offset, "unknown value {idx}: value index out of bounds"),
4382
        }
4383
0
    }
4384
4385
115k
    fn defined_type_at(&self, idx: u32, offset: u64) -> Result<ComponentDefinedTypeId> {
4386
115k
        match self.component_type_at(idx, offset)? {
4387
115k
            ComponentAnyTypeId::Defined(id) => Ok(id),
4388
0
            _ => bail!(offset, "type index {idx} is not a defined type"),
4389
        }
4390
115k
    }
4391
4392
29.7k
    fn core_function_at(&self, idx: u32, offset: u64) -> Result<CoreTypeId> {
4393
29.7k
        match self.core_funcs.get(idx as usize) {
4394
29.7k
            Some(id) => Ok(*id),
4395
0
            None => bail!(
4396
0
                offset,
4397
                "unknown core function {idx}: function index out of bounds"
4398
            ),
4399
        }
4400
29.7k
    }
4401
4402
4.27k
    fn module_at(&self, idx: u32, offset: u64) -> Result<ComponentCoreModuleTypeId> {
4403
4.27k
        match self.core_modules.get(idx as usize) {
4404
4.27k
            Some(id) => Ok(*id),
4405
0
            None => bail!(offset, "unknown module {idx}: module index out of bounds"),
4406
        }
4407
4.27k
    }
4408
4409
22.0k
    fn core_instance_at(&self, idx: u32, offset: u64) -> Result<ComponentCoreInstanceTypeId> {
4410
22.0k
        match self.core_instances.get(idx as usize) {
4411
22.0k
            Some(id) => Ok(*id),
4412
0
            None => bail!(
4413
0
                offset,
4414
                "unknown core instance {idx}: instance index out of bounds"
4415
            ),
4416
        }
4417
22.0k
    }
4418
4419
16.7k
    fn core_instance_export<'a>(
4420
16.7k
        &self,
4421
16.7k
        instance_index: u32,
4422
16.7k
        name: &str,
4423
16.7k
        types: &'a TypeList,
4424
16.7k
        offset: u64,
4425
16.7k
    ) -> Result<&'a EntityType> {
4426
16.7k
        match types[self.core_instance_at(instance_index, offset)?]
4427
16.7k
            .internal_exports(types)
4428
16.7k
            .get(name)
4429
        {
4430
16.7k
            Some(export) => Ok(export),
4431
0
            None => bail!(
4432
0
                offset,
4433
                "core instance {instance_index} has no export named `{name}`"
4434
            ),
4435
        }
4436
16.7k
    }
4437
4438
0
    fn global_at(&self, idx: u32, offset: u64) -> Result<&GlobalType> {
4439
0
        match self.core_globals.get(idx as usize) {
4440
0
            Some(t) => Ok(t),
4441
0
            None => bail!(offset, "unknown global {idx}: global index out of bounds"),
4442
        }
4443
0
    }
4444
4445
0
    fn table_at(&self, idx: u32, offset: u64) -> Result<&TableType> {
4446
0
        match self.core_tables.get(idx as usize) {
4447
0
            Some(t) => Ok(t),
4448
0
            None => bail!(offset, "unknown table {idx}: table index out of bounds"),
4449
        }
4450
0
    }
4451
4452
3.22k
    fn memory_at(&self, idx: u32, offset: u64) -> Result<&MemoryType> {
4453
3.22k
        match self.core_memories.get(idx as usize) {
4454
3.22k
            Some(t) => Ok(t),
4455
0
            None => bail!(offset, "unknown memory {idx}: memory index out of bounds"),
4456
        }
4457
3.22k
    }
4458
4459
0
    fn tag_at(&self, idx: u32, offset: u64) -> Result<CoreTypeId> {
4460
0
        match self.core_tags.get(idx as usize) {
4461
0
            Some(t) => Ok(*t),
4462
0
            None => bail!(offset, "unknown tag {idx}: tag index out of bounds"),
4463
        }
4464
0
    }
4465
4466
    /// Validates that the linear memory at `idx` is valid to use as a canonical
4467
    /// ABI memory.
4468
    ///
4469
    /// At this time this requires that the memory is a plain 32-bit or 64-bit linear
4470
    /// memory. Notably this disallows shared memory.
4471
2.22k
    fn cabi_memory_at(&self, idx: u32, offset: u64) -> Result<PtrSize> {
4472
2.22k
        let ty = self.memory_at(idx, offset)?;
4473
2.22k
        let valid_memory_type = MemoryType {
4474
2.22k
            initial: 0,
4475
2.22k
            maximum: None,
4476
2.22k
            memory64: ty.memory64,
4477
2.22k
            shared: false,
4478
2.22k
            page_size_log2: ty.page_size_log2,
4479
2.22k
        };
4480
2.22k
        if ty.memory64 {
4481
0
            require_feature::cm64(
4482
0
                self.features,
4483
                "64-bit memories require the `cm64` feature to be enabled",
4484
0
                offset,
4485
0
            )?;
4486
2.22k
        }
4487
2.22k
        SubtypeCx::memory_type(ty, &valid_memory_type, offset)?;
4488
2.22k
        Ok(if ty.memory64 {
4489
0
            PtrSize::Ptr64
4490
        } else {
4491
2.22k
            PtrSize::Ptr32
4492
        })
4493
2.22k
    }
4494
4495
    /// Completes the translation of this component, performing final
4496
    /// validation of its structure.
4497
    ///
4498
    /// This method is required to be called for translating all components.
4499
    /// Internally this will convert local data structures into a
4500
    /// `ComponentType` which is suitable to use to describe the type of this
4501
    /// component.
4502
17.2k
    pub fn finish(&mut self, types: &TypeAlloc, offset: u64) -> Result<ComponentType> {
4503
17.2k
        let mut ty = ComponentType {
4504
17.2k
            // Inherit some fields based on translation of the component.
4505
17.2k
            info: self.type_info,
4506
17.2k
            imports: self.imports.clone(),
4507
17.2k
            exports: self.exports.clone(),
4508
17.2k
4509
17.2k
            // This is filled in as a subset of `self.defined_resources`
4510
17.2k
            // depending on what's actually used by the exports. See the
4511
17.2k
            // bottom of this function.
4512
17.2k
            defined_resources: Default::default(),
4513
17.2k
4514
17.2k
            // These are inherited directly from what was calculated for this
4515
17.2k
            // component.
4516
17.2k
            imported_resources: mem::take(&mut self.imported_resources)
4517
17.2k
                .into_iter()
4518
17.2k
                .collect(),
4519
17.2k
            explicit_resources: mem::take(&mut self.explicit_resources),
4520
17.2k
        };
4521
4522
        // Collect all "free variables", or resources, from the imports of this
4523
        // component. None of the resources defined within this component can
4524
        // be used as part of the exports. This set is then used to reject any
4525
        // of `self.defined_resources` which show up.
4526
17.2k
        let mut free = IndexSet::default();
4527
17.4k
        for ty in ty.imports.values() {
4528
17.4k
            types.free_variables_component_entity(&ty.ty, &mut free);
4529
17.4k
        }
4530
17.2k
        for (resource, _path) in self.defined_resources.iter() {
4531
            // FIXME: this error message is quite opaque and doesn't indicate
4532
            // more contextual information such as:
4533
            //
4534
            // * what was the exported resource found in the imports
4535
            // * which import was the resource found within
4536
            //
4537
            // These are possible to calculate here if necessary, however.
4538
943
            if free.contains(resource) {
4539
0
                bail!(offset, "local resource type found in imports");
4540
943
            }
4541
        }
4542
4543
        // The next step in validation a component, with respect to resources,
4544
        // is to minimize the set of defined resources to only those that
4545
        // are actually used by the exports. This weeds out resources that are
4546
        // defined, used within a component, and never exported, for example.
4547
        //
4548
        // The free variables of all exports are inserted into the `free` set
4549
        // (which is reused from the imports after clearing it). The defined
4550
        // resources calculated for this component are then inserted into this
4551
        // type's list of defined resources if it's contained somewhere in
4552
        // the free variables.
4553
        //
4554
        // Note that at the same time all defined resources must be exported,
4555
        // somehow, transitively from this component. The `explicit_resources`
4556
        // map is consulted for this purpose which lists all explicitly
4557
        // exported resources in the component, regardless from whence they
4558
        // came. If not present in this map then it's not exported and an error
4559
        // is returned.
4560
        //
4561
        // NB: the "types are exported" check is probably sufficient nowadays
4562
        // that the check of the `explicit_resources` map is probably not
4563
        // necessary, but it's left here for completeness and out of an
4564
        // abundance of caution.
4565
17.2k
        free.clear();
4566
46.3k
        for ty in ty.exports.values() {
4567
46.3k
            types.free_variables_component_entity(&ty.ty, &mut free);
4568
46.3k
        }
4569
17.2k
        for (id, _rep) in mem::take(&mut self.defined_resources) {
4570
943
            if !free.contains(&id) {
4571
0
                continue;
4572
943
            }
4573
4574
943
            let path = match ty.explicit_resources.get(&id).cloned() {
4575
943
                Some(path) => path,
4576
                // FIXME: this error message is quite opaque and doesn't
4577
                // indicate more contextual information such as:
4578
                //
4579
                // * which resource wasn't found in an export
4580
                // * which export has a reference to the resource
4581
                //
4582
                // These are possible to calculate here if necessary, however.
4583
0
                None => bail!(
4584
0
                    offset,
4585
                    "local resource type found in export but not exported itself"
4586
                ),
4587
            };
4588
4589
943
            ty.defined_resources.push((id, path));
4590
        }
4591
4592
17.2k
        Ok(ty)
4593
17.2k
    }
4594
4595
0
    fn check_value_support(&self, offset: u64) -> Result<()> {
4596
0
        require_feature::cm_values(
4597
0
            self.features,
4598
            "support for component model `value`s is not enabled",
4599
0
            offset,
4600
0
        )?;
4601
0
        Ok(())
4602
0
    }
4603
4604
204k
    fn check_primitive_type(&self, ty: crate::PrimitiveValType, offset: u64) -> Result<()> {
4605
204k
        if ty == crate::PrimitiveValType::ErrorContext {
4606
31.3k
            require_feature::cm_error_context(
4607
31.3k
                self.features,
4608
                "`error-context` requires the component model error-context feature",
4609
31.3k
                offset,
4610
0
            )?;
4611
173k
        }
4612
204k
        Ok(())
4613
204k
    }
4614
}
4615
4616
impl InternRecGroup for ComponentState {
4617
0
    fn features(&self) -> &WasmFeatures {
4618
0
        &self.features
4619
0
    }
4620
4621
0
    fn add_type_id(&mut self, id: CoreTypeId) {
4622
0
        self.core_types.push(ComponentCoreTypeId::Sub(id));
4623
0
    }
4624
4625
0
    fn type_id_at(&self, idx: u32, offset: u64) -> Result<CoreTypeId> {
4626
0
        match self.core_type_at(idx, offset)? {
4627
0
            ComponentCoreTypeId::Sub(id) => Ok(id),
4628
            ComponentCoreTypeId::Module(_) => {
4629
0
                bail!(offset, "type index {idx} is a module type, not a sub type");
4630
            }
4631
        }
4632
0
    }
4633
4634
0
    fn types_len(&self) -> u32 {
4635
0
        u32::try_from(self.core_types.len()).unwrap()
4636
0
    }
4637
}
4638
4639
impl ComponentNameContext {
4640
    /// Registers that the resource `id` is named `name` within this context.
4641
2.53k
    fn register(&mut self, name: &str, id: AliasableResourceId) {
4642
2.53k
        let idx = self.all_resource_names.len();
4643
2.53k
        let prev = self.resource_name_map.insert(id, idx);
4644
2.53k
        assert!(
4645
2.53k
            prev.is_none(),
4646
            "for {id:?}, inserted {idx:?} but already had {prev:?}"
4647
        );
4648
2.53k
        self.all_resource_names.insert(name.to_string());
4649
2.53k
    }
4650
4651
135k
    fn validate_extern(
4652
135k
        &self,
4653
135k
        name: &ComponentExternName<'_>,
4654
135k
        kind: ExternKind,
4655
135k
        ty: &ComponentEntityType,
4656
135k
        types: &TypeAlloc,
4657
135k
        offset: u64,
4658
135k
        kind_names: &mut IndexSet<ComponentName>,
4659
135k
        items: &mut IndexMap<String, ComponentItem>,
4660
135k
        info: &mut TypeInfo,
4661
135k
        features: &WasmFeatures,
4662
135k
    ) -> Result<()> {
4663
        let ComponentExternName {
4664
135k
            name,
4665
135k
            implements,
4666
135k
            external_id,
4667
135k
            version_suffix,
4668
135k
        } = *name;
4669
        // First validate that `name` is even a valid kebab name, meaning it's
4670
        // in kebab-case, is an ID, etc.
4671
135k
        let kebab =
4672
135k
            ComponentName::new_with_features(name, offset, *features).with_context(|| {
4673
0
                format!("{} name `{name}` is not a valid extern name", kind.desc(),)
4674
0
            })?;
4675
4676
135k
        if let ExternKind::Export = kind {
4677
118k
            match kebab.kind() {
4678
                ComponentNameKind::Label(_)
4679
                | ComponentNameKind::Method(_)
4680
                | ComponentNameKind::Static(_)
4681
                | ComponentNameKind::Constructor(_)
4682
118k
                | ComponentNameKind::Interface(_) => {}
4683
4684
                ComponentNameKind::Hash(_)
4685
                | ComponentNameKind::Url(_)
4686
                | ComponentNameKind::Dependency(_) => {
4687
0
                    bail!(offset, "name `{name}` is not a valid export name")
4688
                }
4689
            }
4690
17.4k
        }
4691
4692
135k
        if let Some(implements) = implements {
4693
8.03k
            require_feature::cm_implements(
4694
8.03k
                *features,
4695
                "the `cm-implements` feature is not active",
4696
8.03k
                offset,
4697
0
            )?;
4698
8.03k
            match kebab.kind() {
4699
8.03k
                ComponentNameKind::Label(_) => {}
4700
0
                _ => bail!(offset, "name `{name}` is not valid with `implements`",),
4701
            }
4702
4703
8.03k
            match ty {
4704
8.03k
                ComponentEntityType::Instance(_) => {}
4705
0
                _ => bail!(offset, "only instances can have an `implements`"),
4706
            }
4707
4708
8.03k
            let implements = ComponentName::new_with_features(implements, offset, *features)
4709
8.03k
                .with_context(|| format!("`{implements}` is not a valid name"))?;
4710
8.03k
            match implements.kind() {
4711
8.03k
                ComponentNameKind::Interface(_) => {}
4712
0
                _ => bail!(offset, "name `{implements}` must be an interface"),
4713
            }
4714
127k
        }
4715
4716
135k
        if let Some(_) = version_suffix {
4717
0
            require_feature::cm_canon_names(
4718
0
                *features,
4719
                "the `cm-canon-names` feature is not active",
4720
0
                offset,
4721
0
            )?;
4722
0
            match ty {
4723
0
                ComponentEntityType::Instance(_) => {}
4724
0
                _ => bail!(offset, "only instances can have an `versionsuffix`"),
4725
            }
4726
135k
        }
4727
4728
135k
        if let Some(_) = external_id {
4729
97.0k
            require_feature::cm_implements(
4730
97.0k
                *features,
4731
                "the `cm-implements` feature is not active",
4732
97.0k
                offset,
4733
0
            )?;
4734
38.6k
        }
4735
4736
        // Validate that the kebab name, if it has structure such as
4737
        // `[method]a.b`, is indeed valid with respect to known resources.
4738
135k
        self.validate(&kebab, version_suffix, ty, types, offset)
4739
135k
            .with_context(|| format!("{} name `{kebab}` is not valid", kind.desc()))?;
4740
4741
        // Top-level kebab-names must all be unique, even between both imports
4742
        // and exports ot a component. For those names consult the `kebab_names`
4743
        // set.
4744
135k
        if let Some(prev) = kind_names.replace(kebab.clone()) {
4745
0
            bail!(
4746
0
                offset,
4747
                "{} name `{kebab}` conflicts with previous name `{prev}`",
4748
0
                kind.desc()
4749
            );
4750
135k
        }
4751
4752
        // Otherwise all strings must be unique, regardless of their name, so
4753
        // consult the `items` set to ensure that we're not for example
4754
        // importing the same interface ID twice.
4755
135k
        match items.entry(name.to_string()) {
4756
0
            Entry::Occupied(e) => {
4757
0
                bail!(
4758
0
                    offset,
4759
                    "{kind} name `{name}` conflicts with previous name `{prev}`",
4760
0
                    kind = kind.desc(),
4761
0
                    prev = e.key(),
4762
                );
4763
            }
4764
135k
            Entry::Vacant(e) => {
4765
135k
                e.insert(ComponentItem {
4766
135k
                    ty: *ty,
4767
135k
                    implements: implements.map(|s| s.to_string()),
4768
135k
                    version_suffix: version_suffix.map(|s| s.to_string()),
4769
135k
                    external_id: external_id.map(|s| s.to_string()),
4770
                });
4771
135k
                info.combine(ty.info(types), offset)?;
4772
            }
4773
        }
4774
135k
        Ok(())
4775
135k
    }
4776
4777
    /// Validates that the `name` provided is allowed to have the type `ty`.
4778
135k
    fn validate(
4779
135k
        &self,
4780
135k
        name: &ComponentName,
4781
135k
        version_suffix: Option<&str>,
4782
135k
        ty: &ComponentEntityType,
4783
135k
        types: &TypeAlloc,
4784
135k
        offset: u64,
4785
135k
    ) -> Result<()> {
4786
135k
        let func = || {
4787
6.14k
            let id = match ty {
4788
6.14k
                ComponentEntityType::Func(id) => *id,
4789
0
                _ => bail!(offset, "item is not a func"),
4790
            };
4791
6.14k
            Ok(&types[id])
4792
6.14k
        };
4793
4794
135k
        match name.kind() {
4795
            // No validation necessary for these styles of names
4796
            ComponentNameKind::Label(_)
4797
            | ComponentNameKind::Url(_)
4798
            | ComponentNameKind::Hash(_)
4799
117k
            | ComponentNameKind::Dependency(_) => {}
4800
4801
            // Validate the `version_suffix` field in the context of interface
4802
            // names.
4803
12.1k
            ComponentNameKind::Interface(name) => {
4804
12.1k
                if let Err(e) = name.version(version_suffix) {
4805
0
                    bail!(offset, "invalid interface version: {e}");
4806
12.1k
                }
4807
            }
4808
4809
            // Constructors must return `(own $resource)` or
4810
            // `(result (own $Tresource))` and the `$resource` must be named
4811
            // within this context to match `rname`.
4812
221
            ComponentNameKind::Constructor(rname) => {
4813
221
                let ty = func()?;
4814
221
                if ty.async_ {
4815
0
                    bail!(offset, "constructor function cannot be async");
4816
221
                }
4817
221
                let ty = match ty.result {
4818
221
                    Some(result) => result,
4819
0
                    None => bail!(offset, "function should return one value"),
4820
                };
4821
221
                let resource = match ty {
4822
0
                    ComponentValType::Primitive(_) => None,
4823
221
                    ComponentValType::Type(ty) => match &types[ty] {
4824
221
                        ComponentDefinedType::Own(id) => Some(id),
4825
                        ComponentDefinedType::Result {
4826
0
                            ok: Some(ComponentValType::Type(ok)),
4827
                            ..
4828
0
                        } => match &types[*ok] {
4829
0
                            ComponentDefinedType::Own(id) => Some(id),
4830
0
                            _ => None,
4831
                        },
4832
0
                        _ => None,
4833
                    },
4834
                };
4835
221
                let resource = match resource {
4836
221
                    Some(id) => id,
4837
0
                    None => bail!(
4838
0
                        offset,
4839
                        "function should return `(own $T)` or `(result (own $T))`"
4840
                    ),
4841
                };
4842
221
                self.validate_resource_name(*resource, rname, offset)?;
4843
            }
4844
4845
            // Methods must take `(param "self" (borrow $resource))` as the
4846
            // first argument where `$resources` matches the name `resource` as
4847
            // named in this context.
4848
2.02k
            ComponentNameKind::Method(name) => {
4849
2.02k
                let ty = func()?;
4850
2.02k
                if ty.params.len() == 0 {
4851
0
                    bail!(offset, "function should have at least one argument");
4852
2.02k
                }
4853
2.02k
                let (pname, pty) = &ty.params[0];
4854
2.02k
                if pname.as_str() != "self" {
4855
0
                    bail!(
4856
0
                        offset,
4857
                        "function should have a first argument called `self`",
4858
                    );
4859
2.02k
                }
4860
2.02k
                let id = match pty {
4861
0
                    ComponentValType::Primitive(_) => None,
4862
2.02k
                    ComponentValType::Type(ty) => match &types[*ty] {
4863
2.02k
                        ComponentDefinedType::Borrow(id) => Some(id),
4864
0
                        _ => None,
4865
                    },
4866
                };
4867
2.02k
                let id = match id {
4868
2.02k
                    Some(id) => id,
4869
0
                    None => bail!(
4870
0
                        offset,
4871
                        "function should take a first argument of `(borrow $T)`"
4872
                    ),
4873
                };
4874
2.02k
                self.validate_resource_name(*id, name.resource(), offset)?;
4875
            }
4876
4877
            // Static methods don't have much validation beyond that they must
4878
            // be a function and the resource name referred to must already be
4879
            // in this context.
4880
3.89k
            ComponentNameKind::Static(name) => {
4881
3.89k
                func()?;
4882
3.89k
                if !self.all_resource_names.contains(name.resource().as_str()) {
4883
0
                    bail!(offset, "static resource name is not known in this context");
4884
3.89k
                }
4885
            }
4886
        }
4887
4888
135k
        Ok(())
4889
135k
    }
4890
4891
2.25k
    fn validate_resource_name(
4892
2.25k
        &self,
4893
2.25k
        id: AliasableResourceId,
4894
2.25k
        name: KebabStr<'_>,
4895
2.25k
        offset: u64,
4896
2.25k
    ) -> Result<()> {
4897
2.25k
        let expected_name_idx = match self.resource_name_map.get(&id) {
4898
2.25k
            Some(idx) => *idx,
4899
            None => {
4900
0
                bail!(
4901
0
                    offset,
4902
                    "resource used in function does not have a name in this context"
4903
                )
4904
            }
4905
        };
4906
2.25k
        let expected_name = &self.all_resource_names[expected_name_idx];
4907
2.25k
        if name.as_str() != expected_name {
4908
0
            bail!(
4909
0
                offset,
4910
                "function does not match expected resource name `{expected_name}`"
4911
            );
4912
2.25k
        }
4913
2.25k
        Ok(())
4914
2.25k
    }
4915
}
4916
4917
use self::append_only::*;
4918
4919
mod append_only {
4920
    use crate::prelude::IndexMap;
4921
    use core::hash::Hash;
4922
    use core::ops::Deref;
4923
4924
    pub struct IndexMapAppendOnly<K, V>(IndexMap<K, V>);
4925
4926
    impl<K, V> IndexMapAppendOnly<K, V>
4927
    where
4928
        K: Hash + Eq + Ord + PartialEq + Clone,
4929
    {
4930
3.26k
        pub fn insert(&mut self, key: K, value: V) {
4931
3.26k
            let prev = self.0.insert(key, value);
4932
3.26k
            assert!(prev.is_none());
4933
3.26k
        }
<wasmparser::validator::component::append_only::IndexMapAppendOnly<wasmparser::validator::component_types::ResourceId, alloc::vec::Vec<usize>>>::insert
Line
Count
Source
4930
1.11k
        pub fn insert(&mut self, key: K, value: V) {
4931
1.11k
            let prev = self.0.insert(key, value);
4932
1.11k
            assert!(prev.is_none());
4933
1.11k
        }
<wasmparser::validator::component::append_only::IndexMapAppendOnly<wasmparser::validator::component_types::ResourceId, core::option::Option<wasmparser::readers::core::types::ValType>>>::insert
Line
Count
Source
4930
2.15k
        pub fn insert(&mut self, key: K, value: V) {
4931
2.15k
            let prev = self.0.insert(key, value);
4932
2.15k
            assert!(prev.is_none());
4933
2.15k
        }
4934
    }
4935
4936
    impl<K, V> Deref for IndexMapAppendOnly<K, V> {
4937
        type Target = IndexMap<K, V>;
4938
32.6k
        fn deref(&self) -> &IndexMap<K, V> {
4939
32.6k
            &self.0
4940
32.6k
        }
<wasmparser::validator::component::append_only::IndexMapAppendOnly<wasmparser::validator::component_types::ResourceId, alloc::vec::Vec<usize>> as core::ops::deref::Deref>::deref
Line
Count
Source
4938
14.7k
        fn deref(&self) -> &IndexMap<K, V> {
4939
14.7k
            &self.0
4940
14.7k
        }
<wasmparser::validator::component::append_only::IndexMapAppendOnly<wasmparser::validator::component_types::ResourceId, core::option::Option<wasmparser::readers::core::types::ValType>> as core::ops::deref::Deref>::deref
Line
Count
Source
4938
17.8k
        fn deref(&self) -> &IndexMap<K, V> {
4939
17.8k
            &self.0
4940
17.8k
        }
4941
    }
4942
4943
    impl<K, V> Default for IndexMapAppendOnly<K, V> {
4944
113k
        fn default() -> Self {
4945
113k
            Self(Default::default())
4946
113k
        }
<wasmparser::validator::component::append_only::IndexMapAppendOnly<wasmparser::validator::component_types::ResourceId, alloc::vec::Vec<usize>> as core::default::Default>::default
Line
Count
Source
4944
49.2k
        fn default() -> Self {
4945
49.2k
            Self(Default::default())
4946
49.2k
        }
<wasmparser::validator::component::append_only::IndexMapAppendOnly<wasmparser::validator::component_types::ResourceId, core::option::Option<wasmparser::readers::core::types::ValType>> as core::default::Default>::default
Line
Count
Source
4944
64.0k
        fn default() -> Self {
4945
64.0k
            Self(Default::default())
4946
64.0k
        }
4947
    }
4948
4949
    impl<K, V> IntoIterator for IndexMapAppendOnly<K, V> {
4950
        type IntoIter = <IndexMap<K, V> as IntoIterator>::IntoIter;
4951
        type Item = <IndexMap<K, V> as IntoIterator>::Item;
4952
49.2k
        fn into_iter(self) -> Self::IntoIter {
4953
49.2k
            self.0.into_iter()
4954
49.2k
        }
<wasmparser::validator::component::append_only::IndexMapAppendOnly<wasmparser::validator::component_types::ResourceId, alloc::vec::Vec<usize>> as core::iter::traits::collect::IntoIterator>::into_iter
Line
Count
Source
4952
17.2k
        fn into_iter(self) -> Self::IntoIter {
4953
17.2k
            self.0.into_iter()
4954
17.2k
        }
<wasmparser::validator::component::append_only::IndexMapAppendOnly<wasmparser::validator::component_types::ResourceId, core::option::Option<wasmparser::readers::core::types::ValType>> as core::iter::traits::collect::IntoIterator>::into_iter
Line
Count
Source
4952
32.0k
        fn into_iter(self) -> Self::IntoIter {
4953
32.0k
            self.0.into_iter()
4954
32.0k
        }
4955
    }
4956
}