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