Skip to main content

wac_parser/
resolution.rs

1//! Module for resolving WAC ASTs.
2
3use crate::{ast, Document};
4use indexmap::{IndexMap, IndexSet};
5use miette::{Diagnostic, SourceSpan};
6use semver::Version;
7use std::{
8    collections::{HashMap, HashSet},
9    fmt,
10};
11use wac_graph::{
12    types::{
13        are_semver_compatible, BorrowedPackageKey, DefinedType, Enum, ExternKind, Flags, FuncKind,
14        FuncType, FuncTypeId, Interface, InterfaceId, ItemKind, Package, PackageKey, PrimitiveType,
15        Record, Resource, ResourceAlias, ResourceId, SubtypeChecker, Type, UsedType, ValueType,
16        Variant, World, WorldId,
17    },
18    CompositionGraph, DefineTypeError, EncodeError, EncodeOptions, ExportError, ImportError,
19    InstantiationArgumentError, NodeId, NodeKind, PackageId, Processor,
20};
21use wasmparser::BinaryReaderError;
22
23fn method_extern_name(resource: &str, name: &str, kind: FuncKind) -> String {
24    match kind {
25        FuncKind::Free => unreachable!("a resource method cannot be a free function"),
26        FuncKind::Method => format!("[method]{resource}.{name}"),
27        FuncKind::Static => format!("[static]{resource}.{name}"),
28        FuncKind::Constructor => format!("[constructor]{resource}"),
29    }
30}
31
32struct InterfaceNameDisplay<'a>(&'a Option<String>);
33
34impl fmt::Display for InterfaceNameDisplay<'_> {
35    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
36        match self.0 {
37            Some(name) => write!(f, " for interface `{name}`"),
38            None => Ok(()),
39        }
40    }
41}
42
43struct ParentPathDisplay<'a>(&'a Option<String>, &'a str);
44
45impl fmt::Display for ParentPathDisplay<'_> {
46    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
47        match self.0 {
48            Some(name) => {
49                write!(f, "{name} `{path}` in ", path = self.1)
50            }
51            None => Ok(()),
52        }
53    }
54}
55
56/// Represents an operation that may be performed on an instance.
57#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
58pub enum InstanceOperation {
59    /// The operation was an access of the form `.name` or `.["name"]`.
60    Access,
61    /// The operation was a spread of the form `...id` or `<expr>...`.
62    Spread,
63}
64
65impl fmt::Display for InstanceOperation {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        match self {
68            Self::Access => write!(f, "an access operation"),
69            Self::Spread => write!(f, "a spread operation"),
70        }
71    }
72}
73
74/// Represents a resolution error.
75#[derive(thiserror::Error, Diagnostic, Debug)]
76#[diagnostic(code("failed to resolve document"))]
77pub enum Error {
78    /// An undefined name was encountered.
79    #[error("undefined name `{name}`")]
80    UndefinedName {
81        /// The name that was undefined.
82        name: String,
83        /// The span where the error occurred.
84        #[label(primary, "undefined name `{name}`")]
85        span: SourceSpan,
86    },
87    /// A duplicate name was encountered.
88    #[error("`{name}` is already defined")]
89    DuplicateName {
90        /// The duplicate name.
91        name: String,
92        /// The span where the error occurred.
93        #[label(primary, "`{name}` redefined here")]
94        span: SourceSpan,
95        /// The span where the name was previously defined.
96        #[label("`{name}` previously defined here")]
97        previous: SourceSpan,
98    },
99    /// Duplicate interface export.
100    #[error("duplicate interface export `{name}`{iface}", iface = InterfaceNameDisplay(.interface_name))]
101    DuplicateInterfaceExport {
102        /// The name of the duplicate export.
103        name: String,
104        /// The name of the interface.
105        interface_name: Option<String>,
106        /// The span where the error occurred.
107        #[label(primary, "duplicate export `{name}`")]
108        span: SourceSpan,
109    },
110    /// Duplicate world item.
111    #[error("{kind} `{name}` conflicts with existing {kind} of the same name in world `{world}`")]
112    DuplicateWorldItem {
113        /// The extern kind of the item.
114        kind: ExternKind,
115        /// The name of the item.
116        name: String,
117        /// The name of the world.
118        world: String,
119        /// The span where the error occurred.
120        #[label(primary, "conflicting name `{name}`")]
121        span: SourceSpan,
122    },
123    /// The name is not a function type or interface.
124    #[error("`{name}` ({kind}) is not a function type or interface")]
125    NotFuncOrInterface {
126        /// The name that is not a function type or interface.
127        name: String,
128        /// The kind of the item.
129        kind: String,
130        /// The span where the error occurred.
131        #[label(primary, "`{name}` is not a function type or interface")]
132        span: SourceSpan,
133    },
134    /// The name is not an interface.
135    #[error("`{name}` ({kind}) is not an interface")]
136    NotInterface {
137        /// The name that is not an interface.
138        name: String,
139        /// The kind of the item.
140        kind: String,
141        /// The span where the error occurred.
142        #[label(primary, "`{name}` is not an interface")]
143        span: SourceSpan,
144    },
145    /// Duplicate name in a world include.
146    #[error("duplicate `{name}` in world include `with` clause")]
147    DuplicateWorldIncludeName {
148        /// The name of the duplicate include.
149        name: String,
150        /// The span where the error occurred.
151        #[label(primary, "duplicate name `{name}`")]
152        span: SourceSpan,
153    },
154    /// The name is not a world.
155    #[error("`{name}` ({kind}) is not a world")]
156    NotWorld {
157        /// The name that is not a world.
158        name: String,
159        /// The kind of the item.
160        kind: String,
161        /// The span where the error occurred.
162        #[label(primary, "`{name}` is not a world")]
163        span: SourceSpan,
164    },
165    /// Missing source item for `with` clause in world include.
166    #[error("world `{world}` does not have an import or export named `{name}`")]
167    MissingWorldInclude {
168        /// The name of the world.
169        world: String,
170        /// The name of the missing item.
171        name: String,
172        /// The span where the error occurred.
173        #[label(primary, "no import or export named `{name}`")]
174        span: SourceSpan,
175    },
176    /// A conflict was encountered in a world include.
177    #[error("{kind} `{name}` from world `{from}` conflicts with {kind} of the same name in world `{to}`")]
178    WorldIncludeConflict {
179        /// The extern kind of the item.
180        kind: ExternKind,
181        /// The name of the item.
182        name: String,
183        /// The name of the source world.
184        from: String,
185        /// The name of the target world.
186        to: String,
187        /// The span where the error occurred.
188        #[label(primary, "conflicting name `{name}`")]
189        span: SourceSpan,
190        /// The help for the error.
191        #[help]
192        help: Option<String>,
193    },
194    /// A name is not a type defined in an interface.
195    #[error("a type named `{name}` is not defined in interface `{interface_name}`")]
196    UndefinedInterfaceType {
197        /// The name of the type.
198        name: String,
199        /// The name of the interface.
200        interface_name: String,
201        /// The span where the error occurred.
202        #[label(primary, "`{name}` is not a type in interface `{interface_name}`")]
203        span: SourceSpan,
204    },
205    /// A name is not a value type defined in an interface.
206    #[error("`{name}` ({kind}) is not a value type in interface `{interface_name}`")]
207    NotInterfaceValueType {
208        /// The name that is not a value type.
209        name: String,
210        /// The kind of the item.
211        kind: String,
212        /// The name of the interface.
213        interface_name: String,
214        /// The span where the error occurred.
215        #[label(primary, "`{name}` is not a value type")]
216        span: SourceSpan,
217    },
218    /// A duplicate resource constructor was encountered.
219    #[error("duplicate constructor for resource `{resource}`")]
220    DuplicateResourceConstructor {
221        /// The name of the resource.
222        resource: String,
223        /// The span where the error occurred.
224        #[label(primary, "duplicate constructor")]
225        span: SourceSpan,
226    },
227    /// A duplicate resource method was encountered.
228    #[error("duplicate method `{name}` for resource `{resource}`")]
229    DuplicateResourceMethod {
230        /// The name of the method.
231        name: String,
232        /// The name of the resource.
233        resource: String,
234        /// The span where the error occurred.
235        #[label(primary, "duplicate method `{name}`")]
236        span: SourceSpan,
237    },
238    /// A duplicate variant case was encountered.
239    #[error("duplicate case `{case}` for variant type `{name}`")]
240    DuplicateVariantCase {
241        /// The name of the case.
242        case: String,
243        /// The name of the variant type.
244        name: String,
245        /// The span where the error occurred.
246        #[label(primary, "duplicate case `{case}`")]
247        span: SourceSpan,
248    },
249    /// A duplicate record field was encountered.
250    #[error("duplicate field `{field}` for record type `{name}`")]
251    DuplicateRecordField {
252        /// The name of the field.
253        field: String,
254        /// The name of the record type.
255        name: String,
256        /// The span where the error occurred.
257        #[label(primary, "duplicate field `{field}`")]
258        span: SourceSpan,
259    },
260    /// A duplicate enum case was encountered.
261    #[error("duplicate case `{case}` for enum type `{name}`")]
262    DuplicateEnumCase {
263        /// The name of the case.
264        case: String,
265        /// The name of the enum type.
266        name: String,
267        /// The span where the error occurred.
268        #[label(primary, "duplicate case `{case}`")]
269        span: SourceSpan,
270    },
271    /// A duplicate flag was encountered.
272    #[error("duplicate flag `{flag}` for flags type `{name}`")]
273    DuplicateFlag {
274        /// The name of the flag.
275        flag: String,
276        /// The name of the flags type.
277        name: String,
278        /// The span where the error occurred.
279        #[label(primary, "duplicate flag `{flag}`")]
280        span: SourceSpan,
281    },
282    /// The name cannot be used as an alias type.
283    #[error("`{name}` ({kind}) cannot be used in a type alias")]
284    InvalidAliasType {
285        /// The name that cannot be used as an alias type.
286        name: String,
287        /// The kind of the item.
288        kind: String,
289        /// The span where the error occurred.
290        #[label(primary, "`{name}` cannot be aliased")]
291        span: SourceSpan,
292    },
293    /// The name is not a function type.
294    #[error("`{name}` ({kind}) is not a function type")]
295    NotFuncType {
296        /// The name that is not a function type.
297        name: String,
298        /// The kind of the item.
299        kind: String,
300        /// The span where the error occurred.
301        #[label(primary, "`{name}` is not a function type")]
302        span: SourceSpan,
303    },
304    /// The name is not a resource type.
305    #[error("`{name}` ({kind}) is not a resource type")]
306    NotResourceType {
307        /// The name that is not a resource type.
308        name: String,
309        /// The kind of the item.
310        kind: String,
311        /// The span where the error occurred.
312        #[label(primary, "`{name}` is not a resource type")]
313        span: SourceSpan,
314    },
315    /// The name is not a value type.
316    #[error("`{name}` ({kind}) cannot be used as a value type")]
317    NotValueType {
318        /// The name that is not a value type.
319        name: String,
320        /// The kind of the item.
321        kind: String,
322        /// The span where the error occurred.
323        #[label(primary, "`{name}` not a value type")]
324        span: SourceSpan,
325    },
326    /// A duplicate function parameter was encountered.
327    #[error("duplicate {kind} parameter `{name}`")]
328    DuplicateParameter {
329        /// The name of the parameter.
330        name: String,
331        /// The kind of the function.
332        kind: FuncKind,
333        /// The span where the error occurred.
334        #[label(primary, "duplicate parameter `{name}`")]
335        span: SourceSpan,
336    },
337    /// A duplicate result was encountered.
338    #[error("duplicate {kind} result `{name}`")]
339    DuplicateResult {
340        /// The name of the result.
341        name: String,
342        /// The kind of the function.
343        kind: FuncKind,
344        /// The span where the error occurred.
345        #[label(primary, "duplicate result `{name}`")]
346        span: SourceSpan,
347    },
348    /// A borrow type was encountered in a function result.
349    #[error("function result cannot recursively contain a borrow type")]
350    BorrowInResult {
351        /// The span where the error occurred.
352        #[label(primary, "borrow type in result")]
353        span: SourceSpan,
354    },
355    /// An unknown package was encountered.
356    #[error("unknown package `{name}`")]
357    UnknownPackage {
358        /// The name of the package.
359        name: String,
360        /// The span where the error occurred.
361        #[label(primary, "unknown package `{name}`")]
362        span: SourceSpan,
363    },
364    /// A package failed to parse.
365    #[error("failed to parse package `{name}`")]
366    PackageParseFailure {
367        /// The name of the package.
368        name: String,
369        /// The span where the error occurred.
370        #[label(primary, "package `{name}` failed to parse")]
371        span: SourceSpan,
372        /// The underlying error.
373        #[source]
374        source: anyhow::Error,
375    },
376    /// A package is missing an export.
377    #[error("{prev}package `{package}` has no export named `{export}`", prev = ParentPathDisplay(.kind, .path))]
378    PackageMissingExport {
379        /// The package missing the export.
380        package: String,
381        /// The name of the missing export.
382        export: String,
383        /// The kind of the item missing the export.
384        kind: Option<String>,
385        /// The path to the item missing the export.
386        path: String,
387        /// The span where the error occurred.
388        #[label(primary, "unknown export `{export}`")]
389        span: SourceSpan,
390    },
391    /// A missing export in a package path was encountered.
392    #[error("`{name}` ({kind}) has no export named `{export}`")]
393    PackagePathMissingExport {
394        /// The name that has no matching export.
395        name: String,
396        /// The kind of the item.
397        kind: String,
398        /// The name of the export.
399        export: String,
400        /// The span where the error occurred.
401        #[label(primary, "unknown export `{export}`")]
402        span: SourceSpan,
403    },
404    /// A missing import on a component was encountered.
405    #[error("component `{package}` has no import named `{import}`")]
406    MissingComponentImport {
407        /// The name of the package.
408        package: String,
409        /// The name of the import.
410        import: String,
411        /// The span where the error occurred.
412        #[label(primary, "unknown import `{import}`")]
413        span: SourceSpan,
414    },
415    /// A mismatched instantiation argument was encountered.
416    #[error("mismatched instantiation argument `{name}`")]
417    MismatchedInstantiationArg {
418        /// The name of the argument.
419        name: String,
420        /// The span where the error occurred.
421        #[label(primary, "mismatched argument `{name}`")]
422        span: SourceSpan,
423        /// The source of the error.
424        #[source]
425        source: anyhow::Error,
426    },
427    /// A duplicate instantiation argument was encountered.
428    #[error("duplicate instantiation argument `{name}`")]
429    DuplicateInstantiationArg {
430        /// The name of the argument.
431        name: String,
432        /// The span where the error occurred.
433        #[label(primary, "duplicate argument `{name}`")]
434        span: SourceSpan,
435    },
436    /// A missing instantiation argument was encountered.
437    #[error("missing instantiation argument `{name}` for package `{package}`")]
438    MissingInstantiationArg {
439        /// The name of the argument.
440        name: String,
441        /// The name of the package.
442        package: String,
443        /// The span where the error occurred.
444        #[label(primary, "missing argument `{name}`")]
445        span: SourceSpan,
446    },
447    /// An explicitly imported item conflicts with an item that was implicitly
448    /// imported from an instantiation.
449    #[error("import `{name}` conflicts with an item that was implicitly imported by an instantiation of `{package}`")]
450    ImportConflict {
451        /// The name of the argument.
452        name: String,
453        /// The package that first introduced the import.
454        package: PackageKey,
455        /// The span of the conflicting import.
456        #[label(primary, "explicit import here")]
457        import: SourceSpan,
458        /// The span of the conflicting instantiation.
459        #[label("conflicting instantiation here")]
460        instantiation: SourceSpan,
461    },
462    /// An instantiation argument conflict was encountered.
463    #[error(
464        "failed to merge the type definition for implicit import `{name}` due to conflicting types"
465    )]
466    InstantiationArgMergeFailure {
467        /// The name of the argument.
468        name: String,
469        /// The span where the error occurred.
470        #[label(primary, "conflicting instantiation here")]
471        span: SourceSpan,
472        /// The span where the previous instantiation occurred.
473        #[label("previous instantiation here")]
474        instantiation: SourceSpan,
475        /// The underlying merge error.
476        #[source]
477        source: anyhow::Error,
478    },
479    /// An operation was performed on something that was not an instance.
480    #[error("an instance is required to perform {operation}")]
481    NotAnInstance {
482        /// The kind of item that was not an instance.
483        kind: String,
484        /// The operation that was performed.
485        operation: InstanceOperation,
486        /// The span where the error occurred.
487        #[label(primary, "this evaluated to a {kind} when an instance was expected")]
488        span: SourceSpan,
489    },
490    /// An instance is missing an export.
491    #[error("the instance has no export named `{name}`")]
492    MissingInstanceExport {
493        /// The name of the export.
494        name: String,
495        /// The span where the error occurred.
496        #[label(primary, "unknown export `{name}`")]
497        span: SourceSpan,
498    },
499    /// An export requires an `as`` clause.
500    #[error("export statement requires an `as` clause as the export name cannot be inferred")]
501    ExportRequiresAs {
502        /// The span where the error occurred.
503        #[label(primary, "an `as` clause is required")]
504        span: SourceSpan,
505    },
506    /// A type declaration conflicts with an export of the same name
507    #[error("type declaration `{name}` conflicts with a previous export of the same name")]
508    DeclarationConflict {
509        /// The name of the type.
510        name: String,
511        /// The span where the error occurred.
512        #[label(primary, "conflicting type declaration `{name}`")]
513        span: SourceSpan,
514        /// The span of the previous export.
515        #[label("previous export is here")]
516        export: SourceSpan,
517    },
518    /// An export conflicts with a definition.
519    #[error("export `{name}` conflicts with {kind} definition")]
520    ExportConflict {
521        /// The name of the export.
522        name: String,
523        /// The kind of the definition.
524        kind: String,
525        /// The span where the error occurred.
526        #[label(primary, "conflicting export of `{name}`")]
527        span: SourceSpan,
528        /// The span of the previous definition.
529        #[label("previous definition is here")]
530        definition: SourceSpan,
531        /// The help of the error.
532        #[help]
533        help: Option<String>,
534    },
535    /// A duplicate extern name was encountered.
536    #[error("duplicate {kind} `{name}`")]
537    DuplicateExternName {
538        /// The name of the export.
539        name: String,
540        /// The kind of extern name.
541        kind: ExternKind,
542        /// The span where the error occurred.
543        #[label(primary, "duplicate {kind} name `{name}`")]
544        span: SourceSpan,
545        /// The span where the error occurred.
546        #[label("previous {kind} here")]
547        previous: SourceSpan,
548        /// The help of the error.
549        #[help]
550        help: Option<String>,
551    },
552    /// An invalid extern name was encountered.
553    #[error("{kind} name `{name}` is not valid")]
554    InvalidExternName {
555        /// The name of the export.
556        name: String,
557        /// The kind of extern.
558        kind: ExternKind,
559        /// The span where the error occurred.
560        #[label(primary, "invalid name `{name}`")]
561        span: SourceSpan,
562        /// The underlying validation error.
563        #[source]
564        source: anyhow::Error,
565    },
566    /// A use of a type conflicts with an extern item.
567    #[error("use of type `{name}` conflicts with an {kind} of the same name")]
568    UseConflict {
569        /// The name of the used type.
570        name: String,
571        /// The extern kind of the conflicting item.
572        kind: ExternKind,
573        /// The span where the error occurred.
574        #[label(primary, "conflicting name `{name}`")]
575        span: SourceSpan,
576        /// The help message for the error.
577        #[help]
578        help: Option<String>,
579    },
580    /// A fill argument (`...`) was not the last argument.
581    #[error("implicit import argument `...` must be the last argument")]
582    FillArgumentNotLast {
583        /// The span where the error occurred.
584        #[label(primary, "must be last argument")]
585        span: SourceSpan,
586    },
587    /// A spread instantiation argument did not match any import names.
588    #[error("the instance has no matching exports for the remaining unsatisfied arguments")]
589    SpreadInstantiationNoMatch {
590        /// The span where the error occurred.
591        #[label(primary, "no matching exports for the instance")]
592        span: SourceSpan,
593    },
594    /// An export spread operation was performed and had no effect.
595    #[error(
596        "instance has no exports or all exports of the instance match previously exported names"
597    )]
598    SpreadExportNoEffect {
599        /// The span where the error occurred.
600        #[label(primary, "spreading the exports of this instance has no effect")]
601        span: SourceSpan,
602    },
603    /// An import is not in the target world.
604    #[error("target world `{world}` does not have an import named `{name}`")]
605    ImportNotInTarget {
606        /// The import name.
607        name: String,
608        /// The target world.
609        world: String,
610        /// The span where the error occurred.
611        #[label(primary, "cannot have an import named `{name}`")]
612        span: Option<SourceSpan>,
613    },
614    /// Missing an export for the target world.
615    #[error("target world `{world}` requires an export named `{name}`")]
616    MissingTargetExport {
617        /// The export name.
618        name: String,
619        /// The expected item kind.
620        kind: String,
621        /// The target world.
622        world: String,
623        /// The span where the error occurred.
624        #[label(primary, "must export a {kind} named `{name}` to target this world")]
625        span: SourceSpan,
626    },
627    /// An import or export has a mismatched type for the target world.
628    #[error("{kind} `{name}` has a mismatched type for target world `{world}`")]
629    TargetMismatch {
630        /// The kind of mismatch.
631        kind: ExternKind,
632        /// The mismatched extern name.
633        name: String,
634        /// The target world.
635        world: String,
636        /// The span where the error occurred.
637        #[label(primary, "mismatched type for {kind} `{name}`")]
638        span: Option<SourceSpan>,
639        /// The source of the error.
640        #[source]
641        source: anyhow::Error,
642    },
643    /// The encoding of the graph failed validation.
644    #[error("the encoding of the graph failed validation")]
645    ValidationFailure {
646        /// The source of the validation error.
647        #[source]
648        source: BinaryReaderError,
649    },
650}
651
652/// Represents a resolution result.
653pub type ResolutionResult<T> = std::result::Result<T, Error>;
654
655/// Represents a resolution of an WAC document.
656pub struct Resolution<'a> {
657    /// The document the resolution is from.
658    document: &'a Document<'a>,
659    /// The resolved composition graph.
660    graph: CompositionGraph,
661    /// The map from node id to import span.
662    import_spans: HashMap<NodeId, SourceSpan>,
663    /// The map from node id to instantiation span.
664    instantiation_spans: HashMap<NodeId, SourceSpan>,
665}
666
667impl Resolution<'_> {
668    /// Gets the document that was resolved.
669    pub fn document(&self) -> &Document<'_> {
670        self.document
671    }
672
673    /// Gets the resolved composition graph.
674    pub fn graph(&self) -> &CompositionGraph {
675        &self.graph
676    }
677
678    /// Encodes the resolution into a component.
679    ///
680    /// This method handles translating encoding errors into resolution
681    /// errors that contain source span information.
682    pub fn encode(&self, mut options: EncodeOptions) -> ResolutionResult<Vec<u8>> {
683        options.processor = options.processor.or(Some(Processor {
684            name: env!("CARGO_PKG_NAME"),
685            version: env!("CARGO_PKG_VERSION"),
686        }));
687
688        self.graph.encode(options).map_err(|e| match e {
689            EncodeError::ValidationFailure { source } => Error::ValidationFailure { source },
690            EncodeError::GraphContainsCycle { .. } => panic!("AST contained a cycle"),
691            EncodeError::ImplicitImportConflict {
692                import,
693                instantiation,
694                package,
695                name,
696            } => Error::ImportConflict {
697                name,
698                package,
699                import: self.import_spans[&import],
700                instantiation: self.instantiation_spans[&instantiation],
701            },
702            EncodeError::ImportTypeMergeConflict {
703                import,
704                first,
705                second,
706                source,
707            } => Error::InstantiationArgMergeFailure {
708                name: import,
709                span: self.instantiation_spans[&second],
710                instantiation: self.instantiation_spans[&first],
711                source,
712            },
713        })
714    }
715
716    /// Consumes the resolution and returns the underlying composition graph.
717    ///
718    /// Note that encoding the returned graph may still fail as a result of
719    /// merging implicit instantiation arguments.
720    pub fn into_graph(self) -> CompositionGraph {
721        self.graph
722    }
723}
724
725#[derive(Debug, Copy, Clone)]
726enum Item {
727    /// The item is a node in the composition graph.
728    Node(NodeId),
729    /// The item is a used type within an interface or world scope.
730    Use(Type),
731    /// The item is a type declaration not at root scope.
732    ///
733    /// At root scope, a type declaration is added to the graph.
734    Type(Type),
735}
736
737impl Item {
738    fn kind(&self, graph: &CompositionGraph) -> ItemKind {
739        match self {
740            Self::Node(id) => graph[*id].item_kind(),
741            Self::Use(ty) => ItemKind::Type(*ty),
742            Self::Type(ty) => ItemKind::Type(*ty),
743        }
744    }
745
746    fn node(&self) -> NodeId {
747        match self {
748            Self::Node(node) => *node,
749            _ => panic!("the item is not a node"),
750        }
751    }
752}
753
754#[derive(Default)]
755struct Scope(IndexMap<String, (Item, SourceSpan)>);
756
757impl Scope {
758    fn get(&self, name: &str) -> Option<(Item, SourceSpan)> {
759        self.0.get(name).copied()
760    }
761}
762
763#[derive(Default)]
764struct State {
765    scopes: Vec<Scope>,
766    current: Scope,
767    graph: CompositionGraph,
768    instantiation_spans: HashMap<NodeId, SourceSpan>,
769    import_spans: HashMap<NodeId, SourceSpan>,
770    export_spans: HashMap<NodeId, SourceSpan>,
771}
772
773impl State {
774    fn register_name(&mut self, id: ast::Ident, item: Item) -> ResolutionResult<()> {
775        log::debug!(
776            "registering name `{id}` in the current scope",
777            id = id.string
778        );
779
780        if let Some((_, previous)) = self.current.0.insert(id.string.to_owned(), (item, id.span)) {
781            return Err(Error::DuplicateName {
782                name: id.string.to_owned(),
783                span: id.span,
784                previous,
785            });
786        }
787
788        if let Item::Node(node) = item {
789            // Use only the first name encountered for the node, ignoring
790            // aliasing in the form of `let x = y;`
791            if self.graph[node].name().is_none() {
792                self.graph.set_node_name(node, id.string.to_owned());
793            }
794        }
795
796        Ok(())
797    }
798
799    /// Gets an item by identifier from the root scope.
800    fn root_item(&self, id: &ast::Ident) -> ResolutionResult<(Item, SourceSpan)> {
801        self.root_scope()
802            .get(id.string)
803            .ok_or(Error::UndefinedName {
804                name: id.string.to_owned(),
805                span: id.span,
806            })
807    }
808
809    /// Gets a node from the local (current) scope.
810    fn local_item(&self, id: &ast::Ident) -> ResolutionResult<(Item, SourceSpan)> {
811        self.current.get(id.string).ok_or(Error::UndefinedName {
812            name: id.string.to_owned(),
813            span: id.span,
814        })
815    }
816
817    /// Gets an item by identifier from the local (current) scope or the root scope.
818    fn local_or_root_item(&self, id: &ast::Ident) -> ResolutionResult<(Item, SourceSpan)> {
819        if self.scopes.is_empty() {
820            return self.local_item(id);
821        }
822
823        if let Some((item, span)) = self.current.get(id.string) {
824            return Ok((item, span));
825        }
826
827        self.root_item(id)
828    }
829
830    fn push_scope(&mut self) {
831        log::debug!("pushing new name scope");
832        self.scopes.push(std::mem::take(&mut self.current));
833    }
834
835    fn pop_scope(&mut self) -> Scope {
836        log::debug!("popping name scope");
837        std::mem::replace(&mut self.current, self.scopes.pop().unwrap())
838    }
839
840    fn root_scope(&self) -> &Scope {
841        self.scopes.first().unwrap_or(&self.current)
842    }
843}
844
845pub(crate) struct AstResolver<'a>(&'a Document<'a>);
846
847impl<'a> AstResolver<'a> {
848    pub fn new(ast: &'a Document) -> Self {
849        Self(ast)
850    }
851
852    pub fn resolve(
853        mut self,
854        mut packages: IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
855    ) -> ResolutionResult<Resolution<'a>> {
856        let mut state = State::default();
857
858        for stmt in &self.0.statements {
859            match stmt {
860                ast::Statement::Import(i) => self.import_statement(&mut state, i, &mut packages)?,
861                ast::Statement::Type(t) => self.type_statement(&mut state, t, &mut packages)?,
862                ast::Statement::Let(l) => self.let_statement(&mut state, l, &mut packages)?,
863                ast::Statement::Export(e) => self.export_statement(&mut state, e, &mut packages)?,
864            }
865        }
866
867        // If there's a target world in the directive, validate the composition
868        // conforms to the target
869        if let Some(path) = &self.0.directive.targets {
870            log::debug!("validating composition targets world `{}`", path.string);
871            let item = self.resolve_package_path(&mut state, path, &mut packages)?;
872            match item {
873                ItemKind::Type(Type::World(world)) => {
874                    self.validate_target(&state, path, world)?;
875                }
876                _ => {
877                    return Err(Error::NotWorld {
878                        name: path.string.to_owned(),
879                        kind: item.desc(state.graph.types()).to_owned(),
880                        span: path.span,
881                    });
882                }
883            }
884        }
885
886        Ok(Resolution {
887            document: self.0,
888            graph: state.graph,
889            import_spans: state.import_spans,
890            instantiation_spans: state.instantiation_spans,
891        })
892    }
893
894    fn import_statement(
895        &mut self,
896        state: &mut State,
897        stmt: &'a ast::ImportStatement<'a>,
898        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
899    ) -> ResolutionResult<()> {
900        log::debug!(
901            "resolving import statement for id `{id}`",
902            id = stmt.id.string
903        );
904
905        // Determine the import name to use
906        let (name, span) = match &stmt.name {
907            Some(name) => (name.as_str(), name.span()),
908            None => match &stmt.ty {
909                ast::ImportType::Package(p) => (p.string, p.span),
910                ast::ImportType::Func(_) | ast::ImportType::Interface(_) => {
911                    (stmt.id.string, stmt.id.span)
912                }
913                ast::ImportType::Ident(id) => {
914                    let (item, _) = state.local_item(id)?;
915                    match item.kind(&state.graph) {
916                        ItemKind::Instance(id) => match &state.graph.types()[id].id {
917                            Some(id) => (id.as_str(), stmt.id.span),
918                            None => (stmt.id.string, stmt.id.span),
919                        },
920                        ItemKind::Component(id) => match &state.graph.types()[id].id {
921                            Some(id) => (id.as_str(), stmt.id.span),
922                            None => (stmt.id.string, stmt.id.span),
923                        },
924                        ItemKind::Type(_)
925                        | ItemKind::Func(_)
926                        | ItemKind::Module(_)
927                        | ItemKind::Value(_) => (stmt.id.string, stmt.id.span),
928                    }
929                }
930            },
931        };
932
933        let map_import_error = |state: &State, e: ImportError, span: SourceSpan| match e {
934            ImportError::ImportAlreadyExists { name, node } => Error::DuplicateExternName {
935                name,
936                kind: ExternKind::Import,
937                span,
938                previous: state.import_spans[&node],
939                help: if stmt.name.is_some() {
940                    None
941                } else {
942                    Some("consider using an `as` clause to use a different name".into())
943                },
944            },
945            ImportError::InvalidImportName { name, source } => Error::InvalidExternName {
946                name,
947                kind: ExternKind::Import,
948                span,
949                source,
950            },
951        };
952
953        // Determine the kind for the item to import
954        let name = name.to_string();
955        let kind = match &stmt.ty {
956            ast::ImportType::Package(p) => self.resolve_package_path(state, p, packages)?,
957            ast::ImportType::Func(ty) => ItemKind::Func(self.func_type(
958                state,
959                &ty.params,
960                &ty.results,
961                FuncKind::Free,
962                None,
963                ty.is_async,
964            )?),
965            ast::ImportType::Interface(i) => {
966                ItemKind::Instance(self.inline_interface(state, i, packages)?)
967            }
968            ast::ImportType::Ident(id) => state.local_item(id)?.0.kind(&state.graph),
969        };
970
971        // Import the item
972        log::debug!("adding import `{name}` to the graph");
973        let node = state
974            .graph
975            .import(name, kind.promote())
976            .map_err(|e| map_import_error(state, e, span))?;
977
978        state.import_spans.insert(node, span);
979
980        // Register the local name
981        state.register_name(stmt.id, Item::Node(node))
982    }
983
984    fn type_statement(
985        &mut self,
986        state: &mut State,
987        stmt: &'a ast::TypeStatement<'a>,
988        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
989    ) -> ResolutionResult<()> {
990        log::debug!("resolving type statement");
991
992        let (id, ty) = match stmt {
993            ast::TypeStatement::Interface(i) => (i.id, self.interface_decl(state, i, packages)?),
994            ast::TypeStatement::World(w) => (w.id, self.world_decl(state, w, packages)?),
995            ast::TypeStatement::Type(t) => (
996                *t.id(),
997                match t {
998                    ast::TypeDecl::Variant(v) => self.variant_decl(state, v, false)?,
999                    ast::TypeDecl::Record(r) => self.record_decl(state, r, false)?,
1000                    ast::TypeDecl::Flags(f) => self.flags_decl(state, f, false)?,
1001                    ast::TypeDecl::Enum(e) => self.enum_decl(state, e, false)?,
1002                    ast::TypeDecl::Alias(a) => self.type_alias(state, a, false)?,
1003                },
1004            ),
1005        };
1006
1007        log::debug!("adding type definition `{id}` to the graph", id = id.string);
1008        let node = state
1009            .graph
1010            .define_type(id.string, ty)
1011            .map_err(|e| match e {
1012                DefineTypeError::TypeAlreadyDefined => panic!("type should not be already defined"),
1013                DefineTypeError::CannotDefineResource => panic!("type should not be a resource"),
1014                DefineTypeError::InvalidExternName { .. } => panic!("parsed an invalid type name"),
1015                DefineTypeError::ExportConflict { name } => Error::DeclarationConflict {
1016                    name,
1017                    span: id.span,
1018                    export: state.export_spans[&state.graph.get_export(id.string).unwrap()],
1019                },
1020            })?;
1021
1022        state.export_spans.insert(node, id.span);
1023        state.register_name(id, Item::Node(node))
1024    }
1025
1026    fn let_statement(
1027        &mut self,
1028        state: &mut State,
1029        stmt: &'a ast::LetStatement<'a>,
1030        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
1031    ) -> ResolutionResult<()> {
1032        log::debug!("resolving let statement for id `{id}`", id = stmt.id.string);
1033        let item = self.expr(state, &stmt.expr, packages)?;
1034        state.register_name(stmt.id, item)
1035    }
1036
1037    fn export_statement(
1038        &mut self,
1039        state: &mut State,
1040        stmt: &'a ast::ExportStatement<'a>,
1041        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
1042    ) -> ResolutionResult<()> {
1043        log::debug!("resolving export statement");
1044
1045        let item = self.expr(state, &stmt.expr, packages)?;
1046        match &stmt.options {
1047            ast::ExportOptions::None => {
1048                let name = self
1049                    .infer_export_name(state, item)
1050                    .ok_or(Error::ExportRequiresAs {
1051                        span: stmt.expr.span,
1052                    })?;
1053
1054                self.export_item(state, item, name.to_owned(), stmt.expr.span, true)?;
1055            }
1056            ast::ExportOptions::Spread(span) => {
1057                let exports = match item.kind(&state.graph) {
1058                    ItemKind::Instance(id) => state.graph.types()[id]
1059                        .exports
1060                        .keys()
1061                        .cloned()
1062                        .collect::<Vec<_>>(),
1063                    kind => {
1064                        return Err(Error::NotAnInstance {
1065                            kind: kind.desc(state.graph.types()).to_string(),
1066                            operation: InstanceOperation::Spread,
1067                            span: stmt.expr.span,
1068                        })
1069                    }
1070                };
1071
1072                let mut exported = false;
1073                for name in exports {
1074                    // Only export the item if it another item with the same name
1075                    // has not been already exported
1076                    if state.graph.get_export(&name).is_some() {
1077                        continue;
1078                    }
1079
1080                    let item = self
1081                        .alias_export(
1082                            state,
1083                            item,
1084                            &name,
1085                            stmt.expr.span,
1086                            InstanceOperation::Spread,
1087                        )?
1088                        .expect("expected a matching export name");
1089
1090                    self.export_item(state, item, name, *span, false)?;
1091                    exported = true;
1092                }
1093
1094                if !exported {
1095                    return Err(Error::SpreadExportNoEffect {
1096                        span: stmt.expr.span,
1097                    });
1098                }
1099            }
1100            ast::ExportOptions::Rename(name) => {
1101                self.export_item(state, item, name.as_str().to_owned(), name.span(), false)?;
1102            }
1103        }
1104
1105        Ok(())
1106    }
1107
1108    fn infer_export_name<'b>(&self, state: &'b State, item: Item) -> Option<&'b str> {
1109        // If the item is an instance with an id, try the id.
1110        if let ItemKind::Instance(id) = item.kind(&state.graph) {
1111            if let Some(id) = &state.graph.types()[id].id {
1112                return Some(id);
1113            }
1114        }
1115
1116        // If the item comes from an import or an alias, try the name associated with it
1117        let node = item.node();
1118        if let Some(name) = state.graph.get_import_name(node) {
1119            Some(name)
1120        } else if let Some((_, name)) = state.graph.get_alias_source(node) {
1121            Some(name)
1122        } else {
1123            None
1124        }
1125    }
1126
1127    fn export_item(
1128        &self,
1129        state: &mut State,
1130        item: Item,
1131        name: String,
1132        span: SourceSpan,
1133        show_hint: bool,
1134    ) -> Result<(), Error> {
1135        if let Some((item, prev_span)) = state.root_scope().get(&name) {
1136            let node = &state.graph[item.node()];
1137            if let NodeKind::Definition = node.kind() {
1138                return Err(Error::ExportConflict {
1139                    name,
1140                    kind: node.item_kind().desc(state.graph.types()).to_string(),
1141                    span,
1142                    definition: prev_span,
1143                    help: if !show_hint {
1144                        None
1145                    } else {
1146                        Some("consider using an `as` clause to use a different name".into())
1147                    },
1148                });
1149            }
1150        }
1151
1152        let node = item.node();
1153        state.graph.export(item.node(), name).map_err(|e| match e {
1154            ExportError::ExportAlreadyExists { name, node } => Error::DuplicateExternName {
1155                name,
1156                kind: ExternKind::Export,
1157                span,
1158                previous: state.export_spans[&node],
1159                help: if !show_hint {
1160                    None
1161                } else {
1162                    Some("consider using an `as` clause to use a different name".into())
1163                },
1164            },
1165            wac_graph::ExportError::InvalidExportName { name, source } => {
1166                Error::InvalidExternName {
1167                    name,
1168                    kind: ExternKind::Export,
1169                    span,
1170                    source,
1171                }
1172            }
1173        })?;
1174
1175        state.export_spans.insert(node, span);
1176        Ok(())
1177    }
1178
1179    fn variant_decl(
1180        &mut self,
1181        state: &mut State,
1182        decl: &ast::VariantDecl<'a>,
1183        register_name: bool,
1184    ) -> ResolutionResult<Type> {
1185        log::debug!(
1186            "resolving variant declaration for id `{id}`",
1187            id = decl.id.string
1188        );
1189
1190        let mut cases = IndexMap::new();
1191        for case in &decl.cases {
1192            let ty = case.ty.as_ref().map(|ty| Self::ty(state, ty)).transpose()?;
1193            if cases.insert(case.id.string.into(), ty).is_some() {
1194                return Err(Error::DuplicateVariantCase {
1195                    case: case.id.string.to_string(),
1196                    name: decl.id.string.to_string(),
1197                    span: case.id.span,
1198                });
1199            }
1200        }
1201
1202        let ty = Type::Value(ValueType::Defined(
1203            state
1204                .graph
1205                .types_mut()
1206                .add_defined_type(DefinedType::Variant(Variant { cases })),
1207        ));
1208
1209        if register_name {
1210            state.register_name(decl.id, Item::Type(ty))?;
1211        }
1212
1213        Ok(ty)
1214    }
1215
1216    fn record_decl(
1217        &mut self,
1218        state: &mut State,
1219        decl: &ast::RecordDecl<'a>,
1220        register_name: bool,
1221    ) -> ResolutionResult<Type> {
1222        log::debug!(
1223            "resolving record declaration for id `{id}`",
1224            id = decl.id.string
1225        );
1226
1227        let mut fields = IndexMap::new();
1228        for field in &decl.fields {
1229            let ty = Self::ty(state, &field.ty)?;
1230            if fields.insert(field.id.string.into(), ty).is_some() {
1231                return Err(Error::DuplicateRecordField {
1232                    field: field.id.string.to_string(),
1233                    name: decl.id.string.to_string(),
1234                    span: field.id.span,
1235                });
1236            }
1237        }
1238
1239        let ty = Type::Value(ValueType::Defined(
1240            state
1241                .graph
1242                .types_mut()
1243                .add_defined_type(DefinedType::Record(Record { fields })),
1244        ));
1245
1246        if register_name {
1247            state.register_name(decl.id, Item::Type(ty))?;
1248        }
1249
1250        Ok(ty)
1251    }
1252
1253    fn flags_decl(
1254        &mut self,
1255        state: &mut State,
1256        decl: &ast::FlagsDecl<'a>,
1257        register_name: bool,
1258    ) -> ResolutionResult<Type> {
1259        log::debug!(
1260            "resolving flags declaration for id `{id}`",
1261            id = decl.id.string
1262        );
1263
1264        let mut flags = IndexSet::new();
1265        for flag in &decl.flags {
1266            if !flags.insert(flag.id.string.into()) {
1267                return Err(Error::DuplicateFlag {
1268                    flag: flag.id.string.to_string(),
1269                    name: decl.id.string.to_string(),
1270                    span: flag.id.span,
1271                });
1272            }
1273        }
1274
1275        let ty = Type::Value(ValueType::Defined(
1276            state
1277                .graph
1278                .types_mut()
1279                .add_defined_type(DefinedType::Flags(Flags(flags))),
1280        ));
1281
1282        if register_name {
1283            state.register_name(decl.id, Item::Type(ty))?;
1284        }
1285
1286        Ok(ty)
1287    }
1288
1289    fn enum_decl(
1290        &mut self,
1291        state: &mut State,
1292        decl: &ast::EnumDecl<'a>,
1293        register_name: bool,
1294    ) -> ResolutionResult<Type> {
1295        log::debug!(
1296            "resolving enum declaration for id `{id}`",
1297            id = decl.id.string
1298        );
1299
1300        let mut cases = IndexSet::new();
1301        for case in &decl.cases {
1302            if !cases.insert(case.id.string.to_owned()) {
1303                return Err(Error::DuplicateEnumCase {
1304                    case: case.id.string.to_string(),
1305                    name: decl.id.string.to_string(),
1306                    span: case.id.span,
1307                });
1308            }
1309        }
1310
1311        let ty = Type::Value(ValueType::Defined(
1312            state
1313                .graph
1314                .types_mut()
1315                .add_defined_type(DefinedType::Enum(Enum(cases))),
1316        ));
1317
1318        if register_name {
1319            state.register_name(decl.id, Item::Type(ty))?;
1320        }
1321
1322        Ok(ty)
1323    }
1324
1325    fn type_alias(
1326        &mut self,
1327        state: &mut State,
1328        alias: &ast::TypeAlias<'a>,
1329        register_name: bool,
1330    ) -> ResolutionResult<Type> {
1331        log::debug!("resolving type alias for id `{id}`", id = alias.id.string);
1332
1333        let ty = match &alias.kind {
1334            ast::TypeAliasKind::Func(f) => Type::Func(self.func_type(
1335                state,
1336                &f.params,
1337                &f.results,
1338                FuncKind::Free,
1339                None,
1340                f.is_async,
1341            )?),
1342            ast::TypeAliasKind::Type(ty) => match ty {
1343                ast::Type::Ident(id) => {
1344                    let (item, _) = state.local_item(id)?;
1345                    match item.kind(&state.graph) {
1346                        ItemKind::Type(Type::Resource(id)) => {
1347                            let owner = state.graph.types()[id].alias.and_then(|a| a.owner);
1348                            Type::Resource(state.graph.types_mut().add_resource(Resource {
1349                                name: alias.id.string.to_owned(),
1350                                alias: Some(ResourceAlias { owner, source: id }),
1351                            }))
1352                        }
1353                        ItemKind::Type(Type::Value(ty)) => Type::Value(ValueType::Defined(
1354                            state
1355                                .graph
1356                                .types_mut()
1357                                .add_defined_type(DefinedType::Alias(ty)),
1358                        )),
1359                        ItemKind::Type(Type::Func(id)) | ItemKind::Func(id) => {
1360                            let ty = state.graph.types()[id].clone();
1361                            Type::Func(state.graph.types_mut().add_func_type(ty))
1362                        }
1363                        kind => {
1364                            return Err(Error::InvalidAliasType {
1365                                name: id.string.to_string(),
1366                                kind: kind.desc(state.graph.types()).to_string(),
1367                                span: id.span,
1368                            });
1369                        }
1370                    }
1371                }
1372                _ => {
1373                    let ty = Self::ty(state, ty)?;
1374                    Type::Value(ValueType::Defined(
1375                        state
1376                            .graph
1377                            .types_mut()
1378                            .add_defined_type(DefinedType::Alias(ty)),
1379                    ))
1380                }
1381            },
1382        };
1383
1384        if register_name {
1385            state.register_name(alias.id, Item::Type(ty))?;
1386        }
1387
1388        Ok(ty)
1389    }
1390
1391    fn func_type_ref(
1392        &mut self,
1393        state: &mut State,
1394        r: &ast::FuncTypeRef<'a>,
1395        kind: FuncKind,
1396    ) -> ResolutionResult<FuncTypeId> {
1397        match r {
1398            ast::FuncTypeRef::Func(ty) => {
1399                self.func_type(state, &ty.params, &ty.results, kind, None, ty.is_async)
1400            }
1401            ast::FuncTypeRef::Ident(id) => {
1402                let (item, _) = state.local_item(id)?;
1403                match item.kind(&state.graph) {
1404                    ItemKind::Type(Type::Func(id)) | ItemKind::Func(id) => Ok(id),
1405                    kind => Err(Error::NotFuncType {
1406                        name: id.string.to_string(),
1407                        kind: kind.desc(state.graph.types()).to_string(),
1408                        span: id.span,
1409                    }),
1410                }
1411            }
1412        }
1413    }
1414
1415    fn ty(state: &mut State, ty: &ast::Type<'a>) -> ResolutionResult<ValueType> {
1416        match ty {
1417            ast::Type::U8(_) => Ok(ValueType::Primitive(PrimitiveType::U8)),
1418            ast::Type::S8(_) => Ok(ValueType::Primitive(PrimitiveType::S8)),
1419            ast::Type::U16(_) => Ok(ValueType::Primitive(PrimitiveType::U16)),
1420            ast::Type::S16(_) => Ok(ValueType::Primitive(PrimitiveType::S16)),
1421            ast::Type::U32(_) => Ok(ValueType::Primitive(PrimitiveType::U32)),
1422            ast::Type::S32(_) => Ok(ValueType::Primitive(PrimitiveType::S32)),
1423            ast::Type::U64(_) => Ok(ValueType::Primitive(PrimitiveType::U64)),
1424            ast::Type::S64(_) => Ok(ValueType::Primitive(PrimitiveType::S64)),
1425            ast::Type::F32(_) => Ok(ValueType::Primitive(PrimitiveType::F32)),
1426            ast::Type::F64(_) => Ok(ValueType::Primitive(PrimitiveType::F64)),
1427            ast::Type::Char(_) => Ok(ValueType::Primitive(PrimitiveType::Char)),
1428            ast::Type::Bool(_) => Ok(ValueType::Primitive(PrimitiveType::Bool)),
1429            ast::Type::String(_) => Ok(ValueType::Primitive(PrimitiveType::String)),
1430            ast::Type::Tuple(v, _) => {
1431                let tuple = DefinedType::Tuple(
1432                    v.iter()
1433                        .map(|ty| Self::ty(state, ty))
1434                        .collect::<ResolutionResult<_>>()?,
1435                );
1436
1437                Ok(ValueType::Defined(
1438                    state.graph.types_mut().add_defined_type(tuple),
1439                ))
1440            }
1441            ast::Type::List(ty, _) => {
1442                let ty = Self::ty(state, ty)?;
1443                Ok(ValueType::Defined(
1444                    state
1445                        .graph
1446                        .types_mut()
1447                        .add_defined_type(DefinedType::List(ty)),
1448                ))
1449            }
1450            ast::Type::Option(ty, _) => {
1451                let ty = Self::ty(state, ty)?;
1452                Ok(ValueType::Defined(
1453                    state
1454                        .graph
1455                        .types_mut()
1456                        .add_defined_type(DefinedType::Option(ty)),
1457                ))
1458            }
1459            ast::Type::Result { ok, err, .. } => {
1460                let ok = ok.as_ref().map(|t| Self::ty(state, t)).transpose()?;
1461                let err = err.as_ref().map(|t| Self::ty(state, t)).transpose()?;
1462                Ok(ValueType::Defined(
1463                    state
1464                        .graph
1465                        .types_mut()
1466                        .add_defined_type(DefinedType::Result { ok, err }),
1467                ))
1468            }
1469            ast::Type::Borrow(id, _) => {
1470                let (item, _) = state.local_item(id)?;
1471                let kind = item.kind(&state.graph);
1472                if let ItemKind::Type(Type::Resource(id)) = kind {
1473                    return Ok(ValueType::Borrow(id));
1474                }
1475
1476                Err(Error::NotResourceType {
1477                    name: id.string.to_string(),
1478                    kind: kind.desc(state.graph.types()).to_string(),
1479                    span: id.span,
1480                })
1481            }
1482            ast::Type::Stream(ty, _) => {
1483                let ty = ty.as_ref().map(|t| Self::ty(state, t)).transpose()?;
1484                Ok(ValueType::Defined(
1485                    state
1486                        .graph
1487                        .types_mut()
1488                        .add_defined_type(DefinedType::Stream(ty)),
1489                ))
1490            }
1491            ast::Type::Future(ty, _) => {
1492                let ty = ty.as_ref().map(|t| Self::ty(state, t)).transpose()?;
1493                Ok(ValueType::Defined(
1494                    state
1495                        .graph
1496                        .types_mut()
1497                        .add_defined_type(DefinedType::Future(ty)),
1498                ))
1499            }
1500            ast::Type::ErrorContext(_) => Ok(ValueType::Primitive(PrimitiveType::ErrorContext)),
1501            ast::Type::Ident(id) => {
1502                let (item, _) = state.local_item(id)?;
1503                let kind = item.kind(&state.graph);
1504                match kind {
1505                    ItemKind::Type(Type::Resource(id)) => Ok(ValueType::Own(id)),
1506                    ItemKind::Type(Type::Value(ty)) => Ok(ty),
1507                    _ => Err(Error::NotValueType {
1508                        name: id.string.to_string(),
1509                        kind: kind.desc(state.graph.types()).to_string(),
1510                        span: id.span,
1511                    }),
1512                }
1513            }
1514        }
1515    }
1516
1517    fn id(&self, name: &str) -> String {
1518        format!(
1519            "{pkg}/{name}{version}",
1520            pkg = self.0.directive.package.name,
1521            version = if let Some(version) = &self.0.directive.package.version {
1522                format!("@{version}")
1523            } else {
1524                String::new()
1525            }
1526        )
1527    }
1528
1529    fn interface_decl(
1530        &mut self,
1531        state: &mut State,
1532        decl: &'a ast::InterfaceDecl<'a>,
1533        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
1534    ) -> ResolutionResult<Type> {
1535        log::debug!(
1536            "resolving interface declaration for id `{id}`",
1537            id = decl.id.string
1538        );
1539        state.push_scope();
1540
1541        let mut ty = Interface {
1542            id: Some(self.id(decl.id.string)),
1543            uses: Default::default(),
1544            exports: Default::default(),
1545        };
1546
1547        self.interface_items(state, Some(decl.id.string), &decl.items, packages, &mut ty)?;
1548
1549        state.pop_scope();
1550
1551        Ok(Type::Interface(state.graph.types_mut().add_interface(ty)))
1552    }
1553
1554    fn world_decl(
1555        &mut self,
1556        state: &mut State,
1557        decl: &'a ast::WorldDecl<'a>,
1558        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
1559    ) -> ResolutionResult<Type> {
1560        log::debug!(
1561            "resolving world declaration for id `{id}`",
1562            id = decl.id.string
1563        );
1564        state.push_scope();
1565
1566        let mut ty = World {
1567            id: Some(self.id(decl.id.string)),
1568            uses: Default::default(),
1569            imports: Default::default(),
1570            exports: Default::default(),
1571        };
1572
1573        self.world_items(state, decl.id.string, &decl.items, packages, &mut ty)?;
1574
1575        state.pop_scope();
1576
1577        Ok(Type::World(state.graph.types_mut().add_world(ty)))
1578    }
1579
1580    fn world_items(
1581        &mut self,
1582        state: &mut State,
1583        world: &'a str,
1584        items: &'a [ast::WorldItem<'a>],
1585        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
1586        ty: &mut World,
1587    ) -> ResolutionResult<()> {
1588        let mut includes = Vec::new();
1589        for item in items {
1590            match item {
1591                ast::WorldItem::Use(u) => {
1592                    self.use_type(state, u, &mut ty.uses, &mut ty.imports, packages, true)?
1593                }
1594                ast::WorldItem::Type(decl) => {
1595                    self.item_type_decl(state, decl, &mut ty.imports)?;
1596                }
1597                ast::WorldItem::Import(i) => {
1598                    self.world_item_path(state, &i.path, ExternKind::Import, world, packages, ty)?
1599                }
1600                ast::WorldItem::Export(e) => {
1601                    self.world_item_path(state, &e.path, ExternKind::Export, world, packages, ty)?
1602                }
1603                ast::WorldItem::Include(i) => {
1604                    // We delay processing includes until after all other items have been processed
1605                    includes.push(i);
1606                }
1607            }
1608        }
1609
1610        // Process the includes now that all imports and exports have been processed.
1611        // This allows us to detect conflicts only in explicitly defined items.
1612        for i in includes {
1613            self.world_include(state, i, world, packages, ty)?;
1614        }
1615
1616        Ok(())
1617    }
1618
1619    fn world_item_path(
1620        &mut self,
1621        state: &mut State,
1622        path: &'a ast::WorldItemPath<'a>,
1623        kind: ExternKind,
1624        world: &'a str,
1625        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
1626        ty: &mut World,
1627    ) -> ResolutionResult<()> {
1628        let (k, v) = match path {
1629            ast::WorldItemPath::Named(named) => {
1630                check_name(named.id.string, named.id.span, ty, world, kind)?;
1631
1632                (
1633                    named.id.string.into(),
1634                    match &named.ty {
1635                        ast::ExternType::Ident(id) => {
1636                            let (item, _) = state.local_or_root_item(id)?;
1637                            match item.kind(&state.graph) {
1638                                ItemKind::Type(Type::Interface(id)) => ItemKind::Instance(id),
1639                                ItemKind::Type(Type::Func(id)) => ItemKind::Func(id),
1640                                kind => {
1641                                    return Err(Error::NotFuncOrInterface {
1642                                        name: id.string.to_owned(),
1643                                        kind: kind.desc(state.graph.types()).to_owned(),
1644                                        span: id.span,
1645                                    });
1646                                }
1647                            }
1648                        }
1649                        ast::ExternType::Func(f) => ItemKind::Func(self.func_type(
1650                            state,
1651                            &f.params,
1652                            &f.results,
1653                            FuncKind::Free,
1654                            None,
1655                            f.is_async,
1656                        )?),
1657                        ast::ExternType::Interface(i) => {
1658                            ItemKind::Instance(self.inline_interface(state, i, packages)?)
1659                        }
1660                    },
1661                )
1662            }
1663            ast::WorldItemPath::Ident(id) => {
1664                let (item, _) = state.root_item(id)?;
1665                match item.kind(&state.graph) {
1666                    ItemKind::Type(Type::Interface(iface_ty_id)) => {
1667                        let iface_id = state.graph.types()[iface_ty_id]
1668                            .id
1669                            .as_ref()
1670                            .expect("expected an interface id");
1671                        check_name(iface_id, id.span, ty, world, kind)?;
1672                        (iface_id.clone(), ItemKind::Instance(iface_ty_id))
1673                    }
1674                    kind => {
1675                        return Err(Error::NotInterface {
1676                            name: id.string.to_owned(),
1677                            kind: kind.desc(state.graph.types()).to_owned(),
1678                            span: id.span,
1679                        });
1680                    }
1681                }
1682            }
1683
1684            ast::WorldItemPath::Package(p) => {
1685                match self.resolve_package_path(state, p, packages)? {
1686                    ItemKind::Type(Type::Interface(id)) => {
1687                        let name = state.graph.types()[id]
1688                            .id
1689                            .as_ref()
1690                            .expect("expected an interface id");
1691                        check_name(name, p.span, ty, world, kind)?;
1692                        (name.clone(), ItemKind::Instance(id))
1693                    }
1694                    kind => {
1695                        return Err(Error::NotInterface {
1696                            name: p.string.to_owned(),
1697                            kind: kind.desc(state.graph.types()).to_owned(),
1698                            span: p.span,
1699                        });
1700                    }
1701                }
1702            }
1703        };
1704
1705        if kind == ExternKind::Import {
1706            ty.imports.insert(k, v);
1707        } else {
1708            ty.exports.insert(k, v);
1709        }
1710
1711        return Ok(());
1712
1713        fn check_name(
1714            name: &str,
1715            span: SourceSpan,
1716            ty: &World,
1717            world: &str,
1718            kind: ExternKind,
1719        ) -> ResolutionResult<()> {
1720            let exists: bool = if kind == ExternKind::Import {
1721                ty.imports.contains_key(name)
1722            } else {
1723                ty.exports.contains_key(name)
1724            };
1725
1726            if exists {
1727                return Err(Error::DuplicateWorldItem {
1728                    kind,
1729                    name: name.to_owned(),
1730                    world: world.to_owned(),
1731                    span,
1732                });
1733            }
1734
1735            Ok(())
1736        }
1737    }
1738
1739    fn world_include(
1740        &mut self,
1741        state: &mut State,
1742        include: &'a ast::WorldInclude<'a>,
1743        world: &'a str,
1744        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
1745        ty: &mut World,
1746    ) -> ResolutionResult<()> {
1747        log::debug!("resolving include of world `{world}`");
1748        let mut replacements = HashMap::new();
1749        for item in &include.with {
1750            let prev = replacements.insert(item.from.string, item);
1751            if prev.is_some() {
1752                return Err(Error::DuplicateWorldIncludeName {
1753                    name: item.from.string.to_owned(),
1754                    span: item.from.span,
1755                });
1756            }
1757        }
1758
1759        let id = match &include.world {
1760            ast::WorldRef::Ident(id) => {
1761                let (item, _) = state.root_item(id)?;
1762                match item.kind(&state.graph) {
1763                    ItemKind::Type(Type::World(id)) | ItemKind::Component(id) => id,
1764                    kind => {
1765                        return Err(Error::NotWorld {
1766                            name: id.string.to_owned(),
1767                            kind: kind.desc(state.graph.types()).to_owned(),
1768                            span: id.span,
1769                        });
1770                    }
1771                }
1772            }
1773            ast::WorldRef::Package(path) => {
1774                match self.resolve_package_path(state, path, packages)? {
1775                    ItemKind::Type(Type::World(id)) | ItemKind::Component(id) => id,
1776                    kind => {
1777                        return Err(Error::NotWorld {
1778                            name: path.string.to_owned(),
1779                            kind: kind.desc(state.graph.types()).to_owned(),
1780                            span: path.span,
1781                        });
1782                    }
1783                }
1784            }
1785        };
1786
1787        let other = &state.graph.types()[id];
1788        for (name, item) in &other.imports {
1789            let name = replace_name(
1790                include,
1791                world,
1792                ty,
1793                name,
1794                ExternKind::Import,
1795                &mut replacements,
1796            )?;
1797            ty.imports.entry(name).or_insert(*item);
1798        }
1799
1800        for (name, item) in &other.exports {
1801            let name = replace_name(
1802                include,
1803                world,
1804                ty,
1805                name,
1806                ExternKind::Export,
1807                &mut replacements,
1808            )?;
1809            ty.exports.entry(name).or_insert(*item);
1810        }
1811
1812        if let Some(missing) = replacements.values().next() {
1813            return Err(Error::MissingWorldInclude {
1814                world: include.world.name().to_owned(),
1815                name: missing.from.string.to_owned(),
1816                span: missing.from.span,
1817            });
1818        }
1819
1820        return Ok(());
1821
1822        fn replace_name<'a>(
1823            include: &ast::WorldInclude<'a>,
1824            world: &'a str,
1825            ty: &mut World,
1826            name: &str,
1827            kind: ExternKind,
1828            replacements: &mut HashMap<&str, &ast::WorldIncludeItem<'a>>,
1829        ) -> ResolutionResult<String> {
1830            // Check for a id, which doesn't get replaced.
1831            if name.contains(':') {
1832                return Ok(name.to_owned());
1833            }
1834
1835            let (name, span) = replacements
1836                .remove(name)
1837                .map(|i| (i.to.string, i.to.span))
1838                .unwrap_or_else(|| (name, include.world.span()));
1839
1840            let exists = if kind == ExternKind::Import {
1841                ty.imports.contains_key(name)
1842            } else {
1843                ty.exports.contains_key(name)
1844            };
1845
1846            if exists {
1847                return Err(Error::WorldIncludeConflict {
1848                    kind,
1849                    name: name.to_owned(),
1850                    from: include.world.name().to_owned(),
1851                    to: world.to_owned(),
1852                    span,
1853                    help: if !include.with.is_empty() {
1854                        None
1855                    } else {
1856                        Some("consider using a `with` clause to use a different name".into())
1857                    },
1858                });
1859            }
1860
1861            Ok(name.to_owned())
1862        }
1863    }
1864
1865    fn inline_interface(
1866        &mut self,
1867        state: &mut State,
1868        iface: &'a ast::InlineInterface<'a>,
1869        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
1870    ) -> ResolutionResult<InterfaceId> {
1871        log::debug!("resolving inline interface");
1872
1873        state.push_scope();
1874
1875        let mut ty = Interface {
1876            id: None,
1877            uses: Default::default(),
1878            exports: Default::default(),
1879        };
1880
1881        self.interface_items(state, None, &iface.items, packages, &mut ty)?;
1882
1883        state.pop_scope();
1884
1885        Ok(state.graph.types_mut().add_interface(ty))
1886    }
1887
1888    fn interface_items(
1889        &mut self,
1890        state: &mut State,
1891        name: Option<&'a str>,
1892        items: &'a [ast::InterfaceItem<'a>],
1893        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
1894        ty: &mut Interface,
1895    ) -> ResolutionResult<()> {
1896        for item in items {
1897            match item {
1898                ast::InterfaceItem::Use(u) => {
1899                    self.use_type(state, u, &mut ty.uses, &mut ty.exports, packages, false)?
1900                }
1901                ast::InterfaceItem::Type(decl) => {
1902                    self.item_type_decl(state, decl, &mut ty.exports)?;
1903                }
1904                ast::InterfaceItem::Export(e) => {
1905                    let kind = ItemKind::Func(self.func_type_ref(state, &e.ty, FuncKind::Free)?);
1906                    if ty.exports.insert(e.id.string.into(), kind).is_some() {
1907                        return Err(Error::DuplicateInterfaceExport {
1908                            name: e.id.string.to_owned(),
1909                            interface_name: name.map(ToOwned::to_owned),
1910                            span: e.id.span,
1911                        });
1912                    }
1913                }
1914            }
1915        }
1916
1917        Ok(())
1918    }
1919
1920    fn use_type(
1921        &mut self,
1922        state: &mut State,
1923        use_type: &'a ast::Use<'a>,
1924        uses: &mut IndexMap<String, UsedType>,
1925        externs: &mut IndexMap<String, ItemKind>,
1926        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
1927        in_world: bool,
1928    ) -> ResolutionResult<()> {
1929        let (interface, name) = match &use_type.path {
1930            ast::UsePath::Package(path) => {
1931                match self.resolve_package_path(state, path, packages)? {
1932                    ItemKind::Type(Type::Interface(id)) => (id, path.string),
1933                    kind => {
1934                        return Err(Error::NotInterface {
1935                            name: path.string.to_owned(),
1936                            kind: kind.desc(state.graph.types()).to_owned(),
1937                            span: path.span,
1938                        });
1939                    }
1940                }
1941            }
1942            ast::UsePath::Ident(id) => {
1943                let (item, _) = state.root_item(id)?;
1944                let kind = item.kind(&state.graph);
1945                match kind {
1946                    ItemKind::Type(Type::Interface(iface_ty_id)) => (iface_ty_id, id.string),
1947                    _ => {
1948                        return Err(Error::NotInterface {
1949                            name: id.string.to_owned(),
1950                            kind: kind.desc(state.graph.types()).to_owned(),
1951                            span: id.span,
1952                        });
1953                    }
1954                }
1955            }
1956        };
1957
1958        for item in &use_type.items {
1959            let ident = item.as_id.unwrap_or(item.id);
1960            let kind = state.graph.types()[interface]
1961                .exports
1962                .get(item.id.string)
1963                .ok_or(Error::UndefinedInterfaceType {
1964                    name: item.id.string.to_string(),
1965                    interface_name: name.to_string(),
1966                    span: item.id.span,
1967                })?;
1968
1969            match kind {
1970                ItemKind::Type(ty @ Type::Resource(_)) | ItemKind::Type(ty @ Type::Value(_)) => {
1971                    if externs.contains_key(ident.string) {
1972                        return Err(Error::UseConflict {
1973                            name: ident.string.to_string(),
1974                            kind: if in_world {
1975                                ExternKind::Import
1976                            } else {
1977                                ExternKind::Export
1978                            },
1979                            span: ident.span,
1980                            help: if item.as_id.is_some() {
1981                                None
1982                            } else {
1983                                Some("consider using an `as` clause to use a different name".into())
1984                            },
1985                        });
1986                    }
1987
1988                    uses.insert(
1989                        ident.string.into(),
1990                        UsedType {
1991                            interface,
1992                            name: item.as_id.map(|_| item.id.string.to_string()),
1993                        },
1994                    );
1995                    externs.insert(ident.string.into(), *kind);
1996                    state.register_name(ident, Item::Use(*ty))?;
1997                }
1998                _ => {
1999                    return Err(Error::NotInterfaceValueType {
2000                        name: item.id.string.to_string(),
2001                        kind: kind.desc(state.graph.types()).to_string(),
2002                        interface_name: name.to_string(),
2003                        span: item.id.span,
2004                    });
2005                }
2006            }
2007        }
2008
2009        Ok(())
2010    }
2011
2012    fn item_type_decl(
2013        &mut self,
2014        state: &mut State,
2015        decl: &'a ast::ItemTypeDecl,
2016        externs: &mut IndexMap<String, ItemKind>,
2017    ) -> ResolutionResult<()> {
2018        let (insert, ty) = match decl {
2019            ast::ItemTypeDecl::Resource(r) => (false, self.resource_decl(state, r, externs)?),
2020            ast::ItemTypeDecl::Variant(v) => (true, self.variant_decl(state, v, true)?),
2021            ast::ItemTypeDecl::Record(r) => (true, self.record_decl(state, r, true)?),
2022            ast::ItemTypeDecl::Flags(f) => (true, self.flags_decl(state, f, true)?),
2023            ast::ItemTypeDecl::Enum(e) => (true, self.enum_decl(state, e, true)?),
2024            ast::ItemTypeDecl::Alias(a) => (true, self.type_alias(state, a, true)?),
2025        };
2026
2027        if insert {
2028            let prev = externs.insert(decl.id().string.into(), ItemKind::Type(ty));
2029            assert!(prev.is_none(), "duplicate type in scope");
2030        }
2031
2032        Ok(())
2033    }
2034
2035    fn resource_decl(
2036        &mut self,
2037        state: &mut State,
2038        decl: &ast::ResourceDecl<'a>,
2039        externs: &mut IndexMap<String, ItemKind>,
2040    ) -> ResolutionResult<Type> {
2041        log::debug!(
2042            "resolving resource declaration for id `{id}`",
2043            id = decl.id.string
2044        );
2045
2046        // Define the resource before resolving the methods
2047        let id = state.graph.types_mut().add_resource(Resource {
2048            name: decl.id.string.to_owned(),
2049            alias: None,
2050        });
2051
2052        let ty = Type::Resource(id);
2053        state.register_name(decl.id, Item::Type(ty))?;
2054
2055        // We must add the resource to the externs before any methods
2056        let prev = externs.insert(decl.id.string.into(), ItemKind::Type(ty));
2057        assert!(prev.is_none());
2058
2059        let mut names = HashSet::new();
2060        for method in &decl.methods {
2061            let (name, ty) = match method {
2062                ast::ResourceMethod::Constructor(ast::Constructor { span, params, .. }) => {
2063                    if !names.insert("") {
2064                        return Err(Error::DuplicateResourceConstructor {
2065                            resource: decl.id.string.to_string(),
2066                            span: *span,
2067                        });
2068                    }
2069
2070                    (
2071                        method_extern_name(decl.id.string, "", FuncKind::Constructor),
2072                        self.func_type(
2073                            state,
2074                            params,
2075                            &ast::ResultList::Empty,
2076                            FuncKind::Constructor,
2077                            Some(id),
2078                            false,
2079                        )?,
2080                    )
2081                }
2082                ast::ResourceMethod::Method(ast::Method {
2083                    id: method_id,
2084                    is_static,
2085                    ty,
2086                    ..
2087                }) => {
2088                    let kind = if *is_static {
2089                        FuncKind::Static
2090                    } else {
2091                        FuncKind::Method
2092                    };
2093
2094                    if !names.insert(method_id.string) {
2095                        return Err(Error::DuplicateResourceMethod {
2096                            name: method_id.string.to_string(),
2097                            resource: decl.id.string.to_string(),
2098                            span: method_id.span,
2099                        });
2100                    }
2101
2102                    (
2103                        method_extern_name(decl.id.string, method_id.string, kind),
2104                        self.func_type(
2105                            state,
2106                            &ty.params,
2107                            &ty.results,
2108                            kind,
2109                            Some(id),
2110                            ty.is_async,
2111                        )?,
2112                    )
2113                }
2114            };
2115
2116            let prev = externs.insert(name, ItemKind::Func(ty));
2117            assert!(prev.is_none());
2118        }
2119
2120        Ok(ty)
2121    }
2122
2123    fn func_type(
2124        &mut self,
2125        state: &mut State,
2126        func_params: &[ast::NamedType<'a>],
2127        func_results: &ast::ResultList<'a>,
2128        kind: FuncKind,
2129        resource: Option<ResourceId>,
2130        is_async: bool,
2131    ) -> ResolutionResult<FuncTypeId> {
2132        let mut params = IndexMap::new();
2133
2134        if kind == FuncKind::Method {
2135            params.insert("self".into(), ValueType::Borrow(resource.unwrap()));
2136        }
2137
2138        for param in func_params {
2139            if params
2140                .insert(param.id.string.into(), Self::ty(state, &param.ty)?)
2141                .is_some()
2142            {
2143                return Err(Error::DuplicateParameter {
2144                    name: param.id.string.to_string(),
2145                    kind,
2146                    span: param.id.span,
2147                });
2148            }
2149        }
2150
2151        let result = match func_results {
2152            ast::ResultList::Empty => {
2153                if kind == FuncKind::Constructor {
2154                    Some(ValueType::Own(resource.unwrap()))
2155                } else {
2156                    None
2157                }
2158            }
2159            ast::ResultList::Scalar(ty) => {
2160                let value_type = Self::ty(state, ty)?;
2161                if value_type.contains_borrow(state.graph.types()) {
2162                    return Err(Error::BorrowInResult { span: ty.span() });
2163                }
2164                Some(value_type)
2165            }
2166        };
2167
2168        Ok(state.graph.types_mut().add_func_type(FuncType {
2169            params,
2170            result,
2171            is_async,
2172        }))
2173    }
2174
2175    fn expr(
2176        &mut self,
2177        state: &mut State,
2178        expr: &'a ast::Expr<'a>,
2179        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
2180    ) -> ResolutionResult<Item> {
2181        let mut item = self.primary_expr(state, &expr.primary, packages)?;
2182
2183        let mut parent_span = expr.primary.span();
2184        for expr in &expr.postfix {
2185            item = self.postfix_expr(state, item, expr, parent_span)?;
2186            parent_span = expr.span();
2187        }
2188
2189        Ok(item)
2190    }
2191
2192    fn primary_expr(
2193        &mut self,
2194        state: &mut State,
2195        expr: &'a ast::PrimaryExpr<'a>,
2196        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
2197    ) -> ResolutionResult<Item> {
2198        match expr {
2199            ast::PrimaryExpr::New(e) => self.new_expr(state, e, packages),
2200            ast::PrimaryExpr::Nested(e) => self.expr(state, &e.inner, packages),
2201            ast::PrimaryExpr::Ident(i) => Ok(state.local_item(i)?.0),
2202        }
2203    }
2204
2205    fn new_expr(
2206        &mut self,
2207        state: &mut State,
2208        expr: &'a ast::NewExpr<'a>,
2209        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
2210    ) -> ResolutionResult<Item> {
2211        log::debug!(
2212            "resolving new expression for package `{pkg}`",
2213            pkg = BorrowedPackageKey::from_name_and_version(
2214                expr.package.name,
2215                expr.package.version.as_ref()
2216            )
2217        );
2218
2219        if expr.package.name == self.0.directive.package.name {
2220            return Err(Error::UnknownPackage {
2221                name: expr.package.name.to_string(),
2222                span: expr.package.span,
2223            });
2224        }
2225
2226        let pkg = self.resolve_package(
2227            state,
2228            expr.package.name,
2229            expr.package.version.as_ref(),
2230            expr.package.span,
2231            packages,
2232        )?;
2233        let ty = state.graph[pkg].ty();
2234        let expected = state.graph.types()[ty]
2235            .imports
2236            .keys()
2237            .cloned()
2238            .collect::<IndexSet<_>>();
2239        let mut require_all = true;
2240
2241        let mut arguments: IndexMap<String, (Item, SourceSpan)> = Default::default();
2242        for (i, arg) in expr.arguments.iter().enumerate() {
2243            let (name, item, span) = match arg {
2244                ast::InstantiationArgument::Inferred(id) => {
2245                    self.inferred_instantiation_arg(state, id, ty)?
2246                }
2247                ast::InstantiationArgument::Spread(_) => {
2248                    // Spread arguments will be processed after all other arguments
2249                    continue;
2250                }
2251                ast::InstantiationArgument::Named(arg) => {
2252                    self.named_instantiation_arg(state, arg, ty, packages)?
2253                }
2254                ast::InstantiationArgument::Fill(span) => {
2255                    if i != (expr.arguments.len() - 1) {
2256                        return Err(Error::FillArgumentNotLast { span: *span });
2257                    }
2258
2259                    require_all = false;
2260                    continue;
2261                }
2262            };
2263
2264            let prev = arguments.insert(name.clone(), (item, span));
2265            if prev.is_some() {
2266                return Err(Error::DuplicateInstantiationArg { name, span });
2267            }
2268        }
2269
2270        // Process the spread arguments
2271        for arg in &expr.arguments {
2272            if let ast::InstantiationArgument::Spread(id) = arg {
2273                self.spread_instantiation_arg(state, id, &expected, &mut arguments)?;
2274            }
2275        }
2276
2277        // Create the instantiation node
2278        log::debug!(
2279            "adding instantiation for package `{pkg}` to the graph",
2280            pkg = BorrowedPackageKey::from_name_and_version(
2281                expr.package.name,
2282                expr.package.version.as_ref()
2283            )
2284        );
2285        let instantiation = state.graph.instantiate(pkg);
2286        let prev = state
2287            .instantiation_spans
2288            .insert(instantiation, expr.package.span);
2289        assert!(prev.is_none());
2290
2291        // Set the arguments on the instantiation
2292        for (name, (argument, span)) in &arguments {
2293            log::debug!("adding argument edge `{name}`");
2294            state
2295                .graph
2296                .set_instantiation_argument(instantiation, name, argument.node())
2297                .map_err(|e| match e {
2298                    InstantiationArgumentError::NodeIsNotAnInstantiation { .. } => {
2299                        panic!("node should be an instantiation")
2300                    }
2301                    InstantiationArgumentError::ArgumentAlreadyPassed { .. } => {
2302                        panic!("argument should not already be passed")
2303                    }
2304                    InstantiationArgumentError::InvalidArgumentName {
2305                        node: _,
2306                        name,
2307                        package,
2308                    } => Error::MissingComponentImport {
2309                        package,
2310                        import: name,
2311                        span: *span,
2312                    },
2313                    InstantiationArgumentError::ArgumentTypeMismatch { name, source } => {
2314                        Error::MismatchedInstantiationArg {
2315                            name,
2316                            span: *span,
2317                            source,
2318                        }
2319                    }
2320                })?;
2321        }
2322
2323        // If `...` was not present in the argument list, error if there are
2324        // any missing arguments; implicit arguments will be added during encoding
2325        if require_all {
2326            let world = &state.graph.types()[ty];
2327            if let Some((name, _)) = world
2328                .imports
2329                .iter()
2330                .find(|(n, _)| !arguments.contains_key(n.as_str()))
2331            {
2332                return Err(Error::MissingInstantiationArg {
2333                    name: name.clone(),
2334                    package: expr.package.string.to_string(),
2335                    span: expr.package.span,
2336                });
2337            }
2338        }
2339
2340        Ok(Item::Node(instantiation))
2341    }
2342
2343    fn find_matching_interface_name<'b>(
2344        name: &str,
2345        externs: &'b IndexMap<String, ItemKind>,
2346    ) -> Option<&'b str> {
2347        // If the given name exists directly, don't treat it as an interface name
2348        if externs.contains_key(name) {
2349            return None;
2350        }
2351
2352        // Fall back to searching for a matching interface name, provided it is not ambiguous
2353        // For example, match `foo:bar/baz` if `baz` is the identifier and the only match
2354        let mut matches = externs.iter().filter(|(n, _)| match n.rfind('/') {
2355            Some(start) => {
2356                let mut n = &n[start + 1..];
2357                if let Some(index) = n.find('@') {
2358                    n = &n[..index];
2359                }
2360                n == name
2361            }
2362            None => false,
2363        });
2364
2365        let (name, _) = matches.next()?;
2366        if matches.next().is_some() {
2367            // More than one match, the name is ambiguous
2368            return None;
2369        }
2370
2371        Some(name)
2372    }
2373
2374    fn named_instantiation_arg(
2375        &mut self,
2376        state: &mut State,
2377        arg: &'a ast::NamedInstantiationArgument<'a>,
2378        world: WorldId,
2379        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
2380    ) -> ResolutionResult<(String, Item, SourceSpan)> {
2381        let item = self.expr(state, &arg.expr, packages)?;
2382
2383        let name = match &arg.name {
2384            ast::InstantiationArgumentName::Ident(ident) => Self::find_matching_interface_name(
2385                ident.string,
2386                &state.graph.types()[world].imports,
2387            )
2388            .unwrap_or(ident.string),
2389            ast::InstantiationArgumentName::String(name) => name.value,
2390        };
2391
2392        Ok((name.to_owned(), item, arg.name.span()))
2393    }
2394
2395    fn inferred_instantiation_arg(
2396        &mut self,
2397        state: &mut State,
2398        ident: &ast::Ident<'a>,
2399        world: WorldId,
2400    ) -> ResolutionResult<(String, Item, SourceSpan)> {
2401        let (item, _) = state.local_item(ident)?;
2402        let world = &state.graph.types()[world];
2403        let kind = item.kind(&state.graph);
2404
2405        // If the item is an instance with an id, try the id.
2406        if let ItemKind::Instance(id) = kind {
2407            if let Some(id) = &state.graph.types()[id].id {
2408                if world.imports.contains_key(id.as_str()) {
2409                    return Ok((id.clone(), item, ident.span));
2410                }
2411            }
2412        }
2413
2414        // If the item comes from an import or an alias, try the name associated with it
2415        let node = item.node();
2416        if let Some(name) = state.graph.get_import_name(node) {
2417            if world.imports.contains_key(name) {
2418                return Ok((name.to_string(), item, ident.span));
2419            }
2420        } else if let Some((_, name)) = state.graph.get_alias_source(node) {
2421            if world.imports.contains_key(name) {
2422                return Ok((name.to_string(), item, ident.span));
2423            }
2424        }
2425
2426        // Fall back to searching for a matching interface name, provided it is not ambiguous
2427        // For example, match `foo:bar/baz` if `baz` is the identifier and the only match
2428        if let Some(name) = Self::find_matching_interface_name(ident.string, &world.imports) {
2429            return Ok((name.to_owned(), item, ident.span));
2430        }
2431
2432        // Finally default to the id itself
2433        Ok((ident.string.to_owned(), item, ident.span))
2434    }
2435
2436    fn spread_instantiation_arg(
2437        &mut self,
2438        state: &mut State,
2439        id: &ast::Ident,
2440        expected: &IndexSet<String>,
2441        arguments: &mut IndexMap<String, (Item, SourceSpan)>,
2442    ) -> ResolutionResult<()> {
2443        let item = state.local_item(id)?.0;
2444
2445        // The item must be an instance for a spread
2446        match item.kind(&state.graph) {
2447            ItemKind::Instance(_) => {}
2448            kind => {
2449                return Err(Error::NotAnInstance {
2450                    kind: kind.desc(state.graph.types()).to_string(),
2451                    operation: InstanceOperation::Spread,
2452                    span: id.span,
2453                })
2454            }
2455        }
2456
2457        let mut spread = false;
2458        for name in expected {
2459            // Check if the argument was already provided
2460            if arguments.contains_key(name) {
2461                continue;
2462            }
2463
2464            // Prefer an exact export name match, then fall back to a semver-compatible one
2465            let export_name = {
2466                let exports = match item.kind(&state.graph) {
2467                    ItemKind::Instance(id) => &state.graph.types()[id].exports,
2468                    _ => unreachable!("item was checked to be an instance"),
2469                };
2470
2471                if exports.contains_key(name) {
2472                    Some(name.clone())
2473                } else {
2474                    exports
2475                        .keys()
2476                        .find(|export| are_semver_compatible(export, name))
2477                        .cloned()
2478                }
2479            };
2480
2481            let Some(export_name) = export_name else {
2482                continue;
2483            };
2484
2485            // Alias the matching export of the instance
2486            if let Some(aliased) = self.alias_export(
2487                state,
2488                item,
2489                &export_name,
2490                id.span,
2491                InstanceOperation::Spread,
2492            )? {
2493                spread = true;
2494                arguments.insert(name.clone(), (aliased, id.span));
2495            }
2496        }
2497
2498        if !spread {
2499            return Err(Error::SpreadInstantiationNoMatch { span: id.span });
2500        }
2501
2502        Ok(())
2503    }
2504
2505    fn postfix_expr(
2506        &mut self,
2507        state: &mut State,
2508        item: Item,
2509        expr: &ast::PostfixExpr,
2510        parent_span: SourceSpan,
2511    ) -> ResolutionResult<Item> {
2512        match expr {
2513            ast::PostfixExpr::Access(expr) => {
2514                let exports = match item.kind(&state.graph) {
2515                    ItemKind::Instance(id) => &state.graph.types()[id].exports,
2516                    kind => {
2517                        return Err(Error::NotAnInstance {
2518                            kind: kind.desc(state.graph.types()).to_string(),
2519                            operation: InstanceOperation::Access,
2520                            span: parent_span,
2521                        })
2522                    }
2523                };
2524
2525                let name = Self::find_matching_interface_name(expr.id.string, exports)
2526                    .unwrap_or(expr.id.string)
2527                    .to_string();
2528
2529                self.alias_export(state, item, &name, parent_span, InstanceOperation::Access)?
2530                    .ok_or_else(|| Error::MissingInstanceExport {
2531                        name,
2532                        span: expr.span,
2533                    })
2534            }
2535            ast::PostfixExpr::NamedAccess(expr) => self
2536                .alias_export(
2537                    state,
2538                    item,
2539                    expr.string.value,
2540                    parent_span,
2541                    InstanceOperation::Access,
2542                )?
2543                .ok_or_else(|| Error::MissingInstanceExport {
2544                    name: expr.string.value.to_owned(),
2545                    span: expr.span,
2546                }),
2547        }
2548    }
2549
2550    fn alias_export(
2551        &self,
2552        state: &mut State,
2553        item: Item,
2554        name: &str,
2555        span: SourceSpan,
2556        operation: InstanceOperation,
2557    ) -> ResolutionResult<Option<Item>> {
2558        let exports = match item.kind(&state.graph) {
2559            ItemKind::Instance(id) => &state.graph.types()[id].exports,
2560            kind => {
2561                return Err(Error::NotAnInstance {
2562                    kind: kind.desc(state.graph.types()).to_string(),
2563                    operation,
2564                    span,
2565                })
2566            }
2567        };
2568
2569        if exports.get(name).is_none() {
2570            return Ok(None);
2571        }
2572
2573        let node = state
2574            .graph
2575            .alias_instance_export(item.node(), name)
2576            .expect("alias should be created");
2577
2578        // Insert the span if the node isn't new
2579        Ok(Some(Item::Node(node)))
2580    }
2581
2582    fn resolve_package_path(
2583        &mut self,
2584        state: &mut State,
2585        path: &'a ast::PackagePath<'a>,
2586        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
2587    ) -> ResolutionResult<ItemKind> {
2588        log::debug!("resolving package export `{path}`", path = path.string);
2589
2590        // Check for reference to local item
2591        if path.name == self.0.directive.package.name {
2592            return self.resolve_local_path(state, path);
2593        }
2594
2595        let id = self.resolve_package(
2596            state,
2597            path.name,
2598            path.version.as_ref(),
2599            path.package_name_span(),
2600            packages,
2601        )?;
2602
2603        let package = &state.graph[id];
2604        let mut current = 0;
2605        let mut parent_ty = None;
2606        let mut found = None;
2607        for (i, (segment, _)) in path.segment_spans().enumerate() {
2608            current = i;
2609
2610            // Look up the first segment in the package definitions
2611            if i == 0 {
2612                found = package.definitions().get(segment).copied();
2613                continue;
2614            }
2615
2616            // Otherwise, project into the parent based on the current segment
2617            let Some(parent) = found else { break };
2618            let export = match parent {
2619                // The parent is an interface or instance
2620                ItemKind::Type(Type::Interface(id)) | ItemKind::Instance(id) => {
2621                    state.graph.types()[id].exports.get(segment).copied()
2622                }
2623                // The parent is a world or component or component instantiation
2624                ItemKind::Type(Type::World(id)) | ItemKind::Component(id) => {
2625                    state.graph.types()[id].exports.get(segment).copied()
2626                }
2627                _ => None,
2628            };
2629
2630            parent_ty = found.map(|kind| kind.desc(state.graph.types()));
2631            found = export;
2632            if found.is_none() {
2633                break;
2634            }
2635        }
2636
2637        found.ok_or_else(|| {
2638            let segments = path.segment_spans().enumerate();
2639            let mut prev_path = String::new();
2640            for (i, (segment, span)) in segments {
2641                if i == current {
2642                    return Error::PackageMissingExport {
2643                        package: path.name.to_string(),
2644                        export: segment.to_string(),
2645                        kind: parent_ty.map(ToOwned::to_owned),
2646                        path: prev_path,
2647                        span,
2648                    };
2649                }
2650
2651                if !prev_path.is_empty() {
2652                    prev_path.push('/');
2653                }
2654
2655                prev_path.push_str(segment);
2656            }
2657
2658            unreachable!("path segments should never be empty")
2659        })
2660    }
2661
2662    fn resolve_local_path(
2663        &self,
2664        state: &State,
2665        path: &ast::PackagePath<'a>,
2666    ) -> ResolutionResult<ItemKind> {
2667        log::debug!("resolving local path `{path}`", path = path.string);
2668
2669        let mut segments = path.segment_spans();
2670        let (segment, span) = segments.next().unwrap();
2671        let (item, _) = state.root_item(&ast::Ident {
2672            string: segment,
2673            span,
2674        })?;
2675
2676        let mut current = segment;
2677        let mut kind = item.kind(&state.graph);
2678        for (segment, span) in segments {
2679            let exports = match kind {
2680                ItemKind::Type(Type::Interface(id)) | ItemKind::Instance(id) => {
2681                    &state.graph.types()[id].exports
2682                }
2683                ItemKind::Type(Type::World(id)) | ItemKind::Component(id) => {
2684                    &state.graph.types()[id].exports
2685                }
2686                _ => {
2687                    return Err(Error::PackagePathMissingExport {
2688                        name: current.to_string(),
2689                        kind: kind.desc(state.graph.types()).to_string(),
2690                        export: segment.to_string(),
2691                        span,
2692                    });
2693                }
2694            };
2695
2696            kind =
2697                exports
2698                    .get(segment)
2699                    .copied()
2700                    .ok_or_else(|| Error::PackagePathMissingExport {
2701                        name: current.to_string(),
2702                        kind: kind.desc(state.graph.types()).to_string(),
2703                        export: segment.to_string(),
2704                        span,
2705                    })?;
2706
2707            current = segment;
2708        }
2709
2710        Ok(kind)
2711    }
2712
2713    fn resolve_package(
2714        &mut self,
2715        state: &mut State,
2716        name: &'a str,
2717        version: Option<&'a Version>,
2718        span: SourceSpan,
2719        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
2720    ) -> ResolutionResult<PackageId> {
2721        match state.graph.get_package_by_name(name, version) {
2722            Some((id, _)) => Ok(id),
2723            None => {
2724                let bytes = packages
2725                    .swap_remove(&BorrowedPackageKey::from_name_and_version(name, version))
2726                    .ok_or_else(|| Error::UnknownPackage {
2727                        name: name.to_string(),
2728                        span,
2729                    })?;
2730
2731                log::debug!("registering package `{name}` with the graph");
2732                let package = Package::from_bytes(name, version, bytes, state.graph.types_mut())
2733                    .map_err(|e| Error::PackageParseFailure {
2734                        name: name.to_string(),
2735                        span,
2736                        source: e,
2737                    })?;
2738
2739                Ok(state
2740                    .graph
2741                    .register_package(package)
2742                    .expect("package should not exist"))
2743            }
2744        }
2745    }
2746
2747    fn validate_target(
2748        &self,
2749        state: &State,
2750        path: &ast::PackagePath,
2751        world: WorldId,
2752    ) -> ResolutionResult<()> {
2753        let world = &state.graph.types()[world];
2754        // The interfaces imported implicitly through uses.
2755        let implicit_imported_interfaces = world.implicit_imported_interfaces(state.graph.types());
2756        let mut cache = Default::default();
2757        let mut checker = SubtypeChecker::new(&mut cache);
2758
2759        // The output is allowed to import a subset of the world's imports
2760        checker.invert();
2761        for (name, item_kind, import_node) in state.graph.imports() {
2762            let expected = implicit_imported_interfaces
2763                .get(name)
2764                .or_else(|| world.imports.get(name))
2765                .ok_or_else(|| Error::ImportNotInTarget {
2766                    name: name.to_owned(),
2767                    world: path.string.to_owned(),
2768                    span: import_node.map(|n| state.import_spans[&n]),
2769                })?;
2770
2771            checker
2772                .is_subtype(
2773                    expected.promote(),
2774                    state.graph.types(),
2775                    item_kind,
2776                    state.graph.types(),
2777                )
2778                .map_err(|e| Error::TargetMismatch {
2779                    kind: ExternKind::Import,
2780                    name: name.to_owned(),
2781                    world: path.string.to_owned(),
2782                    span: import_node.map(|n| state.import_spans[&n]),
2783                    source: e,
2784                })?;
2785        }
2786
2787        checker.revert();
2788
2789        // The output must export every export in the world
2790        for (name, expected) in &world.exports {
2791            let export =
2792                state
2793                    .graph
2794                    .get_export(name)
2795                    .ok_or_else(|| Error::MissingTargetExport {
2796                        name: name.clone(),
2797                        world: path.string.to_owned(),
2798                        kind: expected.desc(state.graph.types()).to_string(),
2799                        span: path.span,
2800                    })?;
2801
2802            checker
2803                .is_subtype(
2804                    state.graph[export].item_kind(),
2805                    state.graph.types(),
2806                    expected.promote(),
2807                    state.graph.types(),
2808                )
2809                .map_err(|e| Error::TargetMismatch {
2810                    kind: ExternKind::Export,
2811                    name: name.clone(),
2812                    world: path.string.to_owned(),
2813                    span: state.export_spans.get(&export).copied(),
2814                    source: e,
2815                })?;
2816        }
2817
2818        Ok(())
2819    }
2820}