Coverage Report

Created: 2026-02-23 07:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wasm-tools/crates/wit-parser/src/lib.rs
Line
Count
Source
1
#![no_std]
2
3
extern crate alloc;
4
5
#[cfg(feature = "std")]
6
extern crate std;
7
8
use crate::abi::AbiVariant;
9
use alloc::format;
10
use alloc::string::{String, ToString};
11
use alloc::vec::Vec;
12
#[cfg(feature = "std")]
13
use anyhow::Context;
14
use anyhow::{Result, bail};
15
use id_arena::{Arena, Id};
16
use semver::Version;
17
18
#[cfg(feature = "std")]
19
pub type IndexMap<K, V> = indexmap::IndexMap<K, V, std::hash::RandomState>;
20
#[cfg(feature = "std")]
21
pub type IndexSet<T> = indexmap::IndexSet<T, std::hash::RandomState>;
22
#[cfg(not(feature = "std"))]
23
pub type IndexMap<K, V> = indexmap::IndexMap<K, V, hashbrown::DefaultHashBuilder>;
24
#[cfg(not(feature = "std"))]
25
pub type IndexSet<T> = indexmap::IndexSet<T, hashbrown::DefaultHashBuilder>;
26
27
#[cfg(feature = "std")]
28
pub(crate) use std::collections::{HashMap, HashSet};
29
30
#[cfg(not(feature = "std"))]
31
pub(crate) use hashbrown::{HashMap, HashSet};
32
33
use alloc::borrow::Cow;
34
use core::fmt;
35
use core::hash::{Hash, Hasher};
36
#[cfg(feature = "std")]
37
use std::path::Path;
38
39
#[cfg(feature = "decoding")]
40
pub mod decoding;
41
#[cfg(feature = "decoding")]
42
mod metadata;
43
#[cfg(feature = "decoding")]
44
pub use metadata::PackageMetadata;
45
46
pub mod abi;
47
mod ast;
48
pub use ast::SourceMap;
49
pub use ast::lex::Span;
50
pub use ast::{ParsedUsePath, parse_use_path};
51
mod sizealign;
52
pub use sizealign::*;
53
mod resolve;
54
pub use resolve::*;
55
mod live;
56
pub use live::{LiveTypes, TypeIdVisitor};
57
58
#[cfg(feature = "serde")]
59
use serde_derive::Serialize;
60
#[cfg(feature = "serde")]
61
mod serde_;
62
#[cfg(feature = "serde")]
63
use serde_::*;
64
65
/// Checks if the given string is a legal identifier in wit.
66
0
pub fn validate_id(s: &str) -> Result<()> {
67
0
    ast::validate_id(0, s)?;
68
0
    Ok(())
69
0
}
70
71
pub type WorldId = Id<World>;
72
pub type InterfaceId = Id<Interface>;
73
pub type TypeId = Id<TypeDef>;
74
75
/// Representation of a parsed WIT package which has not resolved external
76
/// dependencies yet.
77
///
78
/// This representation has performed internal resolution of the WIT package
79
/// itself, ensuring that all references internally are valid and the WIT was
80
/// syntactically valid and such.
81
///
82
/// The fields of this structure represent a flat list of arrays unioned from
83
/// all documents within the WIT package. This means, for example, that all
84
/// types from all documents are located in `self.types`. The fields of each
85
/// item can help splitting back out into packages/interfaces/etc as necessary.
86
///
87
/// Note that an `UnresolvedPackage` cannot be queried in general about
88
/// information such as size or alignment as that would require resolution of
89
/// foreign dependencies. Translations such as to-binary additionally are not
90
/// supported on an `UnresolvedPackage` due to the lack of knowledge about the
91
/// foreign types. This is intended to be an intermediate state which can be
92
/// inspected by embedders, if necessary, before quickly transforming to a
93
/// [`Resolve`] to fully work with a WIT package.
94
///
95
/// After an [`UnresolvedPackage`] is parsed it can be fully resolved with
96
/// [`Resolve::push`]. During this operation a dependency map is specified which
97
/// will connect the `foreign_deps` field of this structure to packages
98
/// previously inserted within the [`Resolve`]. Embedders are responsible for
99
/// performing this resolution themselves.
100
#[derive(Clone)]
101
pub struct UnresolvedPackage {
102
    /// The namespace, name, and version information for this package.
103
    pub name: PackageName,
104
105
    /// All worlds from all documents within this package.
106
    ///
107
    /// Each world lists the document that it is from.
108
    pub worlds: Arena<World>,
109
110
    /// All interfaces from all documents within this package.
111
    ///
112
    /// Each interface lists the document that it is from. Interfaces are listed
113
    /// in topological order as well so iteration through this arena will only
114
    /// reference prior elements already visited when working with recursive
115
    /// references.
116
    pub interfaces: Arena<Interface>,
117
118
    /// All types from all documents within this package.
119
    ///
120
    /// Each type lists the interface or world that defined it, or nothing if
121
    /// it's an anonymous type. Types are listed in this arena in topological
122
    /// order to ensure that iteration through this arena will only reference
123
    /// other types transitively that are already iterated over.
124
    pub types: Arena<TypeDef>,
125
126
    /// All foreign dependencies that this package depends on.
127
    ///
128
    /// These foreign dependencies must be resolved to convert this unresolved
129
    /// package into a `Resolve`. The map here is keyed by the name of the
130
    /// foreign package that this depends on, and the sub-map is keyed by an
131
    /// interface name followed by the identifier within `self.interfaces`. The
132
    /// fields of `self.interfaces` describes the required types that are from
133
    /// each foreign interface.
134
    pub foreign_deps: IndexMap<PackageName, IndexMap<String, (AstItem, Vec<Stability>)>>,
135
136
    /// Doc comments for this package.
137
    pub docs: Docs,
138
139
    #[cfg_attr(not(feature = "std"), allow(dead_code))]
140
    package_name_span: Span,
141
    unknown_type_spans: Vec<Span>,
142
    foreign_dep_spans: Vec<Span>,
143
    required_resource_types: Vec<(TypeId, Span)>,
144
}
145
146
impl UnresolvedPackage {
147
    /// Adjusts all spans in this package by adding the given byte offset.
148
    ///
149
    /// This is used when merging source maps to update spans to point to the
150
    /// correct location in the combined source map.
151
13.0k
    pub(crate) fn adjust_spans(&mut self, offset: u32) {
152
        // Adjust parallel vec spans
153
13.0k
        self.package_name_span.adjust(offset);
154
13.0k
        for span in &mut self.unknown_type_spans {
155
2.10k
            span.adjust(offset);
156
2.10k
        }
157
13.0k
        for span in &mut self.foreign_dep_spans {
158
2.05k
            span.adjust(offset);
159
2.05k
        }
160
13.0k
        for (_, span) in &mut self.required_resource_types {
161
16
            span.adjust(offset);
162
16
        }
163
164
        // Adjust spans on arena items
165
16.8k
        for (_, world) in self.worlds.iter_mut() {
166
16.8k
            world.adjust_spans(offset);
167
16.8k
        }
168
56.5k
        for (_, iface) in self.interfaces.iter_mut() {
169
56.5k
            iface.adjust_spans(offset);
170
56.5k
        }
171
142k
        for (_, ty) in self.types.iter_mut() {
172
142k
            ty.adjust_spans(offset);
173
142k
        }
174
13.0k
    }
175
}
176
177
/// Tracks a set of packages, all pulled from the same group of WIT source files.
178
#[derive(Clone)]
179
pub struct UnresolvedPackageGroup {
180
    /// The "main" package in this package group which was found at the root of
181
    /// the WIT files.
182
    ///
183
    /// Note that this is required to be present in all WIT files.
184
    pub main: UnresolvedPackage,
185
186
    /// Nested packages found while parsing `main`, if any.
187
    pub nested: Vec<UnresolvedPackage>,
188
189
    /// A set of processed source files from which these packages have been parsed.
190
    pub source_map: SourceMap,
191
}
192
193
#[derive(Debug, Copy, Clone)]
194
#[cfg_attr(feature = "serde", derive(Serialize))]
195
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
196
pub enum AstItem {
197
    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
198
    Interface(InterfaceId),
199
    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
200
    World(WorldId),
201
}
202
203
/// A structure used to keep track of the name of a package, containing optional
204
/// information such as a namespace and version information.
205
///
206
/// This is directly encoded as an "ID" in the binary component representation
207
/// with an interfaced tacked on as well.
208
#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
209
#[cfg_attr(feature = "serde", derive(Serialize))]
210
#[cfg_attr(feature = "serde", serde(into = "String"))]
211
pub struct PackageName {
212
    /// A namespace such as `wasi` in `wasi:foo/bar`
213
    pub namespace: String,
214
    /// The kebab-name of this package, which is always specified.
215
    pub name: String,
216
    /// Optional major/minor version information.
217
    pub version: Option<Version>,
218
}
219
220
impl From<PackageName> for String {
221
0
    fn from(name: PackageName) -> String {
222
0
        name.to_string()
223
0
    }
224
}
225
226
impl PackageName {
227
    /// Returns the ID that this package name would assign the `interface` name
228
    /// specified.
229
17.3k
    pub fn interface_id(&self, interface: &str) -> String {
230
17.3k
        let mut s = String::new();
231
17.3k
        s.push_str(&format!("{}:{}/{interface}", self.namespace, self.name));
232
17.3k
        if let Some(version) = &self.version {
233
10.6k
            s.push_str(&format!("@{version}"));
234
10.6k
        }
235
17.3k
        s
236
17.3k
    }
237
238
    /// Determines the "semver compatible track" for the given version.
239
    ///
240
    /// This method implements the logic from the component model where semver
241
    /// versions can be compatible with one another. For example versions 1.2.0
242
    /// and 1.2.1 would be considered both compatible with one another because
243
    /// they're on the same semver compatible track.
244
    ///
245
    /// This predicate is used during
246
    /// [`Resolve::merge_world_imports_based_on_semver`] for example to
247
    /// determine whether two imports can be merged together. This is
248
    /// additionally used when creating components to match up imports in
249
    /// core wasm to imports in worlds.
250
411
    pub fn version_compat_track(version: &Version) -> Version {
251
411
        let mut version = version.clone();
252
411
        version.build = semver::BuildMetadata::EMPTY;
253
411
        if !version.pre.is_empty() {
254
372
            return version;
255
39
        }
256
39
        if version.major != 0 {
257
33
            version.minor = 0;
258
33
            version.patch = 0;
259
33
            return version;
260
6
        }
261
6
        if version.minor != 0 {
262
5
            version.patch = 0;
263
5
            return version;
264
1
        }
265
1
        version
266
411
    }
267
268
    /// Returns the string corresponding to
269
    /// [`PackageName::version_compat_track`]. This is done to match the
270
    /// component model's expected naming scheme of imports and exports.
271
92
    pub fn version_compat_track_string(version: &Version) -> String {
272
92
        let version = Self::version_compat_track(version);
273
92
        if !version.pre.is_empty() {
274
90
            return version.to_string();
275
2
        }
276
2
        if version.major != 0 {
277
2
            return format!("{}", version.major);
278
0
        }
279
0
        if version.minor != 0 {
280
0
            return format!("{}.{}", version.major, version.minor);
281
0
        }
282
0
        version.to_string()
283
92
    }
284
}
285
286
impl fmt::Display for PackageName {
287
6.80k
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
288
6.80k
        write!(f, "{}:{}", self.namespace, self.name)?;
289
6.80k
        if let Some(version) = &self.version {
290
5.10k
            write!(f, "@{version}")?;
291
1.69k
        }
292
6.80k
        Ok(())
293
6.80k
    }
