Skip to content

Commit d4d53aa

Browse files
authored
Merge pull request #74 from peterhuene/fix-resource-import
Fix the encoding of imported resources in the `CompositionGraph`.
2 parents 66c0672 + 1ad1447 commit d4d53aa

8 files changed

Lines changed: 258 additions & 71 deletions

File tree

crates/wac-graph/src/encoding.rs

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use wasm_encoder::{
1414

1515
/// A type used to abstract the API differences between a component builder,
1616
/// component type, and instance type from `wasm-encoder`.
17+
#[derive(Debug)]
1718
enum Encodable {
1819
Builder(ComponentBuilder),
1920
Instance(InstanceType),
@@ -94,7 +95,7 @@ impl Default for Encodable {
9495
}
9596
}
9697

97-
#[derive(Default)]
98+
#[derive(Debug, Default)]
9899
pub struct Scope {
99100
/// The map from types to encoded type index.
100101
pub type_indexes: IndexMap<Type, u32>,
@@ -108,7 +109,7 @@ pub struct Scope {
108109
encodable: Encodable,
109110
}
110111

111-
#[derive(Default)]
112+
#[derive(Debug, Default)]
112113
pub struct State {
113114
/// The stack of encoding scopes.
114115
scopes: Vec<Scope>,
@@ -630,7 +631,8 @@ impl<'a> TypeEncoder<'a> {
630631

631632
fn import(&self, state: &mut State, name: &str, kind: ItemKind) {
632633
if let ItemKind::Type(Type::Resource(id)) = kind {
633-
return self.import_resource(state, name, id);
634+
self.import_resource(state, name, id);
635+
return;
634636
}
635637

636638
log::debug!("encoding {kind} import `{name}`", kind = kind.desc(self.0));
@@ -669,9 +671,9 @@ impl<'a> TypeEncoder<'a> {
669671
}
670672
}
671673

672-
fn import_resource(&self, state: &mut State, name: &str, id: ResourceId) {
673-
if state.current.resources.contains_key(name) {
674-
return;
674+
pub fn import_resource(&self, state: &mut State, name: &str, id: ResourceId) -> u32 {
675+
if let Some(index) = state.current.resources.get(name) {
676+
return *index;
675677
}
676678

677679
log::debug!("encoding import of resource `{name}`");
@@ -687,17 +689,43 @@ impl<'a> TypeEncoder<'a> {
687689

688690
log::debug!("encoded outer alias for resource `{name}` to type index {index}");
689691
index
690-
} else if let Some(alias_of) = resource.alias_of {
691-
// This is an alias to another resource at the same scope
692-
let orig =
693-
state.current.resources[self.0[self.0.resolve_resource(alias_of)].name.as_str()];
692+
} else if let Some(alias) = resource.alias {
693+
let source = self.0.resolve_resource(alias.source);
694+
let source_index = if let Some(index) =
695+
state.current.resources.get(self.0[source].name.as_str())
696+
{
697+
// The source resource was previously imported
698+
*index
699+
} else if let Some(index) = state.current.type_indexes.get(&Type::Resource(source)) {
700+
// The source resource isn't directly imported, but was previously aliased
701+
*index
702+
} else {
703+
// Otherwise, we need to alias the source resource
704+
// This should only occur for resources owned by interfaces
705+
let source_index = state.current.encodable.type_count();
706+
let iid = self.0[alias.owner.expect("should have owner")]
707+
.id
708+
.as_deref()
709+
.expect("expected an interface with an id");
710+
state.current.encodable.alias(Alias::InstanceExport {
711+
instance: state.current.instances[iid],
712+
kind: ComponentExportKind::Type,
713+
name: self.0[source].name.as_str(),
714+
});
715+
state
716+
.current
717+
.type_indexes
718+
.insert(Type::Resource(source), source_index);
719+
source_index
720+
};
721+
694722
let index = state.current.encodable.type_count();
695723
state
696724
.current
697725
.encodable
698-
.import_type(name, ComponentTypeRef::Type(TypeBounds::Eq(orig)));
726+
.import_type(name, ComponentTypeRef::Type(TypeBounds::Eq(source_index)));
699727

700-
log::debug!("encoded import for resource `{name}` as type index {index} (alias of type index {orig})");
728+
log::debug!("encoded import for resource `{name}` as type index {index} (alias of type index {source_index})");
701729
index
702730
} else {
703731
// Otherwise, this is a new resource type, import with a subtype bounds
@@ -712,6 +740,7 @@ impl<'a> TypeEncoder<'a> {
712740
};
713741

714742
state.current.resources.insert(resource.name.clone(), index);
743+
index
715744
}
716745

717746
fn export(&self, state: &mut State, name: &str, kind: ItemKind) -> u32 {
@@ -759,10 +788,10 @@ impl<'a> TypeEncoder<'a> {
759788
Self::export_type(state, name, ComponentTypeRef::Type(TypeBounds::Eq(outer)));
760789
log::debug!("encoded outer alias for resource `{name}` as type index {index}");
761790
index
762-
} else if let Some(alias_of) = resource.alias_of {
791+
} else if let Some(alias) = resource.alias {
763792
// This is an alias to another resource at the same scope
764-
let index =
765-
state.current.resources[self.0[self.0.resolve_resource(alias_of)].name.as_str()];
793+
let index = state.current.resources
794+
[self.0[self.0.resolve_resource(alias.source)].name.as_str()];
766795
let index =
767796
Self::export_type(state, name, ComponentTypeRef::Type(TypeBounds::Eq(index)));
768797
log::debug!("encoded alias for resource `{name}` as type index {index}");

crates/wac-graph/src/graph.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1458,13 +1458,19 @@ impl<'a> CompositionGraphEncoder<'a> {
14581458
}
14591459
}
14601460

1461+
let encoder = TypeEncoder::new(types);
1462+
1463+
// Defer to special handling if the item being imported is a resource
1464+
if let ItemKind::Type(Type::Resource(id)) = kind {
1465+
return encoder.import_resource(state, name, id);
1466+
}
1467+
14611468
log::debug!(
14621469
"encoding import of {kind} `{name}`",
14631470
kind = kind.desc(types)
14641471
);
14651472

14661473
// Encode the type and import
1467-
let encoder = TypeEncoder::new(types);
14681474
let ty = encoder.ty(state, kind.ty(), None);
14691475
let index = state.builder().import(
14701476
name,
@@ -1712,7 +1718,7 @@ mod test {
17121718
let mut graph = CompositionGraph::new();
17131719
let id = graph.types_mut().add_resource(Resource {
17141720
name: "a".to_string(),
1715-
alias_of: None,
1721+
alias: None,
17161722
});
17171723
assert!(matches!(
17181724
graph.define_type("foo", Type::Resource(id)).unwrap_err(),
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+
(export (;0;) "my-resource" (type (sub resource)))
5+
)
6+
)
7+
(import "test:foo/my-interface" (instance (;0;) (type 0)))
8+
(alias export 0 "my-resource" (type (;1;)))
9+
(import "my-resource" (type (;2;) (eq 1)))
10+
(import "my-resource2" (type (;3;) (eq 2)))
11+
(type (;4;)
12+
(component
13+
(type (;0;)
14+
(instance
15+
(export (;0;) "my-resource" (type (sub resource)))
16+
)
17+
)
18+
(import "test:foo/my-interface" (instance (;0;) (type 0)))
19+
(alias export 0 "my-resource" (type (;1;)))
20+
(import "my-resource" (type (;2;) (eq 1)))
21+
(import "my-resource2" (type (;3;) (eq 2)))
22+
(type (;4;) (own 3))
23+
(type (;5;) (func (param "r" 4)))
24+
(export (;0;) "my-func" (func (type 5)))
25+
)
26+
)
27+
(import "unlocked-dep=<test:foo>" (component (;0;) (type 4)))
28+
(instance (;1;) (instantiate 0
29+
(with "test:foo/my-interface" (instance 0))
30+
(with "my-resource" (type 2))
31+
(with "my-resource2" (type 3))
32+
)
33+
)
34+
(alias export 1 "my-func" (func (;0;)))
35+
(export (;1;) "my-func" (func 0))
36+
)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package test:foo;
2+
3+
world my-world {
4+
use my-interface.{my-resource};
5+
type my-resource2 = my-resource;
6+
7+
export my-func: func(r: my-resource2);
8+
}
9+
10+
interface my-interface {
11+
resource my-resource {}
12+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"packages": [
3+
{
4+
"name": "test:foo",
5+
"path": "foo.wit"
6+
}
7+
],
8+
"nodes": [
9+
{
10+
"type": "instantiation",
11+
"package": 0
12+
},
13+
{
14+
"type": "alias",
15+
"source": 0,
16+
"export": "my-func"
17+
}
18+
],
19+
"exports": [
20+
{
21+
"node": 1,
22+
"name": "my-func"
23+
}
24+
]
25+
}

0 commit comments

Comments
 (0)