Coverage Report

Created: 2026-04-09 08:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wasm-tools/crates/wit-component/src/dummy.rs
Line
Count
Source
1
use wit_parser::abi::WasmType;
2
use wit_parser::{
3
    Function, FutureIntrinsic, LiftLowerAbi, ManglingAndAbi, Resolve, ResourceIntrinsic,
4
    StreamIntrinsic, TypeDefKind, TypeId, WasmExport, WasmExportKind, WasmImport, WorldId,
5
    WorldItem, WorldKey,
6
};
7
8
/// Generate a dummy implementation core Wasm module for a given WIT document
9
3.82k
pub fn dummy_module(resolve: &Resolve, world: WorldId, mangling: ManglingAndAbi) -> Vec<u8> {
10
3.82k
    let world = &resolve.worlds[world];
11
3.82k
    let mut wat = String::new();
12
3.82k
    wat.push_str("(module\n");
13
5.12k
    for (name, import) in world.imports.iter() {
14
5.12k
        match import {
15
901
            WorldItem::Function(func) => {
16
901
                push_imported_func(&mut wat, resolve, None, func, mangling);
17
901
            }
18
704
            WorldItem::Interface { id: import, .. } => {
19
951
                for (_, func) in resolve.interfaces[*import].functions.iter() {
20
951
                    push_imported_func(&mut wat, resolve, Some(name), func, mangling);
21
951
                }
22
1.31k
                for (_, ty) in resolve.interfaces[*import].types.iter() {
23
1.31k
                    push_imported_type_intrinsics(&mut wat, resolve, Some(name), *ty, mangling);
24
1.31k
                }
25
            }
26
3.52k
            WorldItem::Type { id, .. } => {
27
3.52k
                push_imported_type_intrinsics(&mut wat, resolve, None, *id, mangling);
28
3.52k
            }
29
        }
30
    }
31
32
3.82k
    if mangling.is_async() {
33
562
        push_root_async_intrinsics(&mut wat);
34
3.25k
    }
35
36
    // Append any intrinsics which are imported but used in exported items
37
    // (e.g. resources)
38
3.82k
    for (name, export) in world.exports.iter() {
39
747
        match export {
40
348
            WorldItem::Function(func) => {
41
348
                push_exported_func_intrinsics(&mut wat, resolve, None, func, mangling);
42
348
            }
43
399
            WorldItem::Interface { id: export, .. } => {
44
785
                for (_, func) in resolve.interfaces[*export].functions.iter() {
45
785
                    push_exported_func_intrinsics(&mut wat, resolve, Some(name), func, mangling);
46
785
                }
47
511
                for (_, ty) in resolve.interfaces[*export].types.iter() {
48
511
                    push_exported_type_intrinsics(&mut wat, resolve, Some(name), *ty, mangling);
49
511
                }
50
            }
51
0
            WorldItem::Type { .. } => {}
52
        }
53
    }
54
55
3.82k
    for (name, export) in world.exports.iter() {
56
747
        match export {
57
348
            WorldItem::Function(func) => {
58
348
                push_func_export(&mut wat, resolve, None, func, mangling);
59
348
            }
60
399
            WorldItem::Interface { id: export, .. } => {
61
785
                for (_, func) in resolve.interfaces[*export].functions.iter() {
62
785
                    push_func_export(&mut wat, resolve, Some(name), func, mangling);
63
785
                }
64
511
                for (_, ty) in resolve.interfaces[*export].types.iter() {
65
511
                    push_exported_resource_functions(&mut wat, resolve, name, *ty, mangling);
66
511
                }
67
            }
68
0
            WorldItem::Type { .. } => {}
69
        }
70
    }
71
72
3.82k
    let memory = resolve.wasm_export_name(mangling, WasmExport::Memory);
73
3.82k
    wat.push_str(&format!("(memory (export {memory:?}) 0)\n"));
74
3.82k
    let realloc = resolve.wasm_export_name(mangling, WasmExport::Realloc);
75
3.82k
    wat.push_str(&format!(
76
3.82k
        "(func (export {realloc:?}) (param i32 i32 i32 i32) (result i32) unreachable)\n"
77
3.82k
    ));
78
79
3.82k
    let initialize = resolve.wasm_export_name(mangling, WasmExport::Initialize);
80
3.82k
    wat.push_str(&format!("(func (export {initialize:?}))"));
81
3.82k
    wat.push_str(")\n");
82
83
3.82k
    return wat::parse_str(&wat).unwrap();
84
3.82k
}
85
86
1.85k
fn push_imported_func(
87
1.85k
    wat: &mut String,
88
1.85k
    resolve: &Resolve,
89
1.85k
    interface: Option<&WorldKey>,
90
1.85k
    func: &Function,
91
1.85k
    mangling: ManglingAndAbi,
92
1.85k
) {
93
1.85k
    let sig = resolve.wasm_signature(mangling.import_variant(), func);
94
95
1.85k
    let (module, name) = resolve.wasm_import_name(mangling, WasmImport::Func { interface, func });
96
1.85k
    wat.push_str(&format!("(import {module:?} {name:?} (func"));
97
1.85k
    push_tys(wat, "param", &sig.params);
98
1.85k
    push_tys(wat, "result", &sig.results);
99
1.85k
    wat.push_str("))\n");
100
101
1.85k
    if mangling.is_async() {
102
281
        push_imported_future_and_stream_intrinsics(wat, resolve, mangling, false, interface, func);
103
1.57k
    }
104
1.85k
}
105
106
4.83k
fn push_imported_type_intrinsics(
107
4.83k
    wat: &mut String,
108
4.83k
    resolve: &Resolve,
109
4.83k
    interface: Option<&WorldKey>,
110
4.83k
    resource: TypeId,
111
4.83k
    mangling: ManglingAndAbi,
112
4.83k
) {
113
4.83k
    let ty = &resolve.types[resource];
114
4.83k
    match ty.kind {
115
        TypeDefKind::Resource => {
116
261
            let (module, name) = resolve.wasm_import_name(
117
261
                // Force using a sync ABI here at this time as support for async
118
261
                // resource drop isn't implemented yet.
119
261
                mangling.sync(),
120
261
                WasmImport::ResourceIntrinsic {
121
261
                    interface,
122
261
                    resource,
123
261
                    intrinsic: ResourceIntrinsic::ImportedDrop,
124
261
                },
125
261
            );
126
261
            wat.push_str(&format!("(import {module:?} {name:?} (func (param i32)))"));
127
128
261
            if mangling.is_async() {
129
38
                // TODO: when wit-component supports async resource drop,
130
38
                // implement it here too.
131
38
                // let name = format!("[async-lower]{name}");
132
38
                // wat.push_str(&format!("(import {module:?} {name:?} (func (param i32)))"));
133
223
            }
134
        }
135
136
        // No other types with intrinsics at this time (futures/streams are
137
        // relative to where they show up in function types.
138
4.57k
        _ => {}
139
    }
140
4.83k
}
141
142
1.13k
fn push_exported_func_intrinsics(
143
1.13k
    wat: &mut String,
144
1.13k
    resolve: &Resolve,
145
1.13k
    interface: Option<&WorldKey>,
146
1.13k
    func: &Function,
147
1.13k
    mangling: ManglingAndAbi,
148
1.13k
) {
149
1.13k
    if !mangling.is_async() {
150
902
        return;
151
231
    }
152
153
    // For exported async functions, generate a `task.return` intrinsic.
154
231
    let (module, name, sig) = func.task_return_import(resolve, interface, mangling.mangling());
155
231
    wat.push_str(&format!("(import {module:?} {name:?} (func"));
156
231
    push_tys(wat, "param", &sig.params);
157
231
    push_tys(wat, "result", &sig.results);
158
231
    wat.push_str("))\n");
159
160
231
    push_imported_future_and_stream_intrinsics(wat, resolve, mangling, true, interface, func);
161
1.13k
}
162
163
512
fn push_imported_future_and_stream_intrinsics(
164
512
    wat: &mut String,
165
512
    resolve: &Resolve,
166
512
    mangling: ManglingAndAbi,
167
512
    exported: bool,
168
512
    interface: Option<&WorldKey>,
169
512
    func: &Function,
170
512
) {
171
512
    for id in func.find_futures_and_streams(resolve).into_iter() {
172
140
        match &resolve.types[id].kind {
173
            TypeDefKind::Future(_) => {
174
22
                let mut module = None;
175
242
                let mut intrinsic_name = |intrinsic, async_| {
176
242
                    let (m, name) = resolve.wasm_import_name(
177
242
                        mangling,
178
242
                        WasmImport::FutureIntrinsic {
179
242
                            interface,
180
242
                            func,
181
242
                            ty: Some(id),
182
242
                            intrinsic,
183
242
                            exported,
184
242
                            async_,
185
242
                        },
186
242
                    );
187
242
                    if let Some(prev) = &module {
188
220
                        debug_assert_eq!(prev, &m);
189
22
                    } else {
190
22
                        module = Some(m);
191
22
                    }
192
242
                    name
193
242
                };
194
195
22
                let new = intrinsic_name(FutureIntrinsic::New, false);
196
22
                let read = intrinsic_name(FutureIntrinsic::Read, false);
197
22
                let write = intrinsic_name(FutureIntrinsic::Write, false);
198
22
                let cancel_read = intrinsic_name(FutureIntrinsic::CancelRead, false);
199
22
                let cancel_write = intrinsic_name(FutureIntrinsic::CancelWrite, false);
200
22
                let drop_readable = intrinsic_name(FutureIntrinsic::DropReadable, false);
201
22
                let drop_writable = intrinsic_name(FutureIntrinsic::DropWritable, false);
202
22
                let async_read = intrinsic_name(FutureIntrinsic::Read, true);
203
22
                let async_write = intrinsic_name(FutureIntrinsic::Write, true);
204
22
                let async_cancel_read = intrinsic_name(FutureIntrinsic::CancelRead, true);
205
22
                let async_cancel_write = intrinsic_name(FutureIntrinsic::CancelWrite, true);
206
22
                let module = module.unwrap();
207
208
22
                wat.push_str(&format!(
209
22
                    r#"
210
22
(import {module:?} {new:?} (func (result i64)))
211
22
(import {module:?} {read:?} (func (param i32 i32) (result i32)))
212
22
(import {module:?} {write:?} (func (param i32 i32) (result i32)))
213
22
(import {module:?} {cancel_read:?} (func (param i32) (result i32)))
214
22
(import {module:?} {cancel_write:?} (func (param i32) (result i32)))
215
22
(import {module:?} {drop_readable:?} (func (param i32)))
216
22
(import {module:?} {drop_writable:?} (func (param i32)))
217
22
(import {module:?} {async_read:?} (func (param i32 i32) (result i32)))
218
22
(import {module:?} {async_write:?} (func (param i32 i32) (result i32)))
219
22
220
22
;; deferred behind ๐Ÿš
221
22
;;(import {module:?} {async_cancel_read:?} (func (param i32) (result i32)))
222
22
;;(import {module:?} {async_cancel_write:?} (func (param i32) (result i32)))
223
22
"#
224
22
                ));
225
            }
226
            TypeDefKind::Stream(_) => {
227
118
                let mut module = None;
228
1.29k
                let mut intrinsic_name = |intrinsic, async_| {
229
1.29k
                    let (m, name) = resolve.wasm_import_name(
230
1.29k
                        mangling,
231
1.29k
                        WasmImport::StreamIntrinsic {
232
1.29k
                            interface,
233
1.29k
                            func,
234
1.29k
                            ty: Some(id),
235
1.29k
                            intrinsic,
236
1.29k
                            exported,
237
1.29k
                            async_,
238
1.29k
                        },
239
1.29k
                    );
240
1.29k
                    if let Some(prev) = &module {
241
1.18k
                        debug_assert_eq!(prev, &m);
242
118
                    } else {
243
118
                        module = Some(m);
244
118
                    }
245
1.29k
                    name
246
1.29k
                };
247
248
118
                let new = intrinsic_name(StreamIntrinsic::New, false);
249
118
                let read = intrinsic_name(StreamIntrinsic::Read, false);
250
118
                let write = intrinsic_name(StreamIntrinsic::Write, false);
251
118
                let cancel_read = intrinsic_name(StreamIntrinsic::CancelRead, false);
252
118
                let cancel_write = intrinsic_name(StreamIntrinsic::CancelWrite, false);
253
118
                let drop_readable = intrinsic_name(StreamIntrinsic::DropReadable, false);
254
118
                let drop_writable = intrinsic_name(StreamIntrinsic::DropWritable, false);
255
118
                let async_read = intrinsic_name(StreamIntrinsic::Read, true);
256
118
                let async_write = intrinsic_name(StreamIntrinsic::Write, true);
257
118
                let async_cancel_read = intrinsic_name(StreamIntrinsic::CancelRead, true);
258
118
                let async_cancel_write = intrinsic_name(StreamIntrinsic::CancelWrite, true);
259
118
                let module = module.unwrap();
260
261
118
                wat.push_str(&format!(
262
118
                    r#"
263
118
(import {module:?} {new:?} (func (result i64)))
264
118
(import {module:?} {read:?} (func (param i32 i32 i32) (result i32)))
265
118
(import {module:?} {write:?} (func (param i32 i32 i32) (result i32)))
266
118
(import {module:?} {cancel_read:?} (func (param i32) (result i32)))
267
118
(import {module:?} {cancel_write:?} (func (param i32) (result i32)))
268
118
(import {module:?} {drop_readable:?} (func (param i32)))
269
118
(import {module:?} {drop_writable:?} (func (param i32)))
270
118
(import {module:?} {async_read:?} (func (param i32 i32 i32) (result i32)))
271
118
(import {module:?} {async_write:?} (func (param i32 i32 i32) (result i32)))
272
118
273
118
;; deferred behind ๐Ÿš
274
118
;;(import {module:?} {async_cancel_read:?} (func (param i32) (result i32)))
275
118
;;(import {module:?} {async_cancel_write:?} (func (param i32) (result i32)))
276
118
"#
277
118
                ));
278
            }
279
0
            _ => unreachable!(),
280
        }
281
    }
282
512
}
283
284
511
fn push_exported_type_intrinsics(
285
511
    wat: &mut String,
286
511
    resolve: &Resolve,
287
511
    interface: Option<&WorldKey>,
288
511
    resource: TypeId,
289
511
    mangling: ManglingAndAbi,
290
511
) {
291
511
    let ty = &resolve.types[resource];
292
511
    match ty.kind {
293
        TypeDefKind::Resource => {
294
84
            let intrinsics = [
295
84
                (ResourceIntrinsic::ExportedDrop, "(func (param i32))"),
296
84
                (
297
84
                    ResourceIntrinsic::ExportedNew,
298
84
                    "(func (param i32) (result i32))",
299
84
                ),
300
84
                (
301
84
                    ResourceIntrinsic::ExportedRep,
302
84
                    "(func (param i32) (result i32))",
303
84
                ),
304
84
            ];
305
252
            for (intrinsic, sig) in intrinsics {
306
252
                let (module, name) = resolve.wasm_import_name(
307
252
                    mangling.sync(),
308
252
                    WasmImport::ResourceIntrinsic {
309
252
                        interface,
310
252
                        resource,
311
252
                        intrinsic,
312
252
                    },
313
252
                );
314
252
                wat.push_str(&format!("(import {module:?} {name:?} {sig})\n"));
315
252
            }
316
        }
317
318
        // No other types with intrinsics at this time (futures/streams
319
        // relative to where they are in a function).
320
427
        _ => {}
321
    }
322
511
}
323
324
511
fn push_exported_resource_functions(
325
511
    wat: &mut String,
326
511
    resolve: &Resolve,
327
511
    interface: &WorldKey,
328
511
    resource: TypeId,
329
511
    mangling: ManglingAndAbi,
330
511
) {
331
511
    let ty = &resolve.types[resource];
332
511
    match ty.kind {
333
84
        TypeDefKind::Resource => {}
334
427
        _ => return,
335
    }
336
    // Feign destructors for any resource that this interface
337
    // exports
338
84
    let name = resolve.wasm_export_name(
339
84
        mangling,
340
84
        WasmExport::ResourceDtor {
341
84
            interface,
342
84
            resource,
343
84
        },
344
    );
345
84
    wat.push_str(&format!("(func (export {name:?}) (param i32))"));
346
511
}
347
348
1.13k
fn push_func_export(
349
1.13k
    wat: &mut String,
350
1.13k
    resolve: &Resolve,
351
1.13k
    interface: Option<&WorldKey>,
352
1.13k
    func: &Function,
353
1.13k
    mangling: ManglingAndAbi,
354
1.13k
) {
355
1.13k
    let sig = resolve.wasm_signature(mangling.export_variant(), func);
356
1.13k
    let name = resolve.wasm_export_name(
357
1.13k
        mangling,
358
1.13k
        WasmExport::Func {
359
1.13k
            interface,
360
1.13k
            func,
361
1.13k
            kind: WasmExportKind::Normal,
362
1.13k
        },
363
    );
364
1.13k
    wat.push_str(&format!("(func (export \"{name}\")"));
365
1.13k
    push_tys(wat, "param", &sig.params);
366
1.13k
    push_tys(wat, "result", &sig.results);
367
1.13k
    wat.push_str(" unreachable)\n");
368
369
1.02k
    match mangling {
370
902
        ManglingAndAbi::Standard32 | ManglingAndAbi::Legacy(LiftLowerAbi::Sync) => {
371
902
            let name = resolve.wasm_export_name(
372
902
                mangling,
373
902
                WasmExport::Func {
374
902
                    interface,
375
902
                    func,
376
902
                    kind: WasmExportKind::PostReturn,
377
902
                },
378
902
            );
379
902
            wat.push_str(&format!("(func (export \"{name}\")"));
380
902
            push_tys(wat, "param", &sig.results);
381
902
            wat.push_str(")\n");
382
902
        }
383
166
        ManglingAndAbi::Legacy(LiftLowerAbi::AsyncCallback) => {
384
166
            let name = resolve.wasm_export_name(
385
166
                mangling,
386
166
                WasmExport::Func {
387
166
                    interface,
388
166
                    func,
389
166
                    kind: WasmExportKind::Callback,
390
166
                },
391
166
            );
392
166
            wat.push_str(&format!(
393
166
                "(func (export \"{name}\") (param i32 i32 i32) (result i32) unreachable)\n"
394
166
            ));
395
166
        }
396
65
        ManglingAndAbi::Legacy(LiftLowerAbi::AsyncStackful) => {}
397
    }
398
1.13k
}
399
400
7.33k
fn push_tys(dst: &mut String, desc: &str, params: &[WasmType]) {
401
7.33k
    if params.is_empty() {
402
2.01k
        return;
403
5.32k
    }
404
5.32k
    dst.push_str(" (");
405
5.32k
    dst.push_str(desc);
406
10.9k
    for ty in params {
407
10.9k
        dst.push(' ');
408
10.9k
        match ty {
409
8.61k
            WasmType::I32 => dst.push_str("i32"),
410
608
            WasmType::I64 => dst.push_str("i64"),
411
382
            WasmType::F32 => dst.push_str("f32"),
412
256
            WasmType::F64 => dst.push_str("f64"),
413
940
            WasmType::Pointer => dst.push_str("i32"),
414
4
            WasmType::PointerOrI64 => dst.push_str("i64"),
415
181
            WasmType::Length => dst.push_str("i32"),
416
        }
417
    }
418
5.32k
    dst.push(')');
419
7.33k
}
420
421
562
fn push_root_async_intrinsics(dst: &mut String) {
422
562
    dst.push_str(
423
562
        r#"
424
562
(import "[export]$root" "[task-cancel]" (func))
425
562
(import "$root" "[backpressure-inc]" (func))
426
562
(import "$root" "[backpressure-dec]" (func))
427
562
(import "$root" "[waitable-set-new]" (func (result i32)))
428
562
(import "$root" "[waitable-set-wait]" (func (param i32 i32) (result i32)))
429
562
(import "$root" "[waitable-set-poll]" (func (param i32 i32) (result i32)))
430
562
(import "$root" "[waitable-set-drop]" (func (param i32)))
431
562
(import "$root" "[waitable-join]" (func (param i32 i32)))
432
562
(import "$root" "[thread-yield]" (func (result i32)))
433
562
(import "$root" "[subtask-drop]" (func (param i32)))
434
562
(import "$root" "[subtask-cancel]" (func (param i32) (result i32)))
435
562
(import "$root" "[context-get-0]" (func (result i32)))
436
562
(import "$root" "[context-set-0]" (func (param i32)))
437
562
438
562
;; deferred behind ๐Ÿงต upstream
439
562
;;(import "$root" "[cancellable][waitable-set-wait]" (func (param i32 i32) (result i32)))
440
562
;;(import "$root" "[cancellable][waitable-set-poll]" (func (param i32 i32) (result i32)))
441
562
;;(import "$root" "[cancellable][thread-yield]" (func (result i32)))
442
562
;;(import "$root" "[context-get-1]" (func (result i32)))
443
562
;;(import "$root" "[context-set-1]" (func (param i32)))
444
562
445
562
;; deferred behind ๐Ÿ“ upstream
446
562
;;(import "$root" "[error-context-new-utf8]" (func (param i32 i32) (result i32)))
447
562
;;(import "$root" "[error-context-new-utf16]" (func (param i32 i32) (result i32)))
448
562
;;(import "$root" "[error-context-new-latin1+utf16]" (func (param i32 i32) (result i32)))
449
562
;;(import "$root" "[error-context-debug-message-utf8]" (func (param i32 i32)))
450
562
;;(import "$root" "[error-context-debug-message-utf16]" (func (param i32 i32)))
451
562
;;(import "$root" "[error-context-debug-message-latin1+utf16]" (func (param i32 i32)))
452
562
;;(import "$root" "[error-context-drop]" (func (param i32)))
453
562
"#,
454
    );
455
562
}