294
}
295
296
#[derive(Debug)]
297
struct Error {
298
    span: Span,
299
    msg: String,
300
    highlighted: Option<String>,
301
}
302
303
impl Error {
304
0
    fn new(span: Span, msg: impl Into<String>) -> Error {
305
0
        Error {
306
0
            span,
307
0
            msg: msg.into(),
308
0
            highlighted: None,
309
0
        }
310
0
    }
Unexecuted instantiation: <wit_parser::Error>::new::<alloc::string::String>
Unexecuted instantiation: <wit_parser::Error>::new::<&str>
311
312
    /// Highlights this error using the given source map, if the span is known.
313
0
    fn highlight(&mut self, source_map: &ast::SourceMap) {
314
0
        if self.highlighted.is_none() {
315
0
            self.highlighted = source_map.highlight_span(self.span, &self.msg);
316
0
        }
317
0
    }
318
}
319
320
impl fmt::Display for Error {
321
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
322
0
        self.highlighted.as_ref().unwrap_or(&self.msg).fmt(f)
323
0
    }
324
}
325
326
impl core::error::Error for Error {}
327
328
#[derive(Debug)]
329
struct PackageNotFoundError {
330
    span: Span,
331
    requested: PackageName,
332
    known: Vec<PackageName>,
333
    highlighted: Option<String>,
334
}
335
336
impl PackageNotFoundError {
337
0
    pub fn new(span: Span, requested: PackageName, known: Vec<PackageName>) -> Self {
338
0
        Self {
339
0
            span,
340
0
            requested,
341
0
            known,
342
0
            highlighted: None,
343
0
        }
344
0
    }
345
346
    /// Highlights this error using the given source map, if the span is known.
347
0
    fn highlight(&mut self, source_map: &ast::SourceMap) {
348
0
        if self.highlighted.is_none() {
349
0
            self.highlighted = source_map.highlight_span(self.span, &format!("{self}"));
350
0
        }
351
0
    }
352
}
353
354
impl fmt::Display for PackageNotFoundError {
355
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
356
0
        if let Some(highlighted) = &self.highlighted {
357
0
            return highlighted.fmt(f);
358
0
        }
359
0
        if self.known.is_empty() {
360
0
            write!(
361
0
                f,
362
                "package '{}' not found. no known packages.",
363
                self.requested
364
0
            )?;
365
        } else {
366
0
            write!(
367
0
                f,
368
                "package '{}' not found. known packages:\n",
369
                self.requested
370
0
            )?;
371
0
            for known in self.known.iter() {
372
0
                write!(f, "    {known}\n")?;
373
            }
374
        }
375
0
        Ok(())
376
0
    }
