Skip to content

Commit 088a728

Browse files
authored
Merge pull request #102 from rylev/merging-import-dependencies
Merging import dependencies
2 parents f31c6bc + 4577cdd commit 088a728

7 files changed

Lines changed: 161 additions & 16 deletions

File tree

crates/wac-graph/src/graph.rs

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,22 +1377,28 @@ impl<'a> CompositionGraphEncoder<'a> {
13771377
fn encode(self, options: EncodeOptions) -> Result<Vec<u8>, EncodeError> {
13781378
let mut state = State::new();
13791379

1380-
// First populate the state with the implicit instantiation arguments
1381-
self.populate_implicit_args(&mut state)?;
1382-
1383-
// Encode each node in the graph in topographical order
1384-
for n in self
1380+
// Separate import nodes from other nodes keeping topological order
1381+
let (import_nodes, other_nodes) = self
13851382
.toposort()
13861383
.map_err(|n| EncodeError::GraphContainsCycle { node: NodeId(n) })?
1387-
{
1384+
.into_iter()
1385+
.partition::<Vec<_>, _>(|index| {
1386+
let node = &self.0.graph[*index];
1387+
matches!(node.kind, NodeKind::Import(_))
1388+
});
1389+
1390+
// First populate the state with both implicit instantiation arguments and explicit imports
1391+
self.encode_imports(&mut state, import_nodes)?;
1392+
1393+
// Encode non-import nodes in the graph in topographical order
1394+
for n in other_nodes {
13881395
let node = &self.0.graph[n];
13891396
let index = match &node.kind {
13901397
NodeKind::Definition => self.definition(&mut state, node),
1391-
NodeKind::Import(name) => {
1392-
self.import(&mut state, name, &self.0.types, node.item_kind)
1393-
}
13941398
NodeKind::Instantiation(_) => self.instantiation(&mut state, n, node, options),
13951399
NodeKind::Alias => self.alias(&mut state, n),
1400+
// `other_nodes` does not contain any import nodes
1401+
NodeKind::Import(_) => unreachable!(),
13961402
};
13971403

13981404
let prev = state.node_indexes.insert(n, index);
@@ -1482,13 +1488,19 @@ impl<'a> CompositionGraphEncoder<'a> {
14821488
Ok(finish_stack)
14831489
}
14841490

1485-
fn populate_implicit_args(&self, state: &mut State) -> Result<(), EncodeError> {
1491+
/// Encode both implicit and explicit imports.
1492+
fn encode_imports(
1493+
&self,
1494+
state: &mut State,
1495+
import_nodes: Vec<NodeIndex>,
1496+
) -> Result<(), EncodeError> {
14861497
let mut aggregator = TypeAggregator::default();
14871498
let mut instantiations = HashMap::new();
14881499
let mut arguments = Vec::new();
14891500
let mut encoded = HashMap::new();
14901501
let mut cache = Default::default();
14911502
let mut checker = SubtypeChecker::new(&mut cache);
1503+
let mut explicit_imports = HashMap::new();
14921504

14931505
log::debug!("populating implicit imports");
14941506

@@ -1502,13 +1514,14 @@ impl<'a> CompositionGraphEncoder<'a> {
15021514
let package = &self.0[node.package.unwrap()];
15031515
let world = &self.0.types[package.ty()];
15041516

1505-
// Go through the unsatisfied arguments and import them
1506-
for (_, (name, kind)) in world
1517+
let unsatisfied_args = world
15071518
.imports
15081519
.iter()
15091520
.enumerate()
1510-
.filter(|(i, _)| !node.is_arg_satisfied(*i))
1511-
{
1521+
.filter(|(i, _)| !node.is_arg_satisfied(*i));
1522+
1523+
// Go through the unsatisfied arguments and import them
1524+
for (_, (name, kind)) in unsatisfied_args {
15121525
if let Some(import) = self.0.imports.get(name).copied() {
15131526
return Err(EncodeError::ImplicitImportConflict {
15141527
import: NodeId(import),
@@ -1532,14 +1545,26 @@ impl<'a> CompositionGraphEncoder<'a> {
15321545
}
15331546
}
15341547

1548+
log::debug!("populating explicit imports");
1549+
1550+
for n in import_nodes {
1551+
let node = &self.0.graph[n];
1552+
if let NodeKind::Import(name) = &node.kind {
1553+
explicit_imports.insert(name.as_str(), n);
1554+
aggregator = aggregator
1555+
.aggregate(name, self.0.types(), node.item_kind, &mut checker)
1556+
.unwrap();
1557+
}
1558+
}
1559+
15351560
// Next encode the imports
15361561
for (name, kind) in aggregator.imports() {
1537-
log::debug!("import `{name}` is being implicitly imported");
1562+
log::debug!("import `{name}` is being imported");
15381563
let index = self.import(state, name, aggregator.types(), kind);
15391564
encoded.insert(name, (kind.into(), index));
15401565
}
15411566

1542-
// Finally populate the implicit argument map
1567+
// Populate the implicit argument map
15431568
for (node, name) in arguments {
15441569
let (kind, index) = encoded[name.as_str()];
15451570
state
@@ -1549,6 +1574,12 @@ impl<'a> CompositionGraphEncoder<'a> {
15491574
.push((name.clone(), kind, index));
15501575
}
15511576

1577+
// Finally, populate the node indexes with the encoded explicit imports
1578+
for (name, node_index) in explicit_imports {
1579+
let (_, encoded_index) = encoded[name];
1580+
state.node_indexes.insert(node_index, encoded_index);
1581+
}
1582+
15521583
Ok(())
15531584
}
15541585

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package foo:dependency;
2+
3+
interface types {
4+
record my-record {
5+
foo: string
6+
}
7+
}
8+
9+
world w {
10+
export types;
11+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package foo:component;
2+
3+
world w {
4+
export my-interface;
5+
}
6+
7+
interface my-interface{
8+
use foo:dependency/types.{my-record};
9+
my-func: func() -> my-record;
10+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
(component
2+
(type (;0;)
3+
(instance
4+
(type (;0;) (record (field "foo" string)))
5+
(export (;1;) "my-record" (type (eq 0)))
6+
(type (;2;) (variant (case "x")))
7+
(export (;3;) "my-variant" (type (eq 2)))
8+
)
9+
)
10+
(import "foo:dependency/types" (instance (;0;) (type 0)))
11+
(alias export 0 "my-variant" (type (;1;)))
12+
(type (;2;)
13+
(instance
14+
(alias outer 1 1 (type (;0;)))
15+
(export (;1;) "my-variant" (type (eq 0)))
16+
(type (;2;) (func (result 1)))
17+
(export (;0;) "my-func" (func (type 2)))
18+
)
19+
)
20+
(import "foo:test-import/my-interface" (instance (;1;) (type 2)))
21+
(type (;3;)
22+
(component
23+
(type (;0;)
24+
(instance
25+
(type (;0;) (record (field "foo" string)))
26+
(export (;1;) "my-record" (type (eq 0)))
27+
)
28+
)
29+
(import "foo:dependency/types" (instance (;0;) (type 0)))
30+
(alias export 0 "my-record" (type (;1;)))
31+
(type (;2;)
32+
(instance
33+
(alias outer 1 1 (type (;0;)))
34+
(export (;1;) "my-record" (type (eq 0)))
35+
(type (;2;) (func (result 1)))
36+
(export (;0;) "my-func" (func (type 2)))
37+
)
38+
)
39+
(export (;1;) "foo:component/my-interface" (instance (type 2)))
40+
)
41+
)
42+
(import "unlocked-dep=<test:component>" (component (;0;) (type 3)))
43+
(instance (;2;) (instantiate 0
44+
(with "foo:dependency/types" (instance 0))
45+
)
46+
)
47+
)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"packages": [
3+
{
4+
"name": "foo:import",
5+
"path": "import"
6+
},
7+
{
8+
"name": "test:component",
9+
"path": "component"
10+
}
11+
],
12+
"nodes": [
13+
{
14+
"type": "import",
15+
"name": "foo:test-import/my-interface",
16+
"package": 0,
17+
"export": "foo:test-import/my-interface"
18+
},
19+
{
20+
"type": "instantiation",
21+
"package": 1
22+
}
23+
],
24+
"arguments": []
25+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package foo:dependency;
2+
3+
interface types {
4+
variant my-variant {
5+
x
6+
}
7+
}
8+
9+
world w {
10+
export types;
11+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package foo:test-import;
2+
3+
world w {
4+
export my-interface;
5+
}
6+
7+
interface my-interface{
8+
use foo:dependency/types.{my-variant};
9+
my-func: func() -> my-variant;
10+
}

0 commit comments

Comments
 (0)