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