Skip to main content

wac_parser/
resolution.rs

1//! Module for resolving WAC ASTs.
2
3use crate::{ast, Document};
4use indexmap::{IndexMap, IndexSet};
5use miette::{Diagnostic, SourceSpan};
6use semver::Version;
7use std::{
8    collections::{HashMap, HashSet},
9    fmt,
10};
11use wac_graph::{
12    types::{
13        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.graph.types_mut().add_func_type(FuncType {
2134            params,
2135            result,
2136            is_async: false,
2137        }))
2138    }
2139
2140    fn expr(
2141        &mut self,
2142        state: &mut State,
2143        expr: &'a ast::Expr<'a>,
2144        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
2145    ) -> ResolutionResult<Item> {
2146        let mut item = self.primary_expr(state, &expr.primary, packages)?;
2147
2148        let mut parent_span = expr.primary.span();
2149        for expr in &expr.postfix {
2150            item = self.postfix_expr(state, item, expr, parent_span)?;
2151            parent_span = expr.span();
2152        }
2153
2154        Ok(item)
2155    }
2156
2157    fn primary_expr(
2158        &mut self,
2159        state: &mut State,
2160        expr: &'a ast::PrimaryExpr<'a>,
2161        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
2162    ) -> ResolutionResult<Item> {
2163        match expr {
2164            ast::PrimaryExpr::New(e) => self.new_expr(state, e, packages),
2165            ast::PrimaryExpr::Nested(e) => self.expr(state, &e.inner, packages),
2166            ast::PrimaryExpr::Ident(i) => Ok(state.local_item(i)?.0),
2167        }
2168    }
2169
2170    fn new_expr(
2171        &mut self,
2172        state: &mut State,
2173        expr: &'a ast::NewExpr<'a>,
2174        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
2175    ) -> ResolutionResult<Item> {
2176        log::debug!(
2177            "resolving new expression for package `{pkg}`",
2178            pkg = BorrowedPackageKey::from_name_and_version(
2179                expr.package.name,
2180                expr.package.version.as_ref()
2181            )
2182        );
2183
2184        if expr.package.name == self.0.directive.package.name {
2185            return Err(Error::UnknownPackage {
2186                name: expr.package.name.to_string(),
2187                span: expr.package.span,
2188            });
2189        }
2190
2191        let pkg = self.resolve_package(
2192            state,
2193            expr.package.name,
2194            expr.package.version.as_ref(),
2195            expr.package.span,
2196            packages,
2197        )?;
2198        let ty = state.graph[pkg].ty();
2199        let expected = state.graph.types()[ty]
2200            .imports
2201            .keys()
2202            .cloned()
2203            .collect::<IndexSet<_>>();
2204        let mut require_all = true;
2205
2206        let mut arguments: IndexMap<String, (Item, SourceSpan)> = Default::default();
2207        for (i, arg) in expr.arguments.iter().enumerate() {
2208            let (name, item, span) = match arg {
2209                ast::InstantiationArgument::Inferred(id) => {
2210                    self.inferred_instantiation_arg(state, id, ty)?
2211                }
2212                ast::InstantiationArgument::Spread(_) => {
2213                    // Spread arguments will be processed after all other arguments
2214                    continue;
2215                }
2216                ast::InstantiationArgument::Named(arg) => {
2217                    self.named_instantiation_arg(state, arg, ty, packages)?
2218                }
2219                ast::InstantiationArgument::Fill(span) => {
2220                    if i != (expr.arguments.len() - 1) {
2221                        return Err(Error::FillArgumentNotLast { span: *span });
2222                    }
2223
2224                    require_all = false;
2225                    continue;
2226                }
2227            };
2228
2229            let prev = arguments.insert(name.clone(), (item, span));
2230            if prev.is_some() {
2231                return Err(Error::DuplicateInstantiationArg { name, span });
2232            }
2233        }
2234
2235        // Process the spread arguments
2236        for arg in &expr.arguments {
2237            if let ast::InstantiationArgument::Spread(id) = arg {
2238                self.spread_instantiation_arg(state, id, &expected, &mut arguments)?;
2239            }
2240        }
2241
2242        // Create the instantiation node
2243        log::debug!(
2244            "adding instantiation for package `{pkg}` to the graph",
2245            pkg = BorrowedPackageKey::from_name_and_version(
2246                expr.package.name,
2247                expr.package.version.as_ref()
2248            )
2249        );
2250        let instantiation = state.graph.instantiate(pkg);
2251        let prev = state
2252            .instantiation_spans
2253            .insert(instantiation, expr.package.span);
2254        assert!(prev.is_none());
2255
2256        // Set the arguments on the instantiation
2257        for (name, (argument, span)) in &arguments {
2258            log::debug!("adding argument edge `{name}`");
2259            state
2260                .graph
2261                .set_instantiation_argument(instantiation, name, argument.node())
2262                .map_err(|e| match e {
2263                    InstantiationArgumentError::NodeIsNotAnInstantiation { .. } => {
2264                        panic!("node should be an instantiation")
2265                    }
2266                    InstantiationArgumentError::ArgumentAlreadyPassed { .. } => {
2267                        panic!("argument should not already be passed")
2268                    }
2269                    InstantiationArgumentError::InvalidArgumentName {
2270                        node: _,
2271                        name,
2272                        package,
2273                    } => Error::MissingComponentImport {
2274                        package,
2275                        import: name,
2276                        span: *span,
2277                    },
2278                    InstantiationArgumentError::ArgumentTypeMismatch { name, source } => {
2279                        Error::MismatchedInstantiationArg {
2280                            name,
2281                            span: *span,
2282                            source,
2283                        }
2284                    }
2285                })?;
2286        }
2287
2288        // If `...` was not present in the argument list, error if there are
2289        // any missing arguments; implicit arguments will be added during encoding
2290        if require_all {
2291            let world = &state.graph.types()[ty];
2292            if let Some((name, _)) = world
2293                .imports
2294                .iter()
2295                .find(|(n, _)| !arguments.contains_key(n.as_str()))
2296            {
2297                return Err(Error::MissingInstantiationArg {
2298                    name: name.clone(),
2299                    package: expr.package.string.to_string(),
2300                    span: expr.package.span,
2301                });
2302            }
2303        }
2304
2305        Ok(Item::Node(instantiation))
2306    }
2307
2308    fn find_matching_interface_name<'b>(
2309        name: &str,
2310        externs: &'b IndexMap<String, ItemKind>,
2311    ) -> Option<&'b str> {
2312        // If the given name exists directly, don't treat it as an interface name
2313        if externs.contains_key(name) {
2314            return None;
2315        }
2316
2317        // Fall back to searching for a matching interface name, provided it is not ambiguous
2318        // For example, match `foo:bar/baz` if `baz` is the identifier and the only match
2319        let mut matches = externs.iter().filter(|(n, _)| match n.rfind('/') {
2320            Some(start) => {
2321                let mut n = &n[start + 1..];
2322                if let Some(index) = n.find('@') {
2323                    n = &n[..index];
2324                }
2325                n == name
2326            }
2327            None => false,
2328        });
2329
2330        let (name, _) = matches.next()?;
2331        if matches.next().is_some() {
2332            // More than one match, the name is ambiguous
2333            return None;
2334        }
2335
2336        Some(name)
2337    }
2338
2339    fn named_instantiation_arg(
2340        &mut self,
2341        state: &mut State,
2342        arg: &'a ast::NamedInstantiationArgument<'a>,
2343        world: WorldId,
2344        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
2345    ) -> ResolutionResult<(String, Item, SourceSpan)> {
2346        let item = self.expr(state, &arg.expr, packages)?;
2347
2348        let name = match &arg.name {
2349            ast::InstantiationArgumentName::Ident(ident) => Self::find_matching_interface_name(
2350                ident.string,
2351                &state.graph.types()[world].imports,
2352            )
2353            .unwrap_or(ident.string),
2354            ast::InstantiationArgumentName::String(name) => name.value,
2355        };
2356
2357        Ok((name.to_owned(), item, arg.name.span()))
2358    }
2359
2360    fn inferred_instantiation_arg(
2361        &mut self,
2362        state: &mut State,
2363        ident: &ast::Ident<'a>,
2364        world: WorldId,
2365    ) -> ResolutionResult<(String, Item, SourceSpan)> {
2366        let (item, _) = state.local_item(ident)?;
2367        let world = &state.graph.types()[world];
2368        let kind = item.kind(&state.graph);
2369
2370        // If the item is an instance with an id, try the id.
2371        if let ItemKind::Instance(id) = kind {
2372            if let Some(id) = &state.graph.types()[id].id {
2373                if world.imports.contains_key(id.as_str()) {
2374                    return Ok((id.clone(), item, ident.span));
2375                }
2376            }
2377        }
2378
2379        // If the item comes from an import or an alias, try the name associated with it
2380        let node = item.node();
2381        if let Some(name) = state.graph.get_import_name(node) {
2382            if world.imports.contains_key(name) {
2383                return Ok((name.to_string(), item, ident.span));
2384            }
2385        } else if let Some((_, name)) = state.graph.get_alias_source(node) {
2386            if world.imports.contains_key(name) {
2387                return Ok((name.to_string(), item, ident.span));
2388            }
2389        }
2390
2391        // Fall back to searching for a matching interface name, provided it is not ambiguous
2392        // For example, match `foo:bar/baz` if `baz` is the identifier and the only match
2393        if let Some(name) = Self::find_matching_interface_name(ident.string, &world.imports) {
2394            return Ok((name.to_owned(), item, ident.span));
2395        }
2396
2397        // Finally default to the id itself
2398        Ok((ident.string.to_owned(), item, ident.span))
2399    }
2400
2401    fn spread_instantiation_arg(
2402        &mut self,
2403        state: &mut State,
2404        id: &ast::Ident,
2405        expected: &IndexSet<String>,
2406        arguments: &mut IndexMap<String, (Item, SourceSpan)>,
2407    ) -> ResolutionResult<()> {
2408        let item = state.local_item(id)?.0;
2409
2410        // The item must be an instance for a spread
2411        match item.kind(&state.graph) {
2412            ItemKind::Instance(_) => {}
2413            kind => {
2414                return Err(Error::NotAnInstance {
2415                    kind: kind.desc(state.graph.types()).to_string(),
2416                    operation: InstanceOperation::Spread,
2417                    span: id.span,
2418                })
2419            }
2420        }
2421
2422        let mut spread = false;
2423        for name in expected {
2424            // Check if the argument was already provided
2425            if arguments.contains_key(name) {
2426                continue;
2427            }
2428
2429            // Alias a matching export of the instance
2430            if let Some(aliased) =
2431                self.alias_export(state, item, name, id.span, InstanceOperation::Spread)?
2432            {
2433                spread = true;
2434                arguments.insert(name.clone(), (aliased, id.span));
2435            }
2436        }
2437
2438        if !spread {
2439            return Err(Error::SpreadInstantiationNoMatch { span: id.span });
2440        }
2441
2442        Ok(())
2443    }
2444
2445    fn postfix_expr(
2446        &mut self,
2447        state: &mut State,
2448        item: Item,
2449        expr: &ast::PostfixExpr,
2450        parent_span: SourceSpan,
2451    ) -> ResolutionResult<Item> {
2452        match expr {
2453            ast::PostfixExpr::Access(expr) => {
2454                let exports = match item.kind(&state.graph) {
2455                    ItemKind::Instance(id) => &state.graph.types()[id].exports,
2456                    kind => {
2457                        return Err(Error::NotAnInstance {
2458                            kind: kind.desc(state.graph.types()).to_string(),
2459                            operation: InstanceOperation::Access,
2460                            span: parent_span,
2461                        })
2462                    }
2463                };
2464
2465                let name = Self::find_matching_interface_name(expr.id.string, exports)
2466                    .unwrap_or(expr.id.string)
2467                    .to_string();
2468
2469                self.alias_export(state, item, &name, parent_span, InstanceOperation::Access)?
2470                    .ok_or_else(|| Error::MissingInstanceExport {
2471                        name,
2472                        span: expr.span,
2473                    })
2474            }
2475            ast::PostfixExpr::NamedAccess(expr) => self
2476                .alias_export(
2477                    state,
2478                    item,
2479                    expr.string.value,
2480                    parent_span,
2481                    InstanceOperation::Access,
2482                )?
2483                .ok_or_else(|| Error::MissingInstanceExport {
2484                    name: expr.string.value.to_owned(),
2485                    span: expr.span,
2486                }),
2487        }
2488    }
2489
2490    fn alias_export(
2491        &self,
2492        state: &mut State,
2493        item: Item,
2494        name: &str,
2495        span: SourceSpan,
2496        operation: InstanceOperation,
2497    ) -> ResolutionResult<Option<Item>> {
2498        let exports = match item.kind(&state.graph) {
2499            ItemKind::Instance(id) => &state.graph.types()[id].exports,
2500            kind => {
2501                return Err(Error::NotAnInstance {
2502                    kind: kind.desc(state.graph.types()).to_string(),
2503                    operation,
2504                    span,
2505                })
2506            }
2507        };
2508
2509        if exports.get(name).is_none() {
2510            return Ok(None);
2511        }
2512
2513        let node = state
2514            .graph
2515            .alias_instance_export(item.node(), name)
2516            .expect("alias should be created");
2517
2518        // Insert the span if the node isn't new
2519        Ok(Some(Item::Node(node)))
2520    }
2521
2522    fn resolve_package_path(
2523        &mut self,
2524        state: &mut State,
2525        path: &'a ast::PackagePath<'a>,
2526        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
2527    ) -> ResolutionResult<ItemKind> {
2528        log::debug!("resolving package export `{path}`", path = path.string);
2529
2530        // Check for reference to local item
2531        if path.name == self.0.directive.package.name {
2532            return self.resolve_local_path(state, path);
2533        }
2534
2535        let id = self.resolve_package(
2536            state,
2537            path.name,
2538            path.version.as_ref(),
2539            path.package_name_span(),
2540            packages,
2541        )?;
2542
2543        let package = &state.graph[id];
2544        let mut current = 0;
2545        let mut parent_ty = None;
2546        let mut found = None;
2547        for (i, (segment, _)) in path.segment_spans().enumerate() {
2548            current = i;
2549
2550            // Look up the first segment in the package definitions
2551            if i == 0 {
2552                found = package.definitions().get(segment).copied();
2553                continue;
2554            }
2555
2556            // Otherwise, project into the parent based on the current segment
2557            let Some(parent) = found else { break };
2558            let export = match parent {
2559                // The parent is an interface or instance
2560                ItemKind::Type(Type::Interface(id)) | ItemKind::Instance(id) => {
2561                    state.graph.types()[id].exports.get(segment).copied()
2562                }
2563                // The parent is a world or component or component instantiation
2564                ItemKind::Type(Type::World(id)) | ItemKind::Component(id) => {
2565                    state.graph.types()[id].exports.get(segment).copied()
2566                }
2567                _ => None,
2568            };
2569
2570            parent_ty = found.map(|kind| kind.desc(state.graph.types()));
2571            found = export;
2572            if found.is_none() {
2573                break;
2574            }
2575        }
2576
2577        found.ok_or_else(|| {
2578            let segments = path.segment_spans().enumerate();
2579            let mut prev_path = String::new();
2580            for (i, (segment, span)) in segments {
2581                if i == current {
2582                    return Error::PackageMissingExport {
2583                        package: path.name.to_string(),
2584                        export: segment.to_string(),
2585                        kind: parent_ty.map(ToOwned::to_owned),
2586                        path: prev_path,
2587                        span,
2588                    };
2589                }
2590
2591                if !prev_path.is_empty() {
2592                    prev_path.push('/');
2593                }
2594
2595                prev_path.push_str(segment);
2596            }
2597
2598            unreachable!("path segments should never be empty")
2599        })
2600    }
2601
2602    fn resolve_local_path(
2603        &self,
2604        state: &State,
2605        path: &ast::PackagePath<'a>,
2606    ) -> ResolutionResult<ItemKind> {
2607        log::debug!("resolving local path `{path}`", path = path.string);
2608
2609        let mut segments = path.segment_spans();
2610        let (segment, span) = segments.next().unwrap();
2611        let (item, _) = state.root_item(&ast::Ident {
2612            string: segment,
2613            span,
2614        })?;
2615
2616        let mut current = segment;
2617        let mut kind = item.kind(&state.graph);
2618        for (segment, span) in segments {
2619            let exports = match kind {
2620                ItemKind::Type(Type::Interface(id)) | ItemKind::Instance(id) => {
2621                    &state.graph.types()[id].exports
2622                }
2623                ItemKind::Type(Type::World(id)) | ItemKind::Component(id) => {
2624                    &state.graph.types()[id].exports
2625                }
2626                _ => {
2627                    return Err(Error::PackagePathMissingExport {
2628                        name: current.to_string(),
2629                        kind: kind.desc(state.graph.types()).to_string(),
2630                        export: segment.to_string(),
2631                        span,
2632                    });
2633                }
2634            };
2635
2636            kind =
2637                exports
2638                    .get(segment)
2639                    .copied()
2640                    .ok_or_else(|| Error::PackagePathMissingExport {
2641                        name: current.to_string(),
2642                        kind: kind.desc(state.graph.types()).to_string(),
2643                        export: segment.to_string(),
2644                        span,
2645                    })?;
2646
2647            current = segment;
2648        }
2649
2650        Ok(kind)
2651    }
2652
2653    fn resolve_package(
2654        &mut self,
2655        state: &mut State,
2656        name: &'a str,
2657        version: Option<&'a Version>,
2658        span: SourceSpan,
2659        packages: &mut IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
2660    ) -> ResolutionResult<PackageId> {
2661        match state.graph.get_package_by_name(name, version) {
2662            Some((id, _)) => Ok(id),
2663            None => {
2664                let bytes = packages
2665                    .swap_remove(&BorrowedPackageKey::from_name_and_version(name, version))
2666                    .ok_or_else(|| Error::UnknownPackage {
2667                        name: name.to_string(),
2668                        span,
2669                    })?;
2670
2671                log::debug!("registering package `{name}` with the graph");
2672                let package = Package::from_bytes(name, version, bytes, state.graph.types_mut())
2673                    .map_err(|e| Error::PackageParseFailure {
2674                        name: name.to_string(),
2675                        span,
2676                        source: e,
2677                    })?;
2678
2679                Ok(state
2680                    .graph
2681                    .register_package(package)
2682                    .expect("package should not exist"))
2683            }
2684        }
2685    }
2686
2687    fn validate_target(
2688        &self,
2689        state: &State,
2690        path: &ast::PackagePath,
2691        world: WorldId,
2692    ) -> ResolutionResult<()> {
2693        let world = &state.graph.types()[world];
2694        // The interfaces imported implicitly through uses.
2695        let implicit_imported_interfaces = world.implicit_imported_interfaces(state.graph.types());
2696        let mut cache = Default::default();
2697        let mut checker = SubtypeChecker::new(&mut cache);
2698
2699        // The output is allowed to import a subset of the world's imports
2700        checker.invert();
2701        for (name, item_kind, import_node) in state.graph.imports() {
2702            let expected = implicit_imported_interfaces
2703                .get(name)
2704                .or_else(|| world.imports.get(name))
2705                .ok_or_else(|| Error::ImportNotInTarget {
2706                    name: name.to_owned(),
2707                    world: path.string.to_owned(),
2708                    span: import_node.map(|n| state.import_spans[&n]),
2709                })?;
2710
2711            checker
2712                .is_subtype(
2713                    expected.promote(),
2714                    state.graph.types(),
2715                    item_kind,
2716                    state.graph.types(),
2717                )
2718                .map_err(|e| Error::TargetMismatch {
2719                    kind: ExternKind::Import,
2720                    name: name.to_owned(),
2721                    world: path.string.to_owned(),
2722                    span: import_node.map(|n| state.import_spans[&n]),
2723                    source: e,
2724                })?;
2725        }
2726
2727        checker.revert();
2728
2729        // The output must export every export in the world
2730        for (name, expected) in &world.exports {
2731            let export =
2732                state
2733                    .graph
2734                    .get_export(name)
2735                    .ok_or_else(|| Error::MissingTargetExport {
2736                        name: name.clone(),
2737                        world: path.string.to_owned(),
2738                        kind: expected.desc(state.graph.types()).to_string(),
2739                        span: path.span,
2740                    })?;
2741
2742            checker
2743                .is_subtype(
2744                    state.graph[export].item_kind(),
2745                    state.graph.types(),
2746                    expected.promote(),
2747                    state.graph.types(),
2748                )
2749                .map_err(|e| Error::TargetMismatch {
2750                    kind: ExternKind::Export,
2751                    name: name.clone(),
2752                    world: path.string.to_owned(),
2753                    span: state.export_spans.get(&export).copied(),
2754                    source: e,
2755                })?;
2756        }
2757
2758        Ok(())
2759    }
2760}