Skip to content

Commit b5d5381

Browse files
committed
fix: alias instance-exported types reached by id in aggregated imports
Top-level aggregated imports carry no `uses` map, so a type referenced by id (e.g. an imported instance's export used in a record field) was re-encoded as an invalid local definition. `value_type` now aliases it from the imported instance, and imports are encoded instances-first.
1 parent 062a54a commit b5d5381

7 files changed

Lines changed: 126 additions & 21 deletions

File tree

crates/wac-graph/src/encoding.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,28 @@ impl<'a> TypeEncoder<'a> {
190190
Self(types)
191191
}
192192

193+
// Aliases a value type from an imported instance that exports it, rather
194+
// than re-encoding it locally; a local definition is invalid as an
195+
// import bound.
196+
fn aliased_instance_export(&self, state: &mut State, ty: ValueType) -> Option<u32> {
197+
let ty = Type::Value(ty);
198+
let (instance, name) = self.0.interfaces().find_map(|interface| {
199+
let iid = interface.id.as_ref()?;
200+
let instance = *state.current.instances.get(iid)?;
201+
interface.exports.iter().find_map(|(name, kind)| {
202+
matches!(kind, ItemKind::Type(t) if *t == ty).then(|| (instance, name.clone()))
203+
})
204+
})?;
205+
let index = state.current.encodable.type_count();
206+
state.current.encodable.alias(Alias::InstanceExport {
207+
instance,
208+
kind: ComponentExportKind::Type,
209+
name: &name,
210+
});
211+
state.current.type_indexes.insert(ty, index);
212+
Some(index)
213+
}
214+
193215
pub fn ty(&self, state: &mut State, ty: Type, name: Option<&str>) -> u32 {
194216
if let Some(index) = state.current.type_indexes.get(&ty) {
195217
return *index;
@@ -533,6 +555,10 @@ impl<'a> TypeEncoder<'a> {
533555
return ComponentValType::Type(*index);
534556
}
535557

558+
if let Some(index) = self.aliased_instance_export(state, ty) {
559+
return ComponentValType::Type(index);
560+
}
561+
536562
let index = match ty {
537563
ValueType::Primitive(ty) => return ComponentValType::Primitive(ty.into()),
538564
ValueType::Borrow(id) => self.borrow(state, id),

crates/wac-graph/src/graph.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,8 +1544,12 @@ impl<'a> CompositionGraphEncoder<'a> {
15441544

15451545
let mut encoded = HashMap::new();
15461546

1547-
// Next encode the imports
1548-
for (name, kind) in aggregator.imports() {
1547+
// Instances first, so a later type import can alias a type from an
1548+
// instance export instead of re-encoding it as a local definition.
1549+
let (instances, rest): (Vec<_>, Vec<_>) = aggregator
1550+
.imports()
1551+
.partition(|(_, kind)| matches!(kind, ItemKind::Instance(_)));
1552+
for (name, kind) in instances.into_iter().chain(rest) {
15491553
log::debug!("import `{name}` is being imported");
15501554
let index = self.import(state, name, aggregator.types(), kind);
15511555
encoded.insert(name, (kind.into(), index));

crates/wac-graph/tests/graphs/implicit-resource-import/encoded.wat

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,18 @@
66
)
77
(import "foo:dependency/types" (instance (;0;) (type 0)))
88
(alias export 0 "x" (type (;1;)))
9-
(import "x" (type (;2;) (eq 1)))
10-
(alias export 0 "x" (type (;3;)))
11-
(type (;4;)
9+
(type (;2;)
1210
(instance
13-
(alias outer 1 3 (type (;0;)))
11+
(alias outer 1 1 (type (;0;)))
1412
(export (;1;) "x" (type (eq 0)))
1513
(type (;2;) (own 1))
1614
(type (;3;) (func (result 2)))
1715
(export (;0;) "my-func" (func (type 3)))
1816
)
1917
)
20-
(import "foo:test-import/my-interface" (instance (;1;) (type 4)))
21-
(type (;5;)
18+
(import "foo:test-import/my-interface" (instance (;1;) (type 2)))
19+
(import "x" (type (;3;) (eq 1)))
20+
(type (;4;)
2221
(component
2322
(type (;0;)
2423
(instance
@@ -28,30 +27,30 @@
2827
(export (;0;) "foo:dependency/types" (instance (type 0)))
2928
)
3029
)
31-
(import "unlocked-dep=<test:bar>" (component (;0;) (type 5)))
30+
(import "unlocked-dep=<test:bar>" (component (;0;) (type 4)))
3231
(instance (;2;) (instantiate 0))
3332
(alias export 1 "my-func" (func (;0;)))
3433
(alias export 2 "foo:dependency/types" (instance (;3;)))
35-
(type (;6;)
34+
(type (;5;)
3635
(component
3736
(type (;0;)
3837
(instance
3938
(export (;0;) "x" (type (sub resource)))
4039
)
4140
)
4241
(import "foo:dependency/types" (instance (;0;) (type 0)))
43-
(alias outer 1 3 (type (;1;)))
42+
(alias outer 1 1 (type (;1;)))
4443
(import "x" (type (;2;) (eq 1)))
4544
(type (;3;) (own 2))
4645
(type (;4;) (func (result 3)))
4746
(import "my-func" (func (;0;) (type 4)))
4847
)
4948
)
50-
(import "unlocked-dep=<test:baz>" (component (;1;) (type 6)))
49+
(import "unlocked-dep=<test:baz>" (component (;1;) (type 5)))
5150
(instance (;4;) (instantiate 1
5251
(with "foo:dependency/types" (instance 3))
5352
(with "my-func" (func 0))
54-
(with "x" (type 2))
53+
(with "x" (type 3))
5554
)
5655
)
5756
)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
(component
2+
(type (;0;)
3+
(instance
4+
(type (;0;) (record (field "x" s32)))
5+
(export (;1;) "point" (type (eq 0)))
6+
)
7+
)
8+
(import "test:lib/shapes" (instance (;0;) (type 0)))
9+
(alias export 0 "point" (type (;1;)))
10+
(type (;2;) (record (field "origin" 1)))
11+
(import "region" (type (;3;) (eq 2)))
12+
(type (;4;)
13+
(component
14+
(type (;0;)
15+
(instance
16+
(type (;0;) (record (field "x" s32)))
17+
(export (;1;) "point" (type (eq 0)))
18+
)
19+
)
20+
(import "test:lib/shapes" (instance (;0;) (type 0)))
21+
(alias export 0 "point" (type (;1;)))
22+
(type (;2;) (record (field "origin" 1)))
23+
(import "region" (type (;3;) (eq 2)))
24+
(type (;4;) (func (result s32)))
25+
(export (;0;) "run" (func (type 4)))
26+
)
27+
)
28+
(import "unlocked-dep=<test:m>" (component (;0;) (type 4)))
29+
(instance (;1;) (instantiate 0
30+
(with "test:lib/shapes" (instance 0))
31+
(with "region" (type 3))
32+
)
33+
)
34+
(alias export 1 "run" (func (;0;)))
35+
(export (;1;) "run" (func 0))
36+
)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"packages": [
3+
{ "name": "test:m", "path": "m.wat" }
4+
],
5+
"nodes": [
6+
{ "type": "instantiation", "package": 0 },
7+
{ "type": "alias", "source": 0, "export": "run" }
8+
],
9+
"exports": [
10+
{ "node": 1, "name": "run" }
11+
]
12+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
(component
2+
;; Origin interface `shapes`, exporting `point`.
3+
(type (;0;)
4+
(instance
5+
(type (;0;) (record (field "x" s32)))
6+
(export (;1;) "point" (type (eq 0)))
7+
)
8+
)
9+
(import "test:lib/shapes" (instance (;0;) (type 0)))
10+
(alias export 0 "point" (type (;1;)))
11+
12+
;; A record whose field references `point` from `shapes` by id. wit-component
13+
;; produces this shape for a world that imports `shapes` and `use`s a record
14+
;; built on `point`.
15+
(type (;2;) (record (field "origin" 1)))
16+
(import "region" (type (;3;) (eq 2)))
17+
18+
(core module (;0;)
19+
(type (;0;) (func (result i32)))
20+
(func (;0;) (type 0) (result i32) i32.const 7)
21+
(export "run" (func 0))
22+
)
23+
(core instance (;0;) (instantiate 0))
24+
(alias core export 0 "run" (core func (;0;)))
25+
(type (;4;) (func (result s32)))
26+
(func (;0;) (type 4) (canon lift (core func 0)))
27+
(export "run" (func 0))
28+
)

crates/wac-parser/tests/encoding/instantiation.wac.result

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
(component
2-
(type (;0;) (func))
3-
(import "baz" (func (;0;) (type 0)))
4-
(type (;1;)
2+
(type (;0;)
53
(instance
64
(type (;0;) (func))
75
(export (;0;) "foo" (func (type 0)))
86
)
97
)
10-
(import "foo" (instance (;0;) (type 1)))
11-
(type (;2;)
8+
(import "foo" (instance (;0;) (type 0)))
9+
(type (;1;)
1210
(instance
1311
(type (;0;) (func))
1412
(export (;0;) "foo" (func (type 0)))
1513
)
1614
)
17-
(import "i" (instance $i (;1;) (type 2)))
18-
(type (;3;)
15+
(import "i" (instance $i (;1;) (type 1)))
16+
(type (;2;)
1917
(instance
2018
(type (;0;) (func))
2119
(export (;0;) "baz" (func (type 0)))
2220
)
2321
)
24-
(import "i2" (instance $i2 (;2;) (type 3)))
22+
(import "i2" (instance $i2 (;2;) (type 2)))
23+
(type (;3;) (func))
24+
(import "baz" (func (;0;) (type 3)))
2525
(type (;4;) (func))
2626
(import "f" (func $f (;1;) (type 4)))
2727
(type (;5;)

0 commit comments

Comments
 (0)