Skip to main content

wit_parser/
lib.rs

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