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        BorrowedPackageKey, DefinedType, Enum, ExternKind, Flags, FuncKind, FuncType, FuncTypeId,
14        Interface, InterfaceId, ItemKind, Package, PackageKey, PrimitiveType, Record, Resource,
15        ResourceAlias, ResourceId, SubtypeChecker, Type, UsedType, ValueType, Variant, World,
16        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            )?),
964            ast::ImportType::Interface(i) => {
965                ItemKind::Instance(self.inline_interface(state, i, packages)?)
966            }
967            ast::ImportType::Ident(id) => state.local_item(id)?.0.kind(&state.graph),
968        };
969
970        // Import the item
971        log::debug!("adding import `{name}` to the graph");
972        let node = state
973            .graph
974            .import(name, kind.promote())
975            .map_err(|e| map_import_error(state, e, span))?;
976
977        state.import_spans.insert(node, span);
978
979        // Register the local name
980        state.register_name(stmt.id, Item::Node(node))
981    }
982
983    fn type_statement(
984        &mut self,
985        state: &mut State,
986        stmt: &'a ast::TypeStatement<'a>,
987        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
988    ) -> ResolutionResult<()> {
989        log::debug!("resolving type statement");
990
991        let (id, ty) = match stmt {
992            ast::TypeStatement::Interface(i) => (i.id, self.interface_decl(state, i, packages)?),
993            ast::TypeStatement::World(w) => (w.id, self.world_decl(state, w, packages)?),
994            ast::TypeStatement::Type(t) => (
995                *t.id(),
996                match t {
997                    ast::TypeDecl::Variant(v) => self.variant_decl(state, v, false)?,
998                    ast::TypeDecl::Record(r) => self.record_decl(state, r, false)?,
999                    ast::TypeDecl::Flags(f) => self.flags_decl(state, f, false)?,
1000                    ast::TypeDecl::Enum(e) => self.enum_decl(state, e, false)?,
1001                    ast::TypeDecl::Alias(a) => self.type_alias(state, a, false)?,
1002                },
1003            ),
1004        };
1005
1006        log::debug!("adding type definition `{id}` to the graph", id = id.string);
1007        let node = state
1008            .graph
1009            .define_type(id.string, ty)
1010            .map_err(|e| match e {
1011                DefineTypeError::TypeAlreadyDefined => panic!("type should not be already defined"),
1012                DefineTypeError::CannotDefineResource => panic!("type should not be a resource"),
1013                DefineTypeError::InvalidExternName { .. } => panic!("parsed an invalid type name"),
1014                DefineTypeError::ExportConflict { name } => Error::DeclarationConflict {
1015                    name,
1016                    span: id.span,
1017                    export: state.export_spans[&state.graph.get_export(id.string).unwrap()],
1018                },
1019            })?;
1020
1021        state.export_spans.insert(node, id.span);
1022        state.register_name(id, Item::Node(node))
1023    }
1024
1025    fn let_statement(
1026        &mut self,
1027        state: &mut State,
1028        stmt: &'a ast::LetStatement<'a>,
1029        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
1030    ) -> ResolutionResult<()> {
1031        log::debug!("resolving let statement for id `{id}`", id = stmt.id.string);
1032        let item = self.expr(state, &stmt.expr, packages)?;
1033        state.register_name(stmt.id, item)
1034    }
1035
1036    fn export_statement(
1037        &mut self,
1038        state: &mut State,
1039        stmt: &'a ast::ExportStatement<'a>,
1040        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
1041    ) -> ResolutionResult<()> {
1042        log::debug!("resolving export statement");
1043
1044        let item = self.expr(state, &stmt.expr, packages)?;
1045        match &stmt.options {
1046            ast::ExportOptions::None => {
1047                let name = self
1048                    .infer_export_name(state, item)
1049                    .ok_or(Error::ExportRequiresAs {
1050                        span: stmt.expr.span,
1051                    })?;
1052
1053                self.export_item(state, item, name.to_owned(), stmt.expr.span, true)?;
1054            }
1055            ast::ExportOptions::Spread(span) => {
1056                let exports = match item.kind(&state.graph) {
1057                    ItemKind::Instance(id) => state.graph.types()[id]
1058                        .exports
1059                        .keys()
1060                        .cloned()
1061                        .collect::<Vec<_>>(),
1062                    kind => {
1063                        return Err(Error::NotAnInstance {
1064                            kind: kind.desc(state.graph.types()).to_string(),
1065                            operation: InstanceOperation::Spread,
1066                            span: stmt.expr.span,
1067                        })
1068                    }
1069                };
1070
1071                let mut exported = false;
1072                for name in exports {
1073                    // Only export the item if it another item with the same name
1074                    // has not been already exported
1075                    if state.graph.get_export(&name).is_some() {
1076                        continue;
1077                    }
1078
1079                    let item = self
1080                        .alias_export(
1081                            state,
1082                            item,
1083                            &name,
1084                            stmt.expr.span,
1085                            InstanceOperation::Spread,
1086                        )?
1087                        .expect("expected a matching export name");
1088
1089                    self.export_item(state, item, name, *span, false)?;
1090                    exported = true;
1091                }
1092
1093                if !exported {
1094                    return Err(Error::SpreadExportNoEffect {
1095                        span: stmt.expr.span,
1096                    });
1097                }
1098            }
1099            ast::ExportOptions::Rename(name) => {
1100                self.export_item(state, item, name.as_str().to_owned(), name.span(), false)?;
1101            }
1102        }
1103
1104        Ok(())
1105    }
1106
1107    fn infer_export_name<'b>(&self, state: &'b State, item: Item) -> Option<&'b str> {
1108        // If the item is an instance with an id, try the id.
1109        if let ItemKind::Instance(id) = item.kind(&state.graph) {
1110            if let Some(id) = &state.graph.types()[id].id {
1111                return Some(id);
1112            }
1113        }
1114
1115        // If the item comes from an import or an alias, try the name associated with it
1116        let node = item.node();
1117        if let Some(name) = state.graph.get_import_name(node) {
1118            Some(name)
1119        } else if let Some((_, name)) = state.graph.get_alias_source(node) {
1120            Some(name)
1121        } else {
1122            None
1123        }
1124    }
1125
1126    fn export_item(
1127        &self,
1128        state: &mut State,
1129        item: Item,
1130        name: String,
1131        span: SourceSpan,
1132        show_hint: bool,
1133    ) -> Result<(), Error> {
1134        if let Some((item, prev_span)) = state.root_scope().get(&name) {
1135            let node = &state.graph[item.node()];
1136            if let NodeKind::Definition = node.kind() {
1137                return Err(Error::ExportConflict {
1138                    name,
1139                    kind: node.item_kind().desc(state.graph.types()).to_string(),
1140                    span,
1141                    definition: prev_span,
1142                    help: if !show_hint {
1143                        None
1144                    } else {
1145                        Some("consider using an `as` clause to use a different name".into())
1146                    },
1147                });
1148            }
1149        }
1150
1151        let node = item.node();
1152        state.graph.export(item.node(), name).map_err(|e| match e {
1153            ExportError::ExportAlreadyExists { name, node } => Error::DuplicateExternName {
1154                name,
1155                kind: ExternKind::Export,
1156                span,
1157                previous: state.export_spans[&node],
1158                help: if !show_hint {
1159                    None
1160                } else {
1161                    Some("consider using an `as` clause to use a different name".into())
1162                },
1163            },
1164            wac_graph::ExportError::InvalidExportName { name, source } => {
1165                Error::InvalidExternName {
1166                    name,
1167                    kind: ExternKind::Export,
1168                    span,
1169                    source,
1170                }
1171            }
1172        })?;
1173
1174        state.export_spans.insert(node, span);
1175        Ok(())
1176    }
1177
1178    fn variant_decl(
1179        &mut self,
1180        state: &mut State,
1181        decl: &ast::VariantDecl<'a>,
1182        register_name: bool,
1183    ) -> ResolutionResult<Type> {
1184        log::debug!(
1185            "resolving variant declaration for id `{id}`",
1186            id = decl.id.string
1187        );
1188
1189        let mut cases = IndexMap::new();
1190        for case in &decl.cases {
1191            let ty = case.ty.as_ref().map(|ty| Self::ty(state, ty)).transpose()?;
1192            if cases.insert(case.id.string.into(), ty).is_some() {
1193                return Err(Error::DuplicateVariantCase {
1194                    case: case.id.string.to_string(),
1195                    name: decl.id.string.to_string(),
1196                    span: case.id.span,
1197                });
1198            }
1199        }
1200
1201        let ty = Type::Value(ValueType::Defined(
1202            state
1203                .graph
1204                .types_mut()
1205                .add_defined_type(DefinedType::Variant(Variant { cases })),
1206        ));
1207
1208        if register_name {
1209            state.register_name(decl.id, Item::Type(ty))?;
1210        }
1211
1212        Ok(ty)
1213    }
1214
1215    fn record_decl(
1216        &mut self,
1217        state: &mut State,
1218        decl: &ast::RecordDecl<'a>,
1219        register_name: bool,
1220    ) -> ResolutionResult<Type> {
1221        log::debug!(
1222            "resolving record declaration for id `{id}`",
1223            id = decl.id.string
1224        );
1225
1226        let mut fields = IndexMap::new();
1227        for field in &decl.fields {
1228            let ty = Self::ty(state, &field.ty)?;
1229            if fields.insert(field.id.string.into(), ty).is_some() {
1230                return Err(Error::DuplicateRecordField {
1231                    field: field.id.string.to_string(),
1232                    name: decl.id.string.to_string(),
1233                    span: field.id.span,
1234                });
1235            }
1236        }
1237
1238        let ty = Type::Value(ValueType::Defined(
1239            state
1240                .graph
1241                .types_mut()
1242                .add_defined_type(DefinedType::Record(Record { fields })),
1243        ));
1244
1245        if register_name {
1246            state.register_name(decl.id, Item::Type(ty))?;
1247        }
1248
1249        Ok(ty)
1250    }
1251
1252    fn flags_decl(
1253        &mut self,
1254        state: &mut State,
1255        decl: &ast::FlagsDecl<'a>,
1256        register_name: bool,
1257    ) -> ResolutionResult<Type> {
1258        log::debug!(
1259            "resolving flags declaration for id `{id}`",
1260            id = decl.id.string
1261        );
1262
1263        let mut flags = IndexSet::new();
1264        for flag in &decl.flags {
1265            if !flags.insert(flag.id.string.into()) {
1266                return Err(Error::DuplicateFlag {
1267                    flag: flag.id.string.to_string(),
1268                    name: decl.id.string.to_string(),
1269                    span: flag.id.span,
1270                });
1271            }
1272        }
1273
1274        let ty = Type::Value(ValueType::Defined(
1275            state
1276                .graph
1277                .types_mut()
1278                .add_defined_type(DefinedType::Flags(Flags(flags))),
1279        ));
1280
1281        if register_name {
1282            state.register_name(decl.id, Item::Type(ty))?;
1283        }
1284
1285        Ok(ty)
1286    }
1287
1288    fn enum_decl(
1289        &mut self,
1290        state: &mut State,
1291        decl: &ast::EnumDecl<'a>,
1292        register_name: bool,
1293    ) -> ResolutionResult<Type> {
1294        log::debug!(
1295            "resolving enum declaration for id `{id}`",
1296            id = decl.id.string
1297        );
1298
1299        let mut cases = IndexSet::new();
1300        for case in &decl.cases {
1301            if !cases.insert(case.id.string.to_owned()) {
1302                return Err(Error::DuplicateEnumCase {
1303                    case: case.id.string.to_string(),
1304                    name: decl.id.string.to_string(),
1305                    span: case.id.span,
1306                });
1307            }
1308        }
1309
1310        let ty = Type::Value(ValueType::Defined(
1311            state
1312                .graph
1313                .types_mut()
1314                .add_defined_type(DefinedType::Enum(Enum(cases))),
1315        ));
1316
1317        if register_name {
1318            state.register_name(decl.id, Item::Type(ty))?;
1319        }
1320
1321        Ok(ty)
1322    }
1323
1324    fn type_alias(
1325        &mut self,
1326        state: &mut State,
1327        alias: &ast::TypeAlias<'a>,
1328        register_name: bool,
1329    ) -> ResolutionResult<Type> {
1330        log::debug!("resolving type alias for id `{id}`", id = alias.id.string);
1331
1332        let ty = match &alias.kind {
1333            ast::TypeAliasKind::Func(f) => {
1334                Type::Func(self.func_type(state, &f.params, &f.results, FuncKind::Free, None)?)
1335            }
1336            ast::TypeAliasKind::Type(ty) => match ty {
1337                ast::Type::Ident(id) => {
1338                    let (item, _) = state.local_item(id)?;
1339                    match item.kind(&state.graph) {
1340                        ItemKind::Type(Type::Resource(id)) => {
1341                            let owner = state.graph.types()[id].alias.and_then(|a| a.owner);
1342                            Type::Resource(state.graph.types_mut().add_resource(Resource {
1343                                name: alias.id.string.to_owned(),
1344                                alias: Some(ResourceAlias { owner, source: id }),
1345                            }))
1346                        }
1347                        ItemKind::Type(Type::Value(ty)) => Type::Value(ValueType::Defined(
1348                            state
1349                                .graph
1350                                .types_mut()
1351                                .add_defined_type(DefinedType::Alias(ty)),
1352                        )),
1353                        ItemKind::Type(Type::Func(id)) | ItemKind::Func(id) => {
1354                            let ty = state.graph.types()[id].clone();
1355                            Type::Func(state.graph.types_mut().add_func_type(ty))
1356                        }
1357                        kind => {
1358                            return Err(Error::InvalidAliasType {
1359                                name: id.string.to_string(),
1360                                kind: kind.desc(state.graph.types()).to_string(),
1361                                span: id.span,
1362                            });
1363                        }
1364                    }
1365                }
1366                _ => {
1367                    let ty = Self::ty(state, ty)?;
1368                    Type::Value(ValueType::Defined(
1369                        state
1370                            .graph
1371                            .types_mut()
1372                            .add_defined_type(DefinedType::Alias(ty)),
1373                    ))
1374                }
1375            },
1376        };
1377
1378        if register_name {
1379            state.register_name(alias.id, Item::Type(ty))?;
1380        }
1381
1382        Ok(ty)
1383    }
1384
1385    fn func_type_ref(
1386        &mut self,
1387        state: &mut State,
1388        r: &ast::FuncTypeRef<'a>,
1389        kind: FuncKind,
1390    ) -> ResolutionResult<FuncTypeId> {
1391        match r {
1392            ast::FuncTypeRef::Func(ty) => {
1393                self.func_type(state, &ty.params, &ty.results, kind, None)
1394            }
1395            ast::FuncTypeRef::Ident(id) => {
1396                let (item, _) = state.local_item(id)?;
1397                match item.kind(&state.graph) {
1398                    ItemKind::Type(Type::Func(id)) | ItemKind::Func(id) => Ok(id),
1399                    kind => Err(Error::NotFuncType {
1400                        name: id.string.to_string(),
1401                        kind: kind.desc(state.graph.types()).to_string(),
1402                        span: id.span,
1403                    }),
1404                }
1405            }
1406        }
1407    }
1408
1409    fn ty(state: &mut State, ty: &ast::Type<'a>) -> ResolutionResult<ValueType> {
1410        match ty {
1411            ast::Type::U8(_) => Ok(ValueType::Primitive(PrimitiveType::U8)),
1412            ast::Type::S8(_) => Ok(ValueType::Primitive(PrimitiveType::S8)),
1413            ast::Type::U16(_) => Ok(ValueType::Primitive(PrimitiveType::U16)),
1414            ast::Type::S16(_) => Ok(ValueType::Primitive(PrimitiveType::S16)),
1415            ast::Type::U32(_) => Ok(ValueType::Primitive(PrimitiveType::U32)),
1416            ast::Type::S32(_) => Ok(ValueType::Primitive(PrimitiveType::S32)),
1417            ast::Type::U64(_) => Ok(ValueType::Primitive(PrimitiveType::U64)),
1418            ast::Type::S64(_) => Ok(ValueType::Primitive(PrimitiveType::S64)),
1419            ast::Type::F32(_) => Ok(ValueType::Primitive(PrimitiveType::F32)),
1420            ast::Type::F64(_) => Ok(ValueType::Primitive(PrimitiveType::F64)),
1421            ast::Type::Char(_) => Ok(ValueType::Primitive(PrimitiveType::Char)),
1422            ast::Type::Bool(_) => Ok(ValueType::Primitive(PrimitiveType::Bool)),
1423            ast::Type::String(_) => Ok(ValueType::Primitive(PrimitiveType::String)),
1424            ast::Type::Tuple(v, _) => {
1425                let tuple = DefinedType::Tuple(
1426                    v.iter()
1427                        .map(|ty| Self::ty(state, ty))
1428                        .collect::<ResolutionResult<_>>()?,
1429                );
1430
1431                Ok(ValueType::Defined(
1432                    state.graph.types_mut().add_defined_type(tuple),
1433                ))
1434            }
1435            ast::Type::List(ty, _) => {
1436                let ty = Self::ty(state, ty)?;
1437                Ok(ValueType::Defined(
1438                    state
1439                        .graph
1440                        .types_mut()
1441                        .add_defined_type(DefinedType::List(ty)),
1442                ))
1443            }
1444            ast::Type::Option(ty, _) => {
1445                let ty = Self::ty(state, ty)?;
1446                Ok(ValueType::Defined(
1447                    state
1448                        .graph
1449                        .types_mut()
1450                        .add_defined_type(DefinedType::Option(ty)),
1451                ))
1452            }
1453            ast::Type::Result { ok, err, .. } => {
1454                let ok = ok.as_ref().map(|t| Self::ty(state, t)).transpose()?;
1455                let err = err.as_ref().map(|t| Self::ty(state, t)).transpose()?;
1456                Ok(ValueType::Defined(
1457                    state
1458                        .graph
1459                        .types_mut()
1460                        .add_defined_type(DefinedType::Result { ok, err }),
1461                ))
1462            }
1463            ast::Type::Borrow(id, _) => {
1464                let (item, _) = state.local_item(id)?;
1465                let kind = item.kind(&state.graph);
1466                if let ItemKind::Type(Type::Resource(id)) = kind {
1467                    return Ok(ValueType::Borrow(id));
1468                }
1469
1470                Err(Error::NotResourceType {
1471                    name: id.string.to_string(),
1472                    kind: kind.desc(state.graph.types()).to_string(),
1473                    span: id.span,
1474                })
1475            }
1476            ast::Type::Ident(id) => {
1477                let (item, _) = state.local_item(id)?;
1478                let kind = item.kind(&state.graph);
1479                match kind {
1480                    ItemKind::Type(Type::Resource(id)) => Ok(ValueType::Own(id)),
1481                    ItemKind::Type(Type::Value(ty)) => Ok(ty),
1482                    _ => Err(Error::NotValueType {
1483                        name: id.string.to_string(),
1484                        kind: kind.desc(state.graph.types()).to_string(),
1485                        span: id.span,
1486                    }),
1487                }
1488            }
1489        }
1490    }
1491
1492    fn id(&self, name: &str) -> String {
1493        format!(
1494            "{pkg}/{name}{version}",
1495            pkg = self.0.directive.package.name,
1496            version = if let Some(version) = &self.0.directive.package.version {
1497                format!("@{version}")
1498            } else {
1499                String::new()
1500            }
1501        )
1502    }
1503
1504    fn interface_decl(
1505        &mut self,
1506        state: &mut State,
1507        decl: &'a ast::InterfaceDecl<'a>,
1508        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
1509    ) -> ResolutionResult<Type> {
1510        log::debug!(
1511            "resolving interface declaration for id `{id}`",
1512            id = decl.id.string
1513        );
1514        state.push_scope();
1515
1516        let mut ty = Interface {
1517            id: Some(self.id(decl.id.string)),
1518            uses: Default::default(),
1519            exports: Default::default(),
1520        };
1521
1522        self.interface_items(state, Some(decl.id.string), &decl.items, packages, &mut ty)?;
1523
1524        state.pop_scope();
1525
1526        Ok(Type::Interface(state.graph.types_mut().add_interface(ty)))
1527    }
1528
1529    fn world_decl(
1530        &mut self,
1531        state: &mut State,
1532        decl: &'a ast::WorldDecl<'a>,
1533        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
1534    ) -> ResolutionResult<Type> {
1535        log::debug!(
1536            "resolving world declaration for id `{id}`",
1537            id = decl.id.string
1538        );
1539        state.push_scope();
1540
1541        let mut ty = World {
1542            id: Some(self.id(decl.id.string)),
1543            uses: Default::default(),
1544            imports: Default::default(),
1545            exports: Default::default(),
1546        };
1547
1548        self.world_items(state, decl.id.string, &decl.items, packages, &mut ty)?;
1549
1550        state.pop_scope();
1551
1552        Ok(Type::World(state.graph.types_mut().add_world(ty)))
1553    }
1554
1555    fn world_items(
1556        &mut self,
1557        state: &mut State,
1558        world: &'a str,
1559        items: &'a [ast::WorldItem<'a>],
1560        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
1561        ty: &mut World,
1562    ) -> ResolutionResult<()> {
1563        let mut includes = Vec::new();
1564        for item in items {
1565            match item {
1566                ast::WorldItem::Use(u) => {
1567                    self.use_type(state, u, &mut ty.uses, &mut ty.imports, packages, true)?
1568                }
1569                ast::WorldItem::Type(decl) => {
1570                    self.item_type_decl(state, decl, &mut ty.imports)?;
1571                }
1572                ast::WorldItem::Import(i) => {
1573                    self.world_item_path(state, &i.path, ExternKind::Import, world, packages, ty)?
1574                }
1575                ast::WorldItem::Export(e) => {
1576                    self.world_item_path(state, &e.path, ExternKind::Export, world, packages, ty)?
1577                }
1578                ast::WorldItem::Include(i) => {
1579                    // We delay processing includes until after all other items have been processed
1580                    includes.push(i);
1581                }
1582            }
1583        }
1584
1585        // Process the includes now that all imports and exports have been processed.
1586        // This allows us to detect conflicts only in explicitly defined items.
1587        for i in includes {
1588            self.world_include(state, i, world, packages, ty)?;
1589        }
1590
1591        Ok(())
1592    }
1593
1594    fn world_item_path(
1595        &mut self,
1596        state: &mut State,
1597        path: &'a ast::WorldItemPath<'a>,
1598        kind: ExternKind,
1599        world: &'a str,
1600        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
1601        ty: &mut World,
1602    ) -> ResolutionResult<()> {
1603        let (k, v) = match path {
1604            ast::WorldItemPath::Named(named) => {
1605                check_name(named.id.string, named.id.span, ty, world, kind)?;
1606
1607                (
1608                    named.id.string.into(),
1609                    match &named.ty {
1610                        ast::ExternType::Ident(id) => {
1611                            let (item, _) = state.local_or_root_item(id)?;
1612                            match item.kind(&state.graph) {
1613                                ItemKind::Type(Type::Interface(id)) => ItemKind::Instance(id),
1614                                ItemKind::Type(Type::Func(id)) => ItemKind::Func(id),
1615                                kind => {
1616                                    return Err(Error::NotFuncOrInterface {
1617                                        name: id.string.to_owned(),
1618                                        kind: kind.desc(state.graph.types()).to_owned(),
1619                                        span: id.span,
1620                                    });
1621                                }
1622                            }
1623                        }
1624                        ast::ExternType::Func(f) => ItemKind::Func(self.func_type(
1625                            state,
1626                            &f.params,
1627                            &f.results,
1628                            FuncKind::Free,
1629                            None,
1630                        )?),
1631                        ast::ExternType::Interface(i) => {
1632                            ItemKind::Instance(self.inline_interface(state, i, packages)?)
1633                        }
1634                    },
1635                )
1636            }
1637            ast::WorldItemPath::Ident(id) => {
1638                let (item, _) = state.root_item(id)?;
1639                match item.kind(&state.graph) {
1640                    ItemKind::Type(Type::Interface(iface_ty_id)) => {
1641                        let iface_id = state.graph.types()[iface_ty_id]
1642                            .id
1643                            .as_ref()
1644                            .expect("expected an interface id");
1645                        check_name(iface_id, id.span, ty, world, kind)?;
1646                        (iface_id.clone(), ItemKind::Instance(iface_ty_id))
1647                    }
1648                    kind => {
1649                        return Err(Error::NotInterface {
1650                            name: id.string.to_owned(),
1651                            kind: kind.desc(state.graph.types()).to_owned(),
1652                            span: id.span,
1653                        });
1654                    }
1655                }
1656            }
1657
1658            ast::WorldItemPath::Package(p) => {
1659                match self.resolve_package_path(state, p, packages)? {
1660                    ItemKind::Type(Type::Interface(id)) => {
1661                        let name = state.graph.types()[id]
1662                            .id
1663                            .as_ref()
1664                            .expect("expected an interface id");
1665                        check_name(name, p.span, ty, world, kind)?;
1666                        (name.clone(), ItemKind::Instance(id))
1667                    }
1668                    kind => {
1669                        return Err(Error::NotInterface {
1670                            name: p.string.to_owned(),
1671                            kind: kind.desc(state.graph.types()).to_owned(),
1672                            span: p.span,
1673                        });
1674                    }
1675                }
1676            }
1677        };
1678
1679        if kind == ExternKind::Import {
1680            ty.imports.insert(k, v);
1681        } else {
1682            ty.exports.insert(k, v);
1683        }
1684
1685        return Ok(());
1686
1687        fn check_name(
1688            name: &str,
1689            span: SourceSpan,
1690            ty: &World,
1691            world: &str,
1692            kind: ExternKind,
1693        ) -> ResolutionResult<()> {
1694            let exists: bool = if kind == ExternKind::Import {
1695                ty.imports.contains_key(name)
1696            } else {
1697                ty.exports.contains_key(name)
1698            };
1699
1700            if exists {
1701                return Err(Error::DuplicateWorldItem {
1702                    kind,
1703                    name: name.to_owned(),
1704                    world: world.to_owned(),
1705                    span,
1706                });
1707            }
1708
1709            Ok(())
1710        }
1711    }
1712
1713    fn world_include(
1714        &mut self,
1715        state: &mut State,
1716        include: &'a ast::WorldInclude<'a>,
1717        world: &'a str,
1718        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
1719        ty: &mut World,
1720    ) -> ResolutionResult<()> {
1721        log::debug!("resolving include of world `{world}`");
1722        let mut replacements = HashMap::new();
1723        for item in &include.with {
1724            let prev = replacements.insert(item.from.string, item);
1725            if prev.is_some() {
1726                return Err(Error::DuplicateWorldIncludeName {
1727                    name: item.from.string.to_owned(),
1728                    span: item.from.span,
1729                });
1730            }
1731        }
1732
1733        let id = match &include.world {
1734            ast::WorldRef::Ident(id) => {
1735                let (item, _) = state.root_item(id)?;
1736                match item.kind(&state.graph) {
1737                    ItemKind::Type(Type::World(id)) | ItemKind::Component(id) => id,
1738                    kind => {
1739                        return Err(Error::NotWorld {
1740                            name: id.string.to_owned(),
1741                            kind: kind.desc(state.graph.types()).to_owned(),
1742                            span: id.span,
1743                        });
1744                    }
1745                }
1746            }
1747            ast::WorldRef::Package(path) => {
1748                match self.resolve_package_path(state, path, packages)? {
1749                    ItemKind::Type(Type::World(id)) | ItemKind::Component(id) => id,
1750                    kind => {
1751                        return Err(Error::NotWorld {
1752                            name: path.string.to_owned(),
1753                            kind: kind.desc(state.graph.types()).to_owned(),
1754                            span: path.span,
1755                        });
1756                    }
1757                }
1758            }
1759        };
1760
1761        let other = &state.graph.types()[id];
1762        for (name, item) in &other.imports {
1763            let name = replace_name(
1764                include,
1765                world,
1766                ty,
1767                name,
1768                ExternKind::Import,
1769                &mut replacements,
1770            )?;
1771            ty.imports.entry(name).or_insert(*item);
1772        }
1773
1774        for (name, item) in &other.exports {
1775            let name = replace_name(
1776                include,
1777                world,
1778                ty,
1779                name,
1780                ExternKind::Export,
1781                &mut replacements,
1782            )?;
1783            ty.exports.entry(name).or_insert(*item);
1784        }
1785
1786        if let Some(missing) = replacements.values().next() {
1787            return Err(Error::MissingWorldInclude {
1788                world: include.world.name().to_owned(),
1789                name: missing.from.string.to_owned(),
1790                span: missing.from.span,
1791            });
1792        }
1793
1794        return Ok(());
1795
1796        fn replace_name<'a>(
1797            include: &ast::WorldInclude<'a>,
1798            world: &'a str,
1799            ty: &mut World,
1800            name: &str,
1801            kind: ExternKind,
1802            replacements: &mut HashMap<&str, &ast::WorldIncludeItem<'a>>,
1803        ) -> ResolutionResult<String> {
1804            // Check for a id, which doesn't get replaced.
1805            if name.contains(':') {
1806                return Ok(name.to_owned());
1807            }
1808
1809            let (name, span) = replacements
1810                .remove(name)
1811                .map(|i| (i.to.string, i.to.span))
1812                .unwrap_or_else(|| (name, include.world.span()));
1813
1814            let exists = if kind == ExternKind::Import {
1815                ty.imports.contains_key(name)
1816            } else {
1817                ty.exports.contains_key(name)
1818            };
1819
1820            if exists {
1821                return Err(Error::WorldIncludeConflict {
1822                    kind,
1823                    name: name.to_owned(),
1824                    from: include.world.name().to_owned(),
1825                    to: world.to_owned(),
1826                    span,
1827                    help: if !include.with.is_empty() {
1828                        None
1829                    } else {
1830                        Some("consider using a `with` clause to use a different name".into())
1831                    },
1832                });
1833            }
1834
1835            Ok(name.to_owned())
1836        }
1837    }
1838
1839    fn inline_interface(
1840        &mut self,
1841        state: &mut State,
1842        iface: &'a ast::InlineInterface<'a>,
1843        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
1844    ) -> ResolutionResult<InterfaceId> {
1845        log::debug!("resolving inline interface");
1846
1847        state.push_scope();
1848
1849        let mut ty = Interface {
1850            id: None,
1851            uses: Default::default(),
1852            exports: Default::default(),
1853        };
1854
1855        self.interface_items(state, None, &iface.items, packages, &mut ty)?;
1856
1857        state.pop_scope();
1858
1859        Ok(state.graph.types_mut().add_interface(ty))
1860    }
1861
1862    fn interface_items(
1863        &mut self,
1864        state: &mut State,
1865        name: Option<&'a str>,
1866        items: &'a [ast::InterfaceItem<'a>],
1867        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
1868        ty: &mut Interface,
1869    ) -> ResolutionResult<()> {
1870        for item in items {
1871            match item {
1872                ast::InterfaceItem::Use(u) => {
1873                    self.use_type(state, u, &mut ty.uses, &mut ty.exports, packages, false)?
1874                }
1875                ast::InterfaceItem::Type(decl) => {
1876                    self.item_type_decl(state, decl, &mut ty.exports)?;
1877                }
1878                ast::InterfaceItem::Export(e) => {
1879                    let kind = ItemKind::Func(self.func_type_ref(state, &e.ty, FuncKind::Free)?);
1880                    if ty.exports.insert(e.id.string.into(), kind).is_some() {
1881                        return Err(Error::DuplicateInterfaceExport {
1882                            name: e.id.string.to_owned(),
1883                            interface_name: name.map(ToOwned::to_owned),
1884                            span: e.id.span,
1885                        });
1886                    }
1887                }
1888            }
1889        }
1890
1891        Ok(())
1892    }
1893
1894    fn use_type(
1895        &mut self,
1896        state: &mut State,
1897        use_type: &'a ast::Use<'a>,
1898        uses: &mut IndexMap<String, UsedType>,
1899        externs: &mut IndexMap<String, ItemKind>,
1900        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
1901        in_world: bool,
1902    ) -> ResolutionResult<()> {
1903        let (interface, name) = match &use_type.path {
1904            ast::UsePath::Package(path) => {
1905                match self.resolve_package_path(state, path, packages)? {
1906                    ItemKind::Type(Type::Interface(id)) => (id, path.string),
1907                    kind => {
1908                        return Err(Error::NotInterface {
1909                            name: path.string.to_owned(),
1910                            kind: kind.desc(state.graph.types()).to_owned(),
1911                            span: path.span,
1912                        });
1913                    }
1914                }
1915            }
1916            ast::UsePath::Ident(id) => {
1917                let (item, _) = state.root_item(id)?;
1918                let kind = item.kind(&state.graph);
1919                match kind {
1920                    ItemKind::Type(Type::Interface(iface_ty_id)) => (iface_ty_id, id.string),
1921                    _ => {
1922                        return Err(Error::NotInterface {
1923                            name: id.string.to_owned(),
1924                            kind: kind.desc(state.graph.types()).to_owned(),
1925                            span: id.span,
1926                        });
1927                    }
1928                }
1929            }
1930        };
1931
1932        for item in &use_type.items {
1933            let ident = item.as_id.unwrap_or(item.id);
1934            let kind = state.graph.types()[interface]
1935                .exports
1936                .get(item.id.string)
1937                .ok_or(Error::UndefinedInterfaceType {
1938                    name: item.id.string.to_string(),
1939                    interface_name: name.to_string(),
1940                    span: item.id.span,
1941                })?;
1942
1943            match kind {
1944                ItemKind::Type(ty @ Type::Resource(_)) | ItemKind::Type(ty @ Type::Value(_)) => {
1945                    if externs.contains_key(ident.string) {
1946                        return Err(Error::UseConflict {
1947                            name: ident.string.to_string(),
1948                            kind: if in_world {
1949                                ExternKind::Import
1950                            } else {
1951                                ExternKind::Export
1952                            },
1953                            span: ident.span,
1954                            help: if item.as_id.is_some() {
1955                                None
1956                            } else {
1957                                Some("consider using an `as` clause to use a different name".into())
1958                            },
1959                        });
1960                    }
1961
1962                    uses.insert(
1963                        ident.string.into(),
1964                        UsedType {
1965                            interface,
1966                            name: item.as_id.map(|_| item.id.string.to_string()),
1967                        },
1968                    );
1969                    externs.insert(ident.string.into(), *kind);
1970                    state.register_name(ident, Item::Use(*ty))?;
1971                }
1972                _ => {
1973                    return Err(Error::NotInterfaceValueType {
1974                        name: item.id.string.to_string(),
1975                        kind: kind.desc(state.graph.types()).to_string(),
1976                        interface_name: name.to_string(),
1977                        span: item.id.span,
1978                    });
1979                }
1980            }
1981        }
1982
1983        Ok(())
1984    }
1985
1986    fn item_type_decl(
1987        &mut self,
1988        state: &mut State,
1989        decl: &'a ast::ItemTypeDecl,
1990        externs: &mut IndexMap<String, ItemKind>,
1991    ) -> ResolutionResult<()> {
1992        let (insert, ty) = match decl {
1993            ast::ItemTypeDecl::Resource(r) => (false, self.resource_decl(state, r, externs)?),
1994            ast::ItemTypeDecl::Variant(v) => (true, self.variant_decl(state, v, true)?),
1995            ast::ItemTypeDecl::Record(r) => (true, self.record_decl(state, r, true)?),
1996            ast::ItemTypeDecl::Flags(f) => (true, self.flags_decl(state, f, true)?),
1997            ast::ItemTypeDecl::Enum(e) => (true, self.enum_decl(state, e, true)?),
1998            ast::ItemTypeDecl::Alias(a) => (true, self.type_alias(state, a, true)?),
1999        };
2000
2001        if insert {
2002            let prev = externs.insert(decl.id().string.into(), ItemKind::Type(ty));
2003            assert!(prev.is_none(), "duplicate type in scope");
2004        }
2005
2006        Ok(())
2007    }
2008
2009    fn resource_decl(
2010        &mut self,
2011        state: &mut State,
2012        decl: &ast::ResourceDecl<'a>,
2013        externs: &mut IndexMap<String, ItemKind>,
2014    ) -> ResolutionResult<Type> {
2015        log::debug!(
2016            "resolving resource declaration for id `{id}`",
2017            id = decl.id.string
2018        );
2019
2020        // Define the resource before resolving the methods
2021        let id = state.graph.types_mut().add_resource(Resource {
2022            name: decl.id.string.to_owned(),
2023            alias: None,
2024        });
2025
2026        let ty = Type::Resource(id);
2027        state.register_name(decl.id, Item::Type(ty))?;
2028
2029        // We must add the resource to the externs before any methods
2030        let prev = externs.insert(decl.id.string.into(), ItemKind::Type(ty));
2031        assert!(prev.is_none());
2032
2033        let mut names = HashSet::new();
2034        for method in &decl.methods {
2035            let (name, ty) = match method {
2036                ast::ResourceMethod::Constructor(ast::Constructor { span, params, .. }) => {
2037                    if !names.insert("") {
2038                        return Err(Error::DuplicateResourceConstructor {
2039                            resource: decl.id.string.to_string(),
2040                            span: *span,
2041                        });
2042                    }
2043
2044                    (
2045                        method_extern_name(decl.id.string, "", FuncKind::Constructor),
2046                        self.func_type(
2047                            state,
2048                            params,
2049                            &ast::ResultList::Empty,
2050                            FuncKind::Constructor,
2051                            Some(id),
2052                        )?,
2053                    )
2054                }
2055                ast::ResourceMethod::Method(ast::Method {
2056                    id: method_id,
2057                    is_static,
2058                    ty,
2059                    ..
2060                }) => {
2061                    let kind = if *is_static {
2062                        FuncKind::Static
2063                    } else {
2064                        FuncKind::Method
2065                    };
2066
2067                    if !names.insert(method_id.string) {
2068                        return Err(Error::DuplicateResourceMethod {
2069                            name: method_id.string.to_string(),
2070                            resource: decl.id.string.to_string(),
2071                            span: method_id.span,
2072                        });
2073                    }
2074
2075                    (
2076                        method_extern_name(decl.id.string, method_id.string, kind),
2077                        self.func_type(state, &ty.params, &ty.results, kind, Some(id))?,
2078                    )
2079                }
2080            };
2081
2082            let prev = externs.insert(name, ItemKind::Func(ty));
2083            assert!(prev.is_none());
2084        }
2085
2086        Ok(ty)
2087    }
2088
2089    fn func_type(
2090        &mut self,
2091        state: &mut State,
2092        func_params: &[ast::NamedType<'a>],
2093        func_results: &ast::ResultList<'a>,
2094        kind: FuncKind,
2095        resource: Option<ResourceId>,
2096    ) -> ResolutionResult<FuncTypeId> {
2097        let mut params = IndexMap::new();
2098
2099        if kind == FuncKind::Method {
2100            params.insert("self".into(), ValueType::Borrow(resource.unwrap()));
2101        }
2102
2103        for param in func_params {
2104            if params
2105                .insert(param.id.string.into(), Self::ty(state, &param.ty)?)
2106                .is_some()
2107            {
2108                return Err(Error::DuplicateParameter {
2109                    name: param.id.string.to_string(),
2110                    kind,
2111                    span: param.id.span,
2112                });
2113            }
2114        }
2115
2116        let result = match func_results {
2117            ast::ResultList::Empty => {
2118                if kind == FuncKind::Constructor {
2119                    Some(ValueType::Own(resource.unwrap()))
2120                } else {
2121                    None
2122                }
2123            }
2124            ast::ResultList::Scalar(ty) => {
2125                let value_type = Self::ty(state, ty)?;
2126                if value_type.contains_borrow(state.graph.types()) {
2127                    return Err(Error::BorrowInResult { span: ty.span() });
2128                }
2129                Some(value_type)
2130            }
2131        };
2132
2133        Ok(state
2134            .graph
2135            .types_mut()
2136            .add_func_type(FuncType { params, result }))
2137    }
2138
2139    fn expr(
2140        &mut self,
2141        state: &mut State,
2142        expr: &'a ast::Expr<'a>,
2143        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
2144    ) -> ResolutionResult<Item> {
2145        let mut item = self.primary_expr(state, &expr.primary, packages)?;
2146
2147        let mut parent_span = expr.primary.span();
2148        for expr in &expr.postfix {
2149            item = self.postfix_expr(state, item, expr, parent_span)?;
2150            parent_span = expr.span();
2151        }
2152
2153        Ok(item)
2154    }
2155
2156    fn primary_expr(
2157        &mut self,
2158        state: &mut State,
2159        expr: &'a ast::PrimaryExpr<'a>,
2160        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
2161    ) -> ResolutionResult<Item> {
2162        match expr {
2163            ast::PrimaryExpr::New(e) => self.new_expr(state, e, packages),
2164            ast::PrimaryExpr::Nested(e) => self.expr(state, &e.inner, packages),
2165            ast::PrimaryExpr::Ident(i) => Ok(state.local_item(i)?.0),
2166        }
2167    }
2168
2169    fn new_expr(
2170        &mut self,
2171        state: &mut State,
2172        expr: &'a ast::NewExpr<'a>,
2173        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
2174    ) -> ResolutionResult<Item> {
2175        log::debug!(
2176            "resolving new expression for package `{pkg}`",
2177            pkg = BorrowedPackageKey::from_name_and_version(
2178                expr.package.name,
2179                expr.package.version.as_ref()
2180            )
2181        );
2182
2183        if expr.package.name == self.0.directive.package.name {
2184            return Err(Error::UnknownPackage {
2185                name: expr.package.name.to_string(),
2186                span: expr.package.span,
2187            });
2188        }
2189
2190        let pkg = self.resolve_package(
2191            state,
2192            expr.package.name,
2193            expr.package.version.as_ref(),
2194            expr.package.span,
2195            packages,
2196        )?;
2197        let ty = state.graph[pkg].ty();
2198        let expected = state.graph.types()[ty]
2199            .imports
2200            .keys()
2201            .cloned()
2202            .collect::<IndexSet<_>>();
2203        let mut require_all = true;
2204
2205        let mut arguments: IndexMap<String, (Item, SourceSpan)> = Default::default();
2206        for (i, arg) in expr.arguments.iter().enumerate() {
2207            let (name, item, span) = match arg {
2208                ast::InstantiationArgument::Inferred(id) => {
2209                    self.inferred_instantiation_arg(state, id, ty)?
2210                }
2211                ast::InstantiationArgument::Spread(_) => {
2212                    // Spread arguments will be processed after all other arguments
2213                    continue;
2214                }
2215                ast::InstantiationArgument::Named(arg) => {
2216                    self.named_instantiation_arg(state, arg, ty, packages)?
2217                }
2218                ast::InstantiationArgument::Fill(span) => {
2219                    if i != (expr.arguments.len() - 1) {
2220                        return Err(Error::FillArgumentNotLast { span: *span });
2221                    }
2222
2223                    require_all = false;
2224                    continue;
2225                }
2226            };
2227
2228            let prev = arguments.insert(name.clone(), (item, span));
2229            if prev.is_some() {
2230                return Err(Error::DuplicateInstantiationArg { name, span });
2231            }
2232        }
2233
2234        // Process the spread arguments
2235        for arg in &expr.arguments {
2236            if let ast::InstantiationArgument::Spread(id) = arg {
2237                self.spread_instantiation_arg(state, id, &expected, &mut arguments)?;
2238            }
2239        }
2240
2241        // Create the instantiation node
2242        log::debug!(
2243            "adding instantiation for package `{pkg}` to the graph",
2244            pkg = BorrowedPackageKey::from_name_and_version(
2245                expr.package.name,
2246                expr.package.version.as_ref()
2247            )
2248        );
2249        let instantiation = state.graph.instantiate(pkg);
2250        let prev = state
2251            .instantiation_spans
2252            .insert(instantiation, expr.package.span);
2253        assert!(prev.is_none());
2254
2255        // Set the arguments on the instantiation
2256        for (name, (argument, span)) in &arguments {
2257            log::debug!("adding argument edge `{name}`");
2258            state
2259                .graph
2260                .set_instantiation_argument(instantiation, name, argument.node())
2261                .map_err(|e| match e {
2262                    InstantiationArgumentError::NodeIsNotAnInstantiation { .. } => {
2263                        panic!("node should be an instantiation")
2264                    }
2265                    InstantiationArgumentError::ArgumentAlreadyPassed { .. } => {
2266                        panic!("argument should not already be passed")
2267                    }
2268                    InstantiationArgumentError::InvalidArgumentName {
2269                        node: _,
2270                        name,
2271                        package,
2272                    } => Error::MissingComponentImport {
2273                        package,
2274                        import: name,
2275                        span: *span,
2276                    },
2277                    InstantiationArgumentError::ArgumentTypeMismatch { name, source } => {
2278                        Error::MismatchedInstantiationArg {
2279                            name,
2280                            span: *span,
2281                            source,
2282                        }
2283                    }
2284                })?;
2285        }
2286
2287        // If `...` was not present in the argument list, error if there are
2288        // any missing arguments; implicit arguments will be added during encoding
2289        if require_all {
2290            let world = &state.graph.types()[ty];
2291            if let Some((name, _)) = world
2292                .imports
2293                .iter()
2294                .find(|(n, _)| !arguments.contains_key(n.as_str()))
2295            {
2296                return Err(Error::MissingInstantiationArg {
2297                    name: name.clone(),
2298                    package: expr.package.string.to_string(),
2299                    span: expr.package.span,
2300                });
2301            }
2302        }
2303
2304        Ok(Item::Node(instantiation))
2305    }
2306
2307    fn find_matching_interface_name<'b>(
2308        name: &str,
2309        externs: &'b IndexMap<String, ItemKind>,
2310    ) -> Option<&'b str> {
2311        // If the given name exists directly, don't treat it as an interface name
2312        if externs.contains_key(name) {
2313            return None;
2314        }
2315
2316        // Fall back to searching for a matching interface name, provided it is not ambiguous
2317        // For example, match `foo:bar/baz` if `baz` is the identifier and the only match
2318        let mut matches = externs.iter().filter(|(n, _)| match n.rfind('/') {
2319            Some(start) => {
2320                let mut n = &n[start + 1..];
2321                if let Some(index) = n.find('@') {
2322                    n = &n[..index];
2323                }
2324                n == name
2325            }
2326            None => false,
2327        });
2328
2329        let (name, _) = matches.next()?;
2330        if matches.next().is_some() {
2331            // More than one match, the name is ambiguous
2332            return None;
2333        }
2334
2335        Some(name)
2336    }
2337
2338    fn named_instantiation_arg(
2339        &mut self,
2340        state: &mut State,
2341        arg: &'a ast::NamedInstantiationArgument<'a>,
2342        world: WorldId,
2343        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
2344    ) -> ResolutionResult<(String, Item, SourceSpan)> {
2345        let item = self.expr(state, &arg.expr, packages)?;
2346
2347        let name = match &arg.name {
2348            ast::InstantiationArgumentName::Ident(ident) => Self::find_matching_interface_name(
2349                ident.string,
2350                &state.graph.types()[world].imports,
2351            )
2352            .unwrap_or(ident.string),
2353            ast::InstantiationArgumentName::String(name) => name.value,
2354        };
2355
2356        Ok((name.to_owned(), item, arg.name.span()))
2357    }
2358
2359    fn inferred_instantiation_arg(
2360        &mut self,
2361        state: &mut State,
2362        ident: &ast::Ident<'a>,
2363        world: WorldId,
2364    ) -> ResolutionResult<(String, Item, SourceSpan)> {
2365        let (item, _) = state.local_item(ident)?;
2366        let world = &state.graph.types()[world];
2367        let kind = item.kind(&state.graph);
2368
2369        // If the item is an instance with an id, try the id.
2370        if let ItemKind::Instance(id) = kind {
2371            if let Some(id) = &state.graph.types()[id].id {
2372                if world.imports.contains_key(id.as_str()) {
2373                    return Ok((id.clone(), item, ident.span));
2374                }
2375            }
2376        }
2377
2378        // If the item comes from an import or an alias, try the name associated with it
2379        let node = item.node();
2380        if let Some(name) = state.graph.get_import_name(node) {
2381            if world.imports.contains_key(name) {
2382                return Ok((name.to_string(), item, ident.span));
2383            }
2384        } else if let Some((_, name)) = state.graph.get_alias_source(node) {
2385            if world.imports.contains_key(name) {
2386                return Ok((name.to_string(), item, ident.span));
2387            }
2388        }
2389
2390        // Fall back to searching for a matching interface name, provided it is not ambiguous
2391        // For example, match `foo:bar/baz` if `baz` is the identifier and the only match
2392        if let Some(name) = Self::find_matching_interface_name(ident.string, &world.imports) {
2393            return Ok((name.to_owned(), item, ident.span));
2394        }
2395
2396        // Finally default to the id itself
2397        Ok((ident.string.to_owned(), item, ident.span))
2398    }
2399
2400    fn spread_instantiation_arg(
2401        &mut self,
2402        state: &mut State,
2403        id: &ast::Ident,
2404        expected: &IndexSet<String>,
2405        arguments: &mut IndexMap<String, (Item, SourceSpan)>,
2406    ) -> ResolutionResult<()> {
2407        let item = state.local_item(id)?.0;
2408
2409        // The item must be an instance for a spread
2410        match item.kind(&state.graph) {
2411            ItemKind::Instance(_) => {}
2412            kind => {
2413                return Err(Error::NotAnInstance {
2414                    kind: kind.desc(state.graph.types()).to_string(),
2415                    operation: InstanceOperation::Spread,
2416                    span: id.span,
2417                })
2418            }
2419        }
2420
2421        let mut spread = false;
2422        for name in expected {
2423            // Check if the argument was already provided
2424            if arguments.contains_key(name) {
2425                continue;
2426            }
2427
2428            // Alias a matching export of the instance
2429            if let Some(aliased) =
2430                self.alias_export(state, item, name, id.span, InstanceOperation::Spread)?
2431            {
2432                spread = true;
2433                arguments.insert(name.clone(), (aliased, id.span));
2434            }
2435        }
2436
2437        if !spread {
2438            return Err(Error::SpreadInstantiationNoMatch { span: id.span });
2439        }
2440
2441        Ok(())
2442    }
2443
2444    fn postfix_expr(
2445        &mut self,
2446        state: &mut State,
2447        item: Item,
2448        expr: &ast::PostfixExpr,
2449        parent_span: SourceSpan,
2450    ) -> ResolutionResult<Item> {
2451        match expr {
2452            ast::PostfixExpr::Access(expr) => {
2453                let exports = match item.kind(&state.graph) {
2454                    ItemKind::Instance(id) => &state.graph.types()[id].exports,
2455                    kind => {
2456                        return Err(Error::NotAnInstance {
2457                            kind: kind.desc(state.graph.types()).to_string(),
2458                            operation: InstanceOperation::Access,
2459                            span: parent_span,
2460                        })
2461                    }
2462                };
2463
2464                let name = Self::find_matching_interface_name(expr.id.string, exports)
2465                    .unwrap_or(expr.id.string)
2466                    .to_string();
2467
2468                self.alias_export(state, item, &name, parent_span, InstanceOperation::Access)?
2469                    .ok_or_else(|| Error::MissingInstanceExport {
2470                        name,
2471                        span: expr.span,
2472                    })
2473            }
2474            ast::PostfixExpr::NamedAccess(expr) => self
2475                .alias_export(
2476                    state,
2477                    item,
2478                    expr.string.value,
2479                    parent_span,
2480                    InstanceOperation::Access,
2481                )?
2482                .ok_or_else(|| Error::MissingInstanceExport {
2483                    name: expr.string.value.to_owned(),
2484                    span: expr.span,
2485                }),
2486        }
2487    }
2488
2489    fn alias_export(
2490        &self,
2491        state: &mut State,
2492        item: Item,
2493        name: &str,
2494        span: SourceSpan,
2495        operation: InstanceOperation,
2496    ) -> ResolutionResult<Option<Item>> {
2497        let exports = match item.kind(&state.graph) {
2498            ItemKind::Instance(id) => &state.graph.types()[id].exports,
2499            kind => {
2500                return Err(Error::NotAnInstance {
2501                    kind: kind.desc(state.graph.types()).to_string(),
2502                    operation,
2503                    span,
2504                })
2505            }
2506        };
2507
2508        if exports.get(name).is_none() {
2509            return Ok(None);
2510        }
2511
2512        let node = state
2513            .graph
2514            .alias_instance_export(item.node(), name)
2515            .expect("alias should be created");
2516
2517        // Insert the span if the node isn't new
2518        Ok(Some(Item::Node(node)))
2519    }
2520
2521    fn resolve_package_path(
2522        &mut self,
2523        state: &mut State,
2524        path: &'a ast::PackagePath<'a>,
2525        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
2526    ) -> ResolutionResult<ItemKind> {
2527        log::debug!("resolving package export `{path}`", path = path.string);
2528
2529        // Check for reference to local item
2530        if path.name == self.0.directive.package.name {
2531            return self.resolve_local_path(state, path);
2532        }
2533
2534        let id = self.resolve_package(
2535            state,
2536            path.name,
2537            path.version.as_ref(),
2538            path.package_name_span(),
2539            packages,
2540        )?;
2541
2542        let package = &state.graph[id];
2543        let mut current = 0;
2544        let mut parent_ty = None;
2545        let mut found = None;
2546        for (i, (segment, _)) in path.segment_spans().enumerate() {
2547            current = i;
2548
2549            // Look up the first segment in the package definitions
2550            if i == 0 {
2551                found = package.definitions().get(segment).copied();
2552                continue;
2553            }
2554
2555            // Otherwise, project into the parent based on the current segment
2556            let export = match found.unwrap() {
2557                // The parent is an interface or instance
2558                ItemKind::Type(Type::Interface(id)) | ItemKind::Instance(id) => {
2559                    state.graph.types()[id].exports.get(segment).copied()
2560                }
2561                // The parent is a world or component or component instantiation
2562                ItemKind::Type(Type::World(id)) | ItemKind::Component(id) => {
2563                    state.graph.types()[id].exports.get(segment).copied()
2564                }
2565                _ => None,
2566            };
2567
2568            parent_ty = found.map(|kind| kind.desc(state.graph.types()));
2569            found = export;
2570            if found.is_none() {
2571                break;
2572            }
2573        }
2574
2575        found.ok_or_else(|| {
2576            let segments = path.segment_spans().enumerate();
2577            let mut prev_path = String::new();
2578            for (i, (segment, span)) in segments {
2579                if i == current {
2580                    return Error::PackageMissingExport {
2581                        package: path.name.to_string(),
2582                        export: segment.to_string(),
2583                        kind: parent_ty.map(ToOwned::to_owned),
2584                        path: prev_path,
2585                        span,
2586                    };
2587                }
2588
2589                if !prev_path.is_empty() {
2590                    prev_path.push('/');
2591                }
2592
2593                prev_path.push_str(segment);
2594            }
2595
2596            unreachable!("path segments should never be empty")
2597        })
2598    }
2599
2600    fn resolve_local_path(
2601        &self,
2602        state: &State,
2603        path: &ast::PackagePath<'a>,
2604    ) -> ResolutionResult<ItemKind> {
2605        log::debug!("resolving local path `{path}`", path = path.string);
2606
2607        let mut segments = path.segment_spans();
2608        let (segment, span) = segments.next().unwrap();
2609        let (item, _) = state.root_item(&ast::Ident {
2610            string: segment,
2611            span,
2612        })?;
2613
2614        let mut current = segment;
2615        let mut kind = item.kind(&state.graph);
2616        for (segment, span) in segments {
2617            let exports = match kind {
2618                ItemKind::Type(Type::Interface(id)) | ItemKind::Instance(id) => {
2619                    &state.graph.types()[id].exports
2620                }
2621                ItemKind::Type(Type::World(id)) | ItemKind::Component(id) => {
2622                    &state.graph.types()[id].exports
2623                }
2624                _ => {
2625                    return Err(Error::PackagePathMissingExport {
2626                        name: current.to_string(),
2627                        kind: kind.desc(state.graph.types()).to_string(),
2628                        export: segment.to_string(),
2629                        span,
2630                    });
2631                }
2632            };
2633
2634            kind =
2635                exports
2636                    .get(segment)
2637                    .copied()
2638                    .ok_or_else(|| Error::PackagePathMissingExport {
2639                        name: current.to_string(),
2640                        kind: kind.desc(state.graph.types()).to_string(),
2641                        export: segment.to_string(),
2642                        span,
2643                    })?;
2644
2645            current = segment;
2646        }
2647
2648        Ok(kind)
2649    }
2650
2651    fn resolve_package(
2652        &mut self,
2653        state: &mut State,
2654        name: &'a str,
2655        version: Option<&'a Version>,
2656        span: SourceSpan,
2657        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
2658    ) -> ResolutionResult<PackageId> {
2659        match state.graph.get_package_by_name(name, version) {
2660            Some((id, _)) => Ok(id),
2661            None => {
2662                let bytes = packages
2663                    .swap_remove(&BorrowedPackageKey::from_name_and_version(name, version))
2664                    .ok_or_else(|| Error::UnknownPackage {
2665                        name: name.to_string(),
2666                        span,
2667                    })?;
2668
2669                log::debug!("registering package `{name}` with the graph");
2670                let package = Package::from_bytes(name, version, bytes, state.graph.types_mut())
2671                    .map_err(|e| Error::PackageParseFailure {
2672                        name: name.to_string(),
2673                        span,
2674                        source: e,
2675                    })?;
2676
2677                Ok(state
2678                    .graph
2679                    .register_package(package)
2680                    .expect("package should not exist"))
2681            }
2682        }
2683    }
2684
2685    fn validate_target(
2686        &self,
2687        state: &State,
2688        path: &ast::PackagePath,
2689        world: WorldId,
2690    ) -> ResolutionResult<()> {
2691        let world = &state.graph.types()[world];
2692        // The interfaces imported implicitly through uses.
2693        let implicit_imported_interfaces = world.implicit_imported_interfaces(state.graph.types());
2694        let mut cache = Default::default();
2695        let mut checker = SubtypeChecker::new(&mut cache);
2696
2697        // The output is allowed to import a subset of the world's imports
2698        checker.invert();
2699        for (name, item_kind, import_node) in state.graph.imports() {
2700            let expected = implicit_imported_interfaces
2701                .get(name)
2702                .or_else(|| world.imports.get(name))
2703                .ok_or_else(|| Error::ImportNotInTarget {
2704                    name: name.to_owned(),
2705                    world: path.string.to_owned(),
2706                    span: import_node.map(|n| state.import_spans[&n]),
2707                })?;
2708
2709            checker
2710                .is_subtype(
2711                    expected.promote(),
2712                    state.graph.types(),
2713                    item_kind,
2714                    state.graph.types(),
2715                )
2716                .map_err(|e| Error::TargetMismatch {
2717                    kind: ExternKind::Import,
2718                    name: name.to_owned(),
2719                    world: path.string.to_owned(),
2720                    span: import_node.map(|n| state.import_spans[&n]),
2721                    source: e,
2722                })?;
2723        }
2724
2725        checker.revert();
2726
2727        // The output must export every export in the world
2728        for (name, expected) in &world.exports {
2729            let export =
2730                state
2731                    .graph
2732                    .get_export(name)
2733                    .ok_or_else(|| Error::MissingTargetExport {
2734                        name: name.clone(),
2735                        world: path.string.to_owned(),
2736                        kind: expected.desc(state.graph.types()).to_string(),
2737                        span: path.span,
2738                    })?;
2739
2740            checker
2741                .is_subtype(
2742                    state.graph[export].item_kind(),
2743                    state.graph.types(),
2744                    expected.promote(),
2745                    state.graph.types(),
2746                )
2747                .map_err(|e| Error::TargetMismatch {
2748                    kind: ExternKind::Export,
2749                    name: name.clone(),
2750                    world: path.string.to_owned(),
2751                    span: state.export_spans.get(&export).copied(),
2752                    source: e,
2753                })?;
2754        }
2755
2756        Ok(())
2757    }
2758}