377
}
378
379
impl core::error::Error for PackageNotFoundError {}
380
381
impl UnresolvedPackageGroup {
382
    /// Parses the given string as a wit document.
383
    ///
384
    /// The `path` argument is used for error reporting. The `contents` provided
385
    /// are considered to be the contents of `path`. This function does not read
386
    /// the filesystem.
387
    #[cfg(feature = "std")]
388
0
    pub fn parse(path: impl AsRef<Path>, contents: &str) -> Result<UnresolvedPackageGroup> {
389
0
        let path = path
390
0
            .as_ref()
391
0
            .to_str()
392
0
            .ok_or_else(|| anyhow::anyhow!("path is not valid utf-8: {:?}", path.as_ref()))?;
393
0
        Self::parse_str(path, contents)
394
0
    }
395
396
    /// Parses the given string as a wit document.
397
    ///
398
    /// The `path` argument is used for error reporting. The `contents` provided
399
    /// are considered to be the contents of `path`. This function does not read
400
    /// the filesystem.
401
5.20k
    pub fn parse_str(path: &str, contents: &str) -> Result<UnresolvedPackageGroup> {
402
5.20k
        let mut map = SourceMap::default();
403
5.20k
        map.push_str(path, contents);
404
5.20k
        map.parse()
405
5.20k
    }
406
407
    /// Parse a WIT package at the provided path.
408
    ///
409
    /// The path provided is inferred whether it's a file or a directory. A file
410
    /// is parsed with [`UnresolvedPackageGroup::parse_file`] and a directory is
411
    /// parsed with [`UnresolvedPackageGroup::parse_dir`].
412
    #[cfg(feature = "std")]
413
0
    pub fn parse_path(path: impl AsRef<Path>) -> Result<UnresolvedPackageGroup> {
414
0
        let path = path.as_ref();
415
0
        if path.is_dir() {
416
0
            UnresolvedPackageGroup::parse_dir(path)
417
        } else {
418
0
            UnresolvedPackageGroup::parse_file(path)
419
        }
420
0
    }
421
422
    /// Parses a WIT package from the file provided.
423
    ///
424
    /// The return value represents all packages found in the WIT file which
425
    /// might be either one or multiple depending on the syntax used.
426
    #[cfg(feature = "std")]
427
0
    pub fn parse_file(path: impl AsRef<Path>) -> Result<UnresolvedPackageGroup> {
428
0
        let path = path.as_ref();
429
0
        let contents = std::fs::read_to_string(path)
430
0
            .with_context(|| format!("failed to read file {path:?}"))?;
431
0
        Self::parse(path, &contents)
432
0
    }
433
434
    /// Parses a WIT package from the directory provided.
435
    ///
436
    /// This method will look at all files under the `path` specified. All
437
    /// `*.wit` files are parsed and assumed to be part of the same package
438
    /// grouping. This is useful when a WIT package is split across multiple
439
    /// files.
440
    #[cfg(feature = "std")]
441
0
    pub fn parse_dir(path: impl AsRef<Path>) -> Result<UnresolvedPackageGroup> {
442
0
        let path = path.as_ref();
443
0
        let mut map = SourceMap::default();
444
0
        let cx = || format!("failed to read directory {path:?}");
Unexecuted instantiation: <wit_parser::UnresolvedPackageGroup>::parse_dir::<&std::path::Path>::{closure#0}
Unexecuted instantiation: <wit_parser::UnresolvedPackageGroup>::parse_dir::<&std::path::PathBuf>::{closure#0}
445
0
        for entry in path.read_dir().with_context(&cx)? {
446
0
            let entry = entry.with_context(&cx)?;
447
0
            let path = entry.path();
448
0
            let ty = entry.file_type().with_context(&cx)?;
449
0
            if ty.is_dir() {
450
0
                continue;
451
0
            }
452
0
            if ty.is_symlink() {
453
0
                if path.is_dir() {
454
0
                    continue;
455
0
                }
456
0
            }
457
0
            let filename = match path.file_name().and_then(|s| s.to_str()) {
Unexecuted instantiation: <wit_parser::UnresolvedPackageGroup>::parse_dir::<&std::path::Path>::{closure#1}
Unexecuted instantiation: <wit_parser::UnresolvedPackageGroup>::parse_dir::<&std::path::PathBuf>::{closure#1}
458
0
                Some(name) => name,
459
0
                None => continue,
460
            };
461
0
            if !filename.ends_with(".wit") {
462
0
                continue;
463
0
            }
464
0
            map.push_file(&path)?;
465
        }
466
0
        map.parse()
467
0
    }
Unexecuted instantiation: <wit_parser::UnresolvedPackageGroup>::parse_dir::<&std::path::Path>
Unexecuted instantiation: <wit_parser::UnresolvedPackageGroup>::parse_dir::<&std::path::PathBuf>
468
}
469
470
#[derive(Debug, Clone)]
471
#[cfg_attr(feature = "serde", derive(Serialize))]
472
pub struct World {
473
    /// The WIT identifier name of this world.
474
    pub name: String,
475
476
    /// All imported items into this interface, both worlds and functions.
477
    pub imports: IndexMap<WorldKey, WorldItem>,
478
479
    /// All exported items from this interface, both worlds and functions.
480
    pub exports: IndexMap<WorldKey, WorldItem>,
481
482
    /// The package that owns this world.
483
    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_optional_id"))]
484
    pub package: Option<PackageId>,
485
486
    /// Documentation associated with this world declaration.
487
    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
488
    pub docs: Docs,
489
490
    /// Stability annotation for this world itself.
491
    #[cfg_attr(
492
        feature = "serde",
493
        serde(skip_serializing_if = "Stability::is_unknown")
494
    )]
495
    pub stability: Stability,
496
497
    /// All the included worlds from this world. Empty if this is fully resolved.
498
    #[cfg_attr(feature = "serde", serde(skip))]
499
    pub includes: Vec<WorldInclude>,
500
501
    /// Source span for this world.
502
    #[cfg_attr(feature = "serde", serde(skip))]
503
    pub span: Span,
504
}
505
506
impl World {
507
    /// Adjusts all spans in this world by adding the given byte offset.
508
32.4k
    pub(crate) fn adjust_spans(&mut self, offset: u32) {
509
32.4k
        self.span.adjust(offset);
510
51.8k
        for item in self.imports.values_mut().chain(self.exports.values_mut()) {
511
51.8k
            item.adjust_spans(offset);
512
51.8k
        }
513
32.4k
        for include in &mut self.includes {
514
0
            include.span.adjust(offset);
515
0
        }
516
32.4k
    }
517
}
518
519
#[derive(Debug, Clone)]
520
pub struct IncludeName {
521
    /// The name of the item
522
    pub name: String,
523
524
    /// The name to be replaced with
525
    pub as_: String,
526
}
527
528
/// An entry in the `includes` list of a world, representing an `include`
529
/// statement in WIT.
530
#[derive(Debug, Clone)]
531
pub struct WorldInclude {
532
    /// The stability annotation on this include.
533
    pub stability: Stability,
534
535
    /// The world being included.
536
    pub id: WorldId,
537
538
    /// Names being renamed as part of this include.
539
    pub names: Vec<IncludeName>,
540
541
    /// Source span for this include statement.
542
    pub span: Span,
543
}
544
545
/// The key to the import/export maps of a world. Either a kebab-name or a
546
/// unique interface.
547
#[derive(Debug, Clone, Eq)]
548
#[cfg_attr(feature = "serde", derive(Serialize))]
549
#[cfg_attr(feature = "serde", serde(into = "String"))]
550
pub enum WorldKey {
551
    /// A kebab-name.
552
    Name(String),
553
    /// An interface which is assigned no kebab-name.
554
    Interface(InterfaceId),
555
}
556
557
impl Hash for WorldKey {
558
208k
    fn hash<H: Hasher>(&self, hasher: &mut H) {
559
208k
        match self {
560
188k
            WorldKey::Name(s) => {
561
188k
                0u8.hash(hasher);
562
188k
                s.as_str().hash(hasher);
563
188k
            }
564
19.7k
            WorldKey::Interface(i) => {
565
19.7k
                1u8.hash(hasher);
566
19.7k
                i.hash(hasher);
567
19.7k
            }
568
        }
569
208k
    }
570
}
571
572
impl PartialEq for WorldKey {
573
34.7k
    fn eq(&self, other: &WorldKey) -> bool {
574
34.7k
        match (self, other) {
575
23.3k
            (WorldKey::Name(a), WorldKey::Name(b)) => a.as_str() == b.as_str(),
576
600
            (WorldKey::Name(_), _) => false,
577
10.2k
            (WorldKey::Interface(a), WorldKey::Interface(b)) => a == b,
578
572
            (WorldKey::Interface(_), _) => false,
579
        }
580
34.7k
    }
581
}
582
583
impl From<WorldKey> for String {
584
0
    fn from(key: WorldKey) -> String {
585
0
        match key {
586
0
            WorldKey::Name(name) => name,
587
0
            WorldKey::Interface(id) => format!("interface-{}", id.index()),
588
        }
589
0
    }
590
}
591
592
impl WorldKey {
593
    /// Asserts that this is `WorldKey::Name` and returns the name.
594
    #[track_caller]
595
9.54k
    pub fn unwrap_name(self) -> String {
596
9.54k
        match self {
597
9.54k
            WorldKey::Name(name) => name,
598
0
            WorldKey::Interface(_) => panic!("expected a name, found interface"),
599
        }
600
9.54k
    }
601
}
602
603
#[derive(Debug, Clone, PartialEq)]
604
#[cfg_attr(feature = "serde", derive(Serialize))]
605
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
606
pub enum WorldItem {
607
    /// An interface is being imported or exported from a world, indicating that
608
    /// it's a namespace of functions.
609
    Interface {
610
        #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
611
        id: InterfaceId,
612
        #[cfg_attr(
613
            feature = "serde",
614
            serde(skip_serializing_if = "Stability::is_unknown")
615
        )]
616
        stability: Stability,
617
        #[cfg_attr(feature = "serde", serde(skip))]
618
        span: Span,
619
    },
620
621
    /// A function is being directly imported or exported from this world.
622
    Function(Function),
623
624
    /// A type is being exported from this world.
625
    ///
626
    /// Note that types are never imported into worlds at this time.
627
    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id_ignore_span"))]
628
    Type { id: TypeId, span: Span },
629
}
630
631
impl WorldItem {
632
31.9k
    pub fn stability<'a>(&'a self, resolve: &'a Resolve) -> &'a Stability {
633
31.9k
        match self {
634
6.31k
            WorldItem::Interface { stability, .. } => stability,
635
6.94k
            WorldItem::Function(f) => &f.stability,
636
18.7k
            WorldItem::Type { id, .. } => &resolve.types[*id].stability,
637
        }
638
31.9k
    }
639
640
27.9k
    pub fn span(&self) -> Span {
641
27.9k
        match self {
642
4.11k
            WorldItem::Interface { span, .. } => *span,
643
5.08k
            WorldItem::Function(f) => f.span,
644
18.7k
            WorldItem::Type { span, .. } => *span,
645
        }
646
27.9k
    }
647
648
51.8k
    pub(crate) fn adjust_spans(&mut self, offset: u32) {
649
51.8k
        match self {
650
10.1k
            WorldItem::Function(f) => f.adjust_spans(offset),
651
8.59k
            WorldItem::Interface { span, .. } => span.adjust(offset),
652
33.0k
            WorldItem::Type { span, .. } => span.adjust(offset),
653
        }
654
51.8k
    }
655
}
656
657
#[derive(Debug, Clone)]
658
#[cfg_attr(feature = "serde", derive(Serialize))]
659
pub struct Interface {
660
    /// Optionally listed name of this interface.
661
    ///
662
    /// This is `None` for inline interfaces in worlds.
663
    pub name: Option<String>,
664
665
    /// Exported types from this interface.
666
    ///
667
    /// Export names are listed within the types themselves. Note that the
668
    /// export name here matches the name listed in the `TypeDef`.
669
    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id_map"))]
670
    pub types: IndexMap<String, TypeId>,
671
672
    /// Exported functions from this interface.
673
    pub functions: IndexMap<String, Function>,
674
675
    /// Documentation associated with this interface.
676
    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
677
    pub docs: Docs,
678
679
    /// Stability attribute for this interface.
680
    #[cfg_attr(
681
        feature = "serde",
682
        serde(skip_serializing_if = "Stability::is_unknown")
683
    )]
