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