684
    pub stability: Stability,
685
686
    /// The package that owns this interface.
687
    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_optional_id"))]
688
    pub package: Option<PackageId>,
689
690
    /// Source span for this interface.
691
    #[cfg_attr(feature = "serde", serde(skip))]
692
    pub span: Span,
693
694
    /// The interface that this one was cloned from, if any.
695
    ///
696
    /// Applicable for [`Resolve::generate_nominal_type_ids`].
697
    #[cfg_attr(
698
        feature = "serde",
699
        serde(
700
            skip_serializing_if = "Option::is_none",
701
            serialize_with = "serialize_optional_id",
702
        )
703
    )]
704
    pub clone_of: Option<InterfaceId>,
705
}
706
707
impl Interface {
708
    /// Adjusts all spans in this interface by adding the given byte offset.
709
60.4k
    pub(crate) fn adjust_spans(&mut self, offset: u32) {
710
60.4k
        self.span.adjust(offset);
711
60.4k
        for func in self.functions.values_mut() {
712
24.3k
            func.adjust_spans(offset);
713
24.3k
        }
714
60.4k
    }
715
}
716
717
#[derive(Debug, Clone, PartialEq)]
718
#[cfg_attr(feature = "serde", derive(Serialize))]
719
pub struct TypeDef {
720
    pub name: Option<String>,
721
    pub kind: TypeDefKind,
722
    pub owner: TypeOwner,
723
    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
724
    pub docs: Docs,
725
    /// Stability attribute for this type.
726
    #[cfg_attr(
727
        feature = "serde",
728
        serde(skip_serializing_if = "Stability::is_unknown")
729
    )]
730
    pub stability: Stability,
731
    /// Source span for this type.
732
    #[cfg_attr(feature = "serde", serde(skip))]
733
    pub span: Span,
734
}
735
736
impl TypeDef {
737
    /// Adjusts all spans in this type definition by adding the given byte offset.
738
    ///
739
    /// This is used when merging source maps to update spans to point to the
740
    /// correct location in the combined source map.
741
197k
    pub(crate) fn adjust_spans(&mut self, offset: u32) {
742
197k
        self.span.adjust(offset);
743
197k
        match &mut self.kind {
744
5.54k
            TypeDefKind::Record(r) => {
745
15.0k
                for field in &mut r.fields {
746
15.0k
                    field.span.adjust(offset);
747
15.0k
                }
748
            }
749
8.72k
            TypeDefKind::Variant(v) => {
750
29.6k
                for case in &mut v.cases {
751
29.6k
                    case.span.adjust(offset);
752
29.6k
                }
753
            }
754
31.9k
            TypeDefKind::Enum(e) => {
755
151k
                for case in &mut e.cases {
756
151k
                    case.span.adjust(offset);
757
151k
                }
758
            }
759
1.75k
            TypeDefKind::Flags(f) => {
760
5.06k
                for flag in &mut f.flags {
761
5.06k
                    flag.span.adjust(offset);
762
5.06k
                }
763
            }
764
149k
            _ => {}
765
        }
766
197k
    }
767
}
768
769
#[derive(Debug, Clone, PartialEq, Hash, Eq)]
770
#[cfg_attr(feature = "serde", derive(Serialize))]
771
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
772
pub enum TypeDefKind {
773
    Record(Record),
774
    Resource,
775
    Handle(Handle),
776
    Flags(Flags),
777
    Tuple(Tuple),
778
    Variant(Variant),
779
    Enum(Enum),
780
    Option(Type),
781
    Result(Result_),
782
    List(Type),
783
    Map(Type, Type),
784
    FixedLengthList(Type, u32),
785
    Future(Option<Type>),
786
    Stream(Option<Type>),
787
    Type(Type),
788
789
    /// This represents a type of unknown structure imported from a foreign
790
    /// interface.
791
    ///
792
    /// This variant is only used during the creation of `UnresolvedPackage` but
793
    /// by the time a `Resolve` is created then this will not exist.
794
    Unknown,
795
}
796
797
impl TypeDefKind {
798
0
    pub fn as_str(&self) -> &'static str {
799
0
        match self {
800
0
            TypeDefKind::Record(_) => "record",
801
0
            TypeDefKind::Resource => "resource",
802
0
            TypeDefKind::Handle(handle) => match handle {
803
0
                Handle::Own(_) => "own",
804
0
                Handle::Borrow(_) => "borrow",
805
            },
806
0
            TypeDefKind::Flags(_) => "flags",
807
0
            TypeDefKind::Tuple(_) => "tuple",
808
0
            TypeDefKind::Variant(_) => "variant",
809
0
            TypeDefKind::Enum(_) => "enum",
810
0
            TypeDefKind::Option(_) => "option",
811
0
            TypeDefKind::Result(_) => "result",
812
0
            TypeDefKind::List(_) => "list",
813
0
            TypeDefKind::Map(_, _) => "map",
814
0
            TypeDefKind::FixedLengthList(..) => "fixed-length list",
815
0
            TypeDefKind::Future(_) => "future",
816
0
            TypeDefKind::Stream(_) => "stream",
817
0
            TypeDefKind::Type(_) => "type",
818
0
            TypeDefKind::Unknown => "unknown",
819
        }
820
0
    }
821
}
822
823
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
824
#[cfg_attr(feature = "serde", derive(Serialize))]
825
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
826
pub enum TypeOwner {
827
    /// This type was defined within a `world` block.
828
    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
829
    World(WorldId),
830
    /// This type was defined within an `interface` block.
831
    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
832
    Interface(InterfaceId),
833
    /// This type wasn't inherently defined anywhere, such as a `list<T>`, which
834
    /// doesn't need an owner.
835
    #[cfg_attr(feature = "serde", serde(untagged, serialize_with = "serialize_none"))]
836
    None,
837
}
838
839
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
840
#[cfg_attr(feature = "serde", derive(Serialize))]
841
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
842
pub enum Handle {
843
    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
844
    Own(TypeId),
845
    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
846
    Borrow(TypeId),
847
}
848
849
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
850
pub enum Type {
851
    Bool,
852
    U8,
853
    U16,
854
    U32,
855
    U64,
856
    S8,
857
    S16,
858
    S32,
859
    S64,
860
    F32,
861
    F64,
862
    Char,
863
    String,
864
    ErrorContext,
865
    Id(TypeId),
866
}
867
868
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
869
pub enum Int {
870
    U8,
871
    U16,
872
    U32,
873
    U64,
874
}
875
876
#[derive(Debug, Clone, PartialEq, Hash, Eq)]
877
#[cfg_attr(feature = "serde", derive(Serialize))]
878
pub struct Record {
879
    pub fields: Vec<Field>,
880
}
881
882
#[derive(Debug, Clone, PartialEq, Hash, Eq)]
883
#[cfg_attr(feature = "serde", derive(Serialize))]
884
pub struct Field {
885
    pub name: String,
886
    #[cfg_attr(feature = "serde", serde(rename = "type"))]
887
    pub ty: Type,
888
    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
889
    pub docs: Docs,
890
    /// Source span for this field.
891
    #[cfg_attr(feature = "serde", serde(skip))]
892
    pub span: Span,
893
}
894
895
#[derive(Debug, Clone, PartialEq, Hash, Eq)]
896
#[cfg_attr(feature = "serde", derive(Serialize))]
897
pub struct Flags {
898
    pub flags: Vec<Flag>,
899
}
900
901
#[derive(Debug, Clone, PartialEq, Hash, Eq)]
902
#[cfg_attr(feature = "serde", derive(Serialize))]
903
pub struct Flag {
904
    pub name: String,
905
    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
906
    pub docs: Docs,
907
    /// Source span for this flag.
908
    #[cfg_attr(feature = "serde", serde(skip))]
909
    pub span: Span,
910
}
911
912
#[derive(Debug, Clone, PartialEq)]
913
pub enum FlagsRepr {
914
    U8,
915
    U16,
916
    U32(usize),
917
}
918
919
impl Flags {
920
305
    pub fn repr(&self) -> FlagsRepr {
921
305
        match self.flags.len() {
922
0
            0 => FlagsRepr::U32(0),
923
305
            n if n <= 8 => FlagsRepr::U8,
924
21
            n if n <= 16 => FlagsRepr::U16,
925
0
            n => FlagsRepr::U32(sizealign::align_to(n, 32) / 32),
926
        }
927
305
    }
928
}
929
930
impl FlagsRepr {
931
18
    pub fn count(&self) -> usize {
932
18
        match self {
933
18
            FlagsRepr::U8 => 1,
934
0
            FlagsRepr::U16 => 1,
935
0
            FlagsRepr::U32(n) => *n,
936
        }
937
18
    }
938
}
939
940
#[derive(Debug, Clone, PartialEq, Hash, Eq)]
941
#[cfg_attr(feature = "serde", derive(Serialize))]
942
pub struct Tuple {
943
    pub types: Vec<Type>,
944
}
945
946
#[derive(Debug, Clone, PartialEq, Hash, Eq)]
947
#[cfg_attr(feature = "serde", derive(Serialize))]
948
pub struct Variant {
949
    pub cases: Vec<Case>,
950
}
951
952
#[derive(Debug, Clone, PartialEq, Hash, Eq)]
953
#[cfg_attr(feature = "serde", derive(Serialize))]
954
pub struct Case {
955
    pub name: String,
956
    #[cfg_attr(feature = "serde", serde(rename = "type"))]
957
    pub ty: Option<Type>,
958
    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
959
    pub docs: Docs,
960
    /// Source span for this variant case.
961
    #[cfg_attr(feature = "serde", serde(skip))]
962
    pub span: Span,
963
}
964
965
impl Variant {
966
1.80k
    pub fn tag(&self) -> Int {
967
1.80k
        discriminant_type(self.cases.len())
968
1.80k
    }
969
}
970
971
#[derive(Debug, Clone, PartialEq, Hash, Eq)]
972
#[cfg_attr(feature = "serde", derive(Serialize))]
973
pub struct Enum {
974
    pub cases: Vec<EnumCase>,
975
}
976
977
#[derive(Debug, Clone, PartialEq, Hash, Eq)]
978
#[cfg_attr(feature = "serde", derive(Serialize))]
979
pub struct EnumCase {
980
    pub name: String,
981
    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
982
    pub docs: Docs,
983
    /// Source span for this enum case.
984
    #[cfg_attr(feature = "serde", serde(skip))]
985
    pub span: Span,
986
}
987
988
impl Enum {
989
1.49k
    pub fn tag(&self) -> Int {
990
1.49k
        discriminant_type(self.cases.len())
991
1.49k
    }
992
}
993
994
/// This corresponds to the `discriminant_type` function in the Canonical ABI.
995
3.30k
fn discriminant_type(num_cases: usize) -> Int {
996
3.30k
    match num_cases.checked_sub(1) {
997
0
        None => Int::U8,
998
3.30k
        Some(n) if n <= u8::max_value() as usize => Int::U8,
999
0
        Some(n) if n <= u16::max_value() as usize => Int::U16,
1000
0
        Some(n) if n <= u32::max_value() as usize => Int::U32,
1001
0
        _ => panic!("too many cases to fit in a repr"),
1002
    }
1003
3.30k
}
1004
1005
#[derive(Debug, Clone, PartialEq, Hash, Eq)]
1006
#[cfg_attr(feature = "serde", derive(Serialize))]
1007
pub struct Result_ {
1008
    pub ok: Option<Type>,
1009
    pub err: Option<Type>,
1010
}
1011
1012
#[derive(Clone, Default, Debug, PartialEq, Eq, Hash)]
1013
#[cfg_attr(feature = "serde", derive(Serialize))]
1014
pub struct Docs {
1015
    pub contents: Option<String>,
1016
}
1017
1018
impl Docs {
1019
0
    pub fn is_empty(&self) -> bool {
1020
0
        self.contents.is_none()
1021
0
    }
1022
}
1023
1024
#[derive(Debug, Clone, PartialEq, Eq)]
1025
#[cfg_attr(feature = "serde", derive(Serialize))]
1026
pub struct Param {
1027
    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "String::is_empty"))]
1028
    pub name: String,
1029
    #[cfg_attr(feature = "serde", serde(rename = "type"))]
1030
    pub ty: Type,
1031
    #[cfg_attr(feature = "serde", serde(skip))]
1032
    pub span: Span,
1033
}
1034
1035
#[derive(Debug, Clone, PartialEq, Eq)]
1036
#[cfg_attr(feature = "serde", derive(Serialize))]
1037
pub struct Function {
1038
    pub name: String,
1039
    pub kind: FunctionKind,
1040
    pub params: Vec<Param>,
1041
    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1042
    pub result: Option<Type>,
1043
    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
1044
    pub docs: Docs,
1045
    /// Stability attribute for this function.
1046
    #[cfg_attr(
1047
        feature = "serde",
1048
        serde(skip_serializing_if = "Stability::is_unknown")
1049
    )]
1050
    pub stability: Stability,
1051
1052
    /// Source span for this function.
1053
    #[cfg_attr(feature = "serde", serde(skip))]
1054
    pub span: Span,
1055
}
1056
1057
#[derive(Debug, Clone, PartialEq, Eq)]
1058
#[cfg_attr(feature = "serde", derive(Serialize))]
1059
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1060
pub enum FunctionKind {
1061
    /// A freestanding function.
1062
    ///
1063
    /// ```wit
1064
    /// interface foo {
1065
    ///     the-func: func();
1066
    /// }
1067
    /// ```
1068
    Freestanding,
1069
1070
    /// An async freestanding function.
1071
    ///
1072
    /// ```wit
1073
    /// interface foo {
1074
    ///     the-func: async func();
1075
    /// }
1076
    /// ```
1077
    AsyncFreestanding,
1078
1079
    /// A resource method where the first parameter is implicitly
1080
    /// `borrow<T>`.
1081
    ///
1082
    /// ```wit
1083
    /// interface foo {
1084
    ///     resource r {
1085
    ///         the-func: func();
1086
    ///     }
1087
    /// }
1088
    /// ```
1089
    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1090
    Method(TypeId),
1091
1092
    /// An async resource method where the first parameter is implicitly
1093
    /// `borrow<T>`.
1094
    ///
1095
    /// ```wit
1096
    /// interface foo {
1097
    ///     resource r {
1098
    ///         the-func: async func();
1099
    ///     }
1100
    /// }
1101
    /// ```
1102
    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1103
    AsyncMethod(TypeId),
1104
1105
    /// A static resource method.
1106
    ///
1107
    /// ```wit
1108
    /// interface foo {
1109
    ///     resource r {
1110
    ///         the-func: static func();
1111
    ///     }
1112
    /// }
1113
    /// ```
1114
    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1115
    Static(TypeId),
1116
1117
    /// An async static resource method.
1118
    ///
1119
    /// ```wit
1120
    /// interface foo {
1121
    ///     resource r {
1122
    ///         the-func: static async func();
1123
    ///     }
1124
    /// }
1125
    /// ```
1126
    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1127
    AsyncStatic(TypeId),
1128
1129
    /// A resource constructor where the return value is implicitly `own<T>`.
1130
    ///
1131
    /// ```wit
1132
    /// interface foo {
1133
    ///     resource r {
1134
    ///         constructor();
1135
    ///     }
1136
    /// }
1137
    /// ```
1138
    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1139
    Constructor(TypeId),
1140
}
1141
1142
impl FunctionKind {
1143
    /// Returns whether this is an async function or not.
1144
59.8k
    pub fn is_async(&self) -> bool {
1145
59.8k
        match self {
1146
            FunctionKind::Freestanding
1147
            | FunctionKind::Method(_)
1148
            | FunctionKind::Static(_)
1149
26.5k
            | FunctionKind::Constructor(_) => false,
1150
            FunctionKind::AsyncFreestanding
1151
            | FunctionKind::AsyncMethod(_)
1152
33.3k
            | FunctionKind::AsyncStatic(_) => true,
1153
        }
1154
59.8k
    }
1155
1156
    /// Returns the resource, if present, that this function kind refers to.
1157
57.0k
    pub fn resource(&self) -> Option<TypeId> {
1158
57.0k
        match self {
1159
41.3k
            FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => None,
1160
1.97k
            FunctionKind::Method(id)
1161
1.81k
            | FunctionKind::Static(id)
1162
1.70k
            | FunctionKind::Constructor(id)
1163
6.74k
            | FunctionKind::AsyncMethod(id)
1164
15.6k
            | FunctionKind::AsyncStatic(id) => Some(*id),
1165
        }
1166
57.0k
    }
1167
1168
    /// Returns the resource, if present, that this function kind refers to.
1169
41.4k
    pub fn resource_mut(&mut self) -> Option<&mut TypeId> {
1170
41.4k
        match self {
1171
32.7k
            FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => None,
1172
1.19k
            FunctionKind::Method(id)
1173
999
            | FunctionKind::Static(id)
1174
987
            | FunctionKind::Constructor(id)
1175
3.56k
            | FunctionKind::AsyncMethod(id)
1176
8.65k
            | FunctionKind::AsyncStatic(id) => Some(id),
1177
        }
1178
41.4k
    }
1179
}
1180
1181
/// Possible forms of name mangling that are supported by this crate.
1182
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1183
pub enum Mangling {
1184
    /// The "standard" component model mangling format for 32-bit linear
1185
    /// memories. This is specified in WebAssembly/component-model#378
1186
    Standard32,
1187
1188
    /// The "legacy" name mangling supported in versions 218-and-prior for this
1189
    /// crate. This is the original support for how components were created from
1190
    /// core wasm modules and this does not correspond to any standard. This is
1191
    /// preserved for now while tools transition to the new scheme.
1192
    Legacy,
1193
}
1194
1195
impl core::str::FromStr for Mangling {
1196
    type Err = anyhow::Error;
1197
1198
0
    fn from_str(s: &str) -> Result<Mangling> {
1199
0
        match s {
1200
0
            "legacy" => Ok(Mangling::Legacy),
1201
0
            "standard32" => Ok(Mangling::Standard32),
1202
            _ => {
1203
0
                bail!(
1204
                    "unknown name mangling `{s}`, \
1205
                     supported values are `legacy` or `standard32`"
1206
                )
1207
            }
1208
        }
1209
0
    }
1210
}
1211
1212
/// Possible lift/lower ABI choices supported when mangling names.
1213
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1214
pub enum LiftLowerAbi {
1215
    /// Both imports and exports will use the synchronous ABI.
1216
    Sync,
1217
1218
    /// Both imports and exports will use the async ABI (with a callback for
1219
    /// each export).
1220
    AsyncCallback,
1221
1222
    /// Both imports and exports will use the async ABI (with no callbacks for
1223
    /// exports).
1224
    AsyncStackful,
1225
}
1226
1227
impl LiftLowerAbi {
1228
2.20k
    fn import_prefix(self) -> &'static str {
1229
2.20k
        match self {
1230
1.92k
            Self::Sync => "",
1231
281
            Self::AsyncCallback | Self::AsyncStackful => "[async-lower]",
1232
        }
1233
2.20k
    }
1234
1235
    /// Get the import [`AbiVariant`] corresponding to this [`LiftLowerAbi`]
1236
1.75k
    pub fn import_variant(self) -> AbiVariant {
1237
1.75k
        match self {
1238
1.46k
            Self::Sync => AbiVariant::GuestImport,
1239
281
            Self::AsyncCallback | Self::AsyncStackful => AbiVariant::GuestImportAsync,
1240
        }
1241
1.75k
    }
1242
1243
2.05k
    fn export_prefix(self) -> &'static str {
1244
2.05k
        match self {
1245
1.64k
            Self::Sync => "",
1246
339
            Self::AsyncCallback => "[async-lift]",
1247
71
            Self::AsyncStackful => "[async-lift-stackful]",
1248
        }
1249
2.05k
    }
1250
1251
    /// Get the export [`AbiVariant`] corresponding to this [`LiftLowerAbi`]
1252
1.02k
    pub fn export_variant(self) -> AbiVariant {
1253
1.02k
        match self {
1254
795
            Self::Sync => AbiVariant::GuestExport,
1255
164
            Self::AsyncCallback => AbiVariant::GuestExportAsync,
1256
64
            Self::AsyncStackful => AbiVariant::GuestExportAsyncStackful,
1257
        }
1258
1.02k
    }
1259
}
1260
1261
/// Combination of [`Mangling`] and [`LiftLowerAbi`].
1262
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1263
pub enum ManglingAndAbi {
1264
    /// See [`Mangling::Standard32`].
1265
    ///
1266
    /// As of this writing, the standard name mangling only supports the
1267
    /// synchronous ABI.
1268
    Standard32,
1269
1270
    /// See [`Mangling::Legacy`] and [`LiftLowerAbi`].
1271
    Legacy(LiftLowerAbi),
1272
}
1273
1274
impl ManglingAndAbi {
1275
    /// Get the import [`AbiVariant`] corresponding to this [`ManglingAndAbi`]
1276
1.85k
    pub fn import_variant(self) -> AbiVariant {
1277
1.85k
        match self {
1278
103
            Self::Standard32 => AbiVariant::GuestImport,
1279
1.75k
            Self::Legacy(abi) => abi.import_variant(),
1280
        }
1281
1.85k
    }
1282
1283
    /// Get the export [`AbiVariant`] corresponding to this [`ManglingAndAbi`]
1284
1.12k
    pub fn export_variant(self) -> AbiVariant {
1285
1.12k
        match self {
1286
104
            Self::Standard32 => AbiVariant::GuestExport,
1287
1.02k
            Self::Legacy(abi) => abi.export_variant(),
1288
        }
1289
1.12k
    }
1290
1291
    /// Switch the ABI to be sync if it's async.
1292
513
    pub fn sync(self) -> Self {
1293
456
        match self {
1294
421
            Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => self,
1295
            Self::Legacy(LiftLowerAbi::AsyncCallback)
1296
92
            | Self::Legacy(LiftLowerAbi::AsyncStackful) => Self::Legacy(LiftLowerAbi::Sync),
1297
        }
1298
513
    }
1299
1300
    /// Returns whether this is an async ABI
1301
7.08k
    pub fn is_async(&self) -> bool {
1302
6.65k
        match self {
1303
5.97k
            Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => false,
1304
            Self::Legacy(LiftLowerAbi::AsyncCallback)
1305
1.11k
            | Self::Legacy(LiftLowerAbi::AsyncStackful) => true,
1306
        }
1307
7.08k
    }
1308
1309
228
    pub fn mangling(&self) -> Mangling {
1310
228
        match self {
1311
0
            Self::Standard32 => Mangling::Standard32,
1312
228
            Self::Legacy(_) => Mangling::Legacy,
1313
        }
1314
228
    }
1315
}
1316
1317
impl Function {
1318
    /// Adjusts all spans in this function by adding the given byte offset.
1319
34.4k
    pub(crate) fn adjust_spans(&mut self, offset: u32) {
1320
34.4k
        self.span.adjust(offset);
1321
79.1k
        for param in &mut self.params {
1322
79.1k
            param.span.adjust(offset);
1323
79.1k
        }
1324
34.4k
    }
1325
1326
10.4k
    pub fn item_name(&self) -> &str {
1327
10.4k
        match &self.kind {
1328
8.75k
            FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => &self.name,
1329
            FunctionKind::Method(_)
1330
            | FunctionKind::Static(_)
1331
            | FunctionKind::AsyncMethod(_)
1332
1.73k
            | FunctionKind::AsyncStatic(_) => &self.name[self.name.find('.').unwrap() + 1..],
1333
0
            FunctionKind::Constructor(_) => "constructor",
1334
        }
1335
10.4k
    }
1336
1337
    /// Returns an iterator over the types used in parameters and results.
1338
    ///
1339
    /// Note that this iterator is not transitive, it only iterates over the
1340
    /// direct references to types that this function has.
1341
2.49k
    pub fn parameter_and_result_types(&self) -> impl Iterator<Item = Type> + '_ {
1342
2.49k
        self.params.iter().map(|p| p.ty).chain(self.result)
1343
2.49k
    }
1344
1345
    /// Gets the core export name for this function.
1346
0
    pub fn standard32_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1347
0
        self.core_export_name(interface, Mangling::Standard32)
1348
0
    }
1349
1350
13.7k
    pub fn legacy_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1351
13.7k
        self.core_export_name(interface, Mangling::Legacy)
1352
13.7k
    }
1353
    /// Gets the core export name for this function.
1354
13.7k
    pub fn core_export_name<'a>(
1355
13.7k
        &'a self,
1356
13.7k
        interface: Option<&str>,
1357
13.7k
        mangling: Mangling,
1358
13.7k
    ) -> Cow<'a, str> {
1359
13.7k
        match interface {
1360
12.4k
            Some(interface) => match mangling {
1361
0
                Mangling::Standard32 => Cow::Owned(format!("cm32p2|{interface}|{}", self.name)),
1362
12.4k
                Mangling::Legacy => Cow::Owned(format!("{interface}#{}", self.name)),
1363
            },
1364
1.29k
            None => match mangling {
1365
0
                Mangling::Standard32 => Cow::Owned(format!("cm32p2||{}", self.name)),
1366
1.29k
                Mangling::Legacy => Cow::Borrowed(&self.name),
1367
            },
1368
        }
1369
13.7k
    }
1370
    /// Collect any future and stream types appearing in the signature of this
1371
    /// function by doing a depth-first search over the parameter types and then
1372
    /// the result types.
1373
    ///
1374
    /// For example, given the WIT function `foo: func(x: future<future<u32>>,
1375
    /// y: u32) -> stream<u8>`, we would return `[future<u32>,
1376
    /// future<future<u32>>, stream<u8>]`.
1377
    ///
1378
    /// This may be used by binding generators to refer to specific `future` and
1379
    /// `stream` types when importing canonical built-ins such as `stream.new`,
1380
    /// `future.read`, etc.  Using the example above, the import
1381
    /// `[future-new-0]foo` would indicate a call to `future.new` for the type
1382
    /// `future<u32>`.  Likewise, `[future-new-1]foo` would indicate a call to
1383
    /// `future.new` for `future<future<u32>>`, and `[stream-new-2]foo` would
1384
    /// indicate a call to `stream.new` for `stream<u8>`.
1385
1.77k
    pub fn find_futures_and_streams(&self, resolve: &Resolve) -> Vec<TypeId> {
1386
1.77k
        let mut results = Vec::new();
1387
4.74k
        for param in self.params.iter() {
1388
4.74k
            find_futures_and_streams(resolve, param.ty, &mut results);
1389
4.74k
        }
1390
1.77k
        if let Some(ty) = self.result {
1391
1.60k
            find_futures_and_streams(resolve, ty, &mut results);
1392
1.60k
        }
1393
1.77k
        results
1394
1.77k
    }
1395
1396
    /// Check if this function is a resource constructor in shorthand form.
1397
    /// I.e. without an explicit return type annotation.
1398
11.5k
    pub fn is_constructor_shorthand(&self, resolve: &Resolve) -> bool {
1399
11.5k
        let FunctionKind::Constructor(containing_resource_id) = self.kind else {
1400
11.2k
            return false;
1401
        };
1402
1403
242
        let Some(Type::Id(id)) = &self.result else {
1404
0
            return false;
1405
        };
1406
1407
242
        let TypeDefKind::Handle(Handle::Own(returned_resource_id)) = resolve.types[*id].kind else {
1408
0
            return false;
1409
        };
1410
1411
242
        return containing_resource_id == returned_resource_id;
1412
11.5k
    }
1413
1414
    /// Returns the `module`, `name`, and signature to use when importing this
1415
    /// function's `task.return` intrinsic using the `mangling` specified.
1416
228
    pub fn task_return_import(
1417
228
        &self,
1418
228
        resolve: &Resolve,
1419
228
        interface: Option<&WorldKey>,
1420
228
        mangling: Mangling,
1421
228
    ) -> (String, String, abi::WasmSignature) {
1422
228
        match mangling {
1423
0
            Mangling::Standard32 => todo!(),
1424
228
            Mangling::Legacy => {}
1425
        }
1426
        // For exported async functions, generate a `task.return` intrinsic.
1427
228
        let module = match interface {
1428
175
            Some(key) => format!("[export]{}", resolve.name_world_key(key)),
1429
53
            None => "[export]$root".to_string(),
1430
        };
1431
228
        let name = format!("[task-return]{}", self.name);
1432
1433
228
        let mut func_tmp = self.clone();
1434
228
        func_tmp.params = Vec::new();
1435
228
        func_tmp.result = None;
1436
228
        if let Some(ty) = self.result {
1437
181
            func_tmp.params.push(Param {
1438
181
                name: "x".to_string(),
1439
181
                ty,
1440
181
                span: Default::default(),
1441
181
            });
1442
181
        }
1443
228
        let sig = resolve.wasm_signature(AbiVariant::GuestImport, &func_tmp);
1444
228
        (module, name, sig)
1445
228
    }
1446
1447
    // push_imported_future_and_stream_intrinsics(wat, resolve, "[export]", interface, func);
1448
}
1449
1450
25.3k
fn find_futures_and_streams(resolve: &Resolve, ty: Type, results: &mut Vec<TypeId>) {
1451
25.3k
    let Type::Id(id) = ty else {
1452
8.45k
        return;
1453
    };
1454
1455
16.8k
    match &resolve.types[id].kind {
1456
        TypeDefKind::Resource
1457
        | TypeDefKind::Handle(_)
1458
        | TypeDefKind::Flags(_)
1459
177
        | TypeDefKind::Enum(_) => {}
1460
19
        TypeDefKind::Record(r) => {
1461
19
            for Field { ty, .. } in &r.fields {
1462
19
                find_futures_and_streams(resolve, *ty, results);
1463
19
            }
1464
        }
1465
1.29k
        TypeDefKind::Tuple(t) => {
1466
3.51k
            for ty in &t.types {
1467
3.51k
                find_futures_and_streams(resolve, *ty, results);
1468
3.51k
            }
1469
        }
1470
2
        TypeDefKind::Variant(v) => {
1471
10
            for Case { ty, .. } in &v.cases {
1472
10
                if let Some(ty) = ty {
1473
10
                    find_futures_and_streams(resolve, *ty, results);
1474
10
                }
1475
            }
1476
        }
1477
381
        TypeDefKind::Option(ty)
1478
163
        | TypeDefKind::List(ty)
1479
134
        | TypeDefKind::FixedLengthList(ty, ..)
1480
685
        | TypeDefKind::Type(ty) => {
1481
685
            find_futures_and_streams(resolve, *ty, results);
1482
685
        }
1483
0
        TypeDefKind::Map(k, v) => {
1484
0
            find_futures_and_streams(resolve, *k, results);
1485
0
            find_futures_and_streams(resolve, *v, results);
1486
0
        }
1487
528
        TypeDefKind::Result(r) => {
1488
528
            if let Some(ty) = r.ok {
1489
480
                find_futures_and_streams(resolve, ty, results);
1490
480
            }
1491
528
            if let Some(ty) = r.err {
1492
253
                find_futures_and_streams(resolve, ty, results);
1493
275
            }
1494
        }
1495
922
        TypeDefKind::Future(ty) => {
1496
922
            if let Some(ty) = ty {
1497
772
                find_futures_and_streams(resolve, *ty, results);
1498
772
            }
1499
922
            results.push(id);
1500
        }
1501
13.2k
        TypeDefKind::Stream(ty) => {
1502
13.2k
            if let Some(ty) = ty {
1503
13.2k
                find_futures_and_streams(resolve, *ty, results);
1504
13.2k
            }
1505
13.2k
            results.push(id);
1506
        }
1507
0
        TypeDefKind::Unknown => unreachable!(),
1508
    }
1509
25.3k
}
1510
1511
/// Representation of the stability attributes associated with a world,
1512
/// interface, function, or type.
1513
///
1514
/// This is added for WebAssembly/component-model#332 where @since and @unstable
1515
/// annotations were added to WIT.
1516
///
1517
/// The order of the of enum values is significant since it is used with Ord and PartialOrd
1518
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1519
#[cfg_attr(feature = "serde", derive(serde_derive::Deserialize, Serialize))]
1520
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1521
pub enum Stability {
1522
    /// This item does not have either `@since` or `@unstable`.
1523
    Unknown,
1524
1525
    /// `@unstable(feature = foo)`
1526
    ///
1527
    /// This item is explicitly tagged `@unstable`. A feature name is listed and
1528
    /// this item is excluded by default in `Resolve` unless explicitly enabled.
1529
    Unstable {
1530
        feature: String,
1531
        #[cfg_attr(
1532
            feature = "serde",
1533
            serde(
1534
                skip_serializing_if = "Option::is_none",
1535
                default,
1536
                serialize_with = "serialize_optional_version",
1537
                deserialize_with = "deserialize_optional_version"
1538
            )
1539
        )]
1540
        deprecated: Option<Version>,
1541
    },
1542
1543
    /// `@since(version = 1.2.3)`
1544
    ///
1545
    /// This item is explicitly tagged with `@since` as stable since the
1546
    /// specified version.  This may optionally have a feature listed as well.
1547
    Stable {
1548
        #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_version"))]
1549
        #[cfg_attr(feature = "serde", serde(deserialize_with = "deserialize_version"))]
1550
        since: Version,
1551
        #[cfg_attr(
1552
            feature = "serde",
1553
            serde(
1554
                skip_serializing_if = "Option::is_none",
1555
                default,
1556
                serialize_with = "serialize_optional_version",
1557
                deserialize_with = "deserialize_optional_version"
1558
            )
1559
        )]
1560
        deprecated: Option<Version>,
1561
    },
1562
}
1563
1564
impl Stability {
1565
    /// Returns whether this is `Stability::Unknown`.
1566
151k
    pub fn is_unknown(&self) -> bool {
1567
151k
        matches!(self, Stability::Unknown)
1568
151k
    }
1569
1570
0
    pub fn is_stable(&self) -> bool {
1571
0
        matches!(self, Stability::Stable { .. })
1572
0
    }
1573
}
1574
1575
impl Default for Stability {
1576
289k
    fn default() -> Stability {
1577
289k
        Stability::Unknown
1578
289k
    }
1579
}
1580
1581
#[cfg(test)]
1582
mod test {
1583
    use super::*;
1584
    use alloc::vec;
1585
1586
    #[test]
1587
    fn test_discriminant_type() {
1588
        assert_eq!(discriminant_type(1), Int::U8);
1589
        assert_eq!(discriminant_type(0x100), Int::U8);
1590
        assert_eq!(discriminant_type(0x101), Int::U16);
1591
        assert_eq!(discriminant_type(0x10000), Int::U16);
1592
        assert_eq!(discriminant_type(0x10001), Int::U32);
1593
        if let Ok(num_cases) = usize::try_from(0x100000000_u64) {
1594
            assert_eq!(discriminant_type(num_cases), Int::U32);
1595
        }
1596
    }
1597
1598
    #[test]
1599
    fn test_find_futures_and_streams() {
1600
        let mut resolve = Resolve::default();
1601
        let t0 = resolve.types.alloc(TypeDef {
1602
            name: None,
1603
            kind: TypeDefKind::Future(Some(Type::U32)),
1604
            owner: TypeOwner::None,
1605
            docs: Docs::default(),
1606
            stability: Stability::Unknown,
1607
            span: Default::default(),
1608
        });
1609
        let t1 = resolve.types.alloc(TypeDef {
1610
            name: None,
1611
            kind: TypeDefKind::Future(Some(Type::Id(t0))),
1612
            owner: TypeOwner::None,
1613
            docs: Docs::default(),
1614
            stability: Stability::Unknown,
1615
            span: Default::default(),
1616
        });
1617
        let t2 = resolve.types.alloc(TypeDef {
1618
            name: None,
1619
            kind: TypeDefKind::Stream(Some(Type::U32)),
1620
            owner: TypeOwner::None,
1621
            docs: Docs::default(),
1622
            stability: Stability::Unknown,
1623
            span: Default::default(),
1624
        });
1625
        let found = Function {
1626
            name: "foo".into(),
1627
            kind: FunctionKind::Freestanding,
1628
            params: vec![
1629
                Param {
1630
                    name: "p1".into(),
1631
                    ty: Type::Id(t1),
1632
                    span: Default::default(),
1633
                },
1634
                Param {
1635
                    name: "p2".into(),
1636
                    ty: Type::U32,
1637
                    span: Default::default(),
1638
                },
1639
            ],
1640
            result: Some(Type::Id(t2)),
1641
            docs: Docs::default(),
1642
            stability: Stability::Unknown,
1643
            span: Default::default(),
1644
        }
1645
        .find_futures_and_streams(&resolve);
1646
        assert_eq!(3, found.len());
1647
        assert_eq!(t0, found[0]);
1648
        assert_eq!(t1, found[1]);
1649
        assert_eq!(t2, found[2]);
1650
    }
1651
}