Skip to content

Commit a3d1fbf

Browse files
committed
use wit_parser::TypeIdVisitor to simplify sort_types
1 parent 2742907 commit a3d1fbf

4 files changed

Lines changed: 66 additions & 111 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/cpp/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ anyhow = { workspace = true }
2727
heck = { workspace = true }
2828
clap = { workspace = true, optional = true }
2929
indexmap = { workspace = true }
30+
wit-parser = { workspace = true }
3031

3132
[dev-dependencies]
3233
test-helpers = { path = '../test-helpers' }

crates/cpp/src/lib.rs

Lines changed: 63 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use wit_bindgen_core::{
2121
WorldKey,
2222
},
2323
};
24+
use wit_parser::TypeIdVisitor;
2425

2526
// mod wamr;
2627
mod symbol_name;
@@ -879,11 +880,10 @@ impl CppInterfaceGenerator<'_> {
879880
fn types(&mut self, iface: InterfaceId) {
880881
let iface_data = &self.resolve().interfaces[iface];
881882

882-
// Second pass: emit full type definitions for all types.
883-
//
884-
// Here we sort the types topologically, taking into consideration the
885-
// parameter and return types of functions associated with resource
886-
// types. This ensures each type is declared before any uses of it.
883+
// Here we sort the types topologically before emitting code for them,
884+
// taking into consideration the parameter and return types of functions
885+
// associated with resource types. This ensures each type is declared
886+
// before any uses of it.
887887
for (name, id) in sort_types(self.resolve, &iface_data.types) {
888888
self.define_type(name, id);
889889
}
@@ -3628,119 +3628,72 @@ fn sort_types<'a>(
36283628
resolve: &Resolve,
36293629
types: &'a IndexMap<String, TypeId>,
36303630
) -> IndexMap<&'a str, TypeId> {
3631-
let mut sorted = IndexSet::new();
3632-
let mut visited = HashSet::new();
3633-
for id in types.values() {
3634-
sort(resolve, Type::Id(*id), &mut sorted, &mut visited);
3631+
struct Visitor<'a> {
3632+
resolve: &'a Resolve,
3633+
sorted: IndexSet<TypeId>,
3634+
visited: HashSet<TypeId>,
36353635
}
3636-
let names = types
3637-
.iter()
3638-
.map(|(k, v)| (*v, k.as_str()))
3639-
.collect::<HashMap<_, _>>();
3640-
sorted
3641-
.into_iter()
3642-
.filter_map(|v| names.get(&v).map(|k| (*k, v)))
3643-
.collect()
3644-
}
36453636

3646-
fn sort(resolve: &Resolve, ty: Type, sorted: &mut IndexSet<TypeId>, visited: &mut HashSet<TypeId>) {
3647-
match ty {
3648-
Type::Bool
3649-
| Type::U8
3650-
| Type::U16
3651-
| Type::U32
3652-
| Type::S8
3653-
| Type::S16
3654-
| Type::S32
3655-
| Type::Char
3656-
| Type::U64
3657-
| Type::S64
3658-
| Type::F32
3659-
| Type::F64
3660-
| Type::String
3661-
| Type::ErrorContext => (),
3662-
Type::Id(id) => {
3663-
let ty = &resolve.types[id];
3664-
match &ty.kind {
3665-
TypeDefKind::Record(record) => {
3666-
for field in &record.fields {
3667-
sort(resolve, field.ty, sorted, visited);
3668-
}
3669-
sorted.insert(id);
3670-
}
3671-
TypeDefKind::Variant(variant) => {
3672-
for case in &variant.cases {
3673-
if let Some(ty) = case.ty {
3674-
sort(resolve, ty, sorted, visited);
3675-
}
3676-
}
3677-
sorted.insert(id);
3678-
}
3679-
TypeDefKind::Enum(_) | TypeDefKind::Flags(_) => {
3680-
sorted.insert(id);
3681-
}
3682-
TypeDefKind::Handle(Handle::Borrow(resource) | Handle::Own(resource)) => {
3683-
sort(resolve, Type::Id(*resource), sorted, visited);
3684-
sorted.insert(id);
3685-
}
3686-
TypeDefKind::Option(some) => {
3687-
sort(resolve, *some, sorted, visited);
3688-
sorted.insert(id);
3689-
}
3690-
TypeDefKind::Result(result) => {
3691-
if let Some(ty) = result.ok {
3692-
sort(resolve, ty, sorted, visited);
3693-
}
3694-
if let Some(ty) = result.err {
3695-
sort(resolve, ty, sorted, visited);
3696-
}
3697-
sorted.insert(id);
3698-
}
3699-
TypeDefKind::Tuple(tuple) => {
3700-
for ty in &tuple.types {
3701-
sort(resolve, *ty, sorted, visited);
3702-
}
3703-
sorted.insert(id);
3704-
}
3705-
TypeDefKind::List(ty) | TypeDefKind::FixedLengthList(ty, _) => {
3706-
sort(resolve, *ty, sorted, visited);
3707-
}
3708-
TypeDefKind::Type(ty) => {
3709-
sort(resolve, *ty, sorted, visited);
3710-
}
3711-
TypeDefKind::Resource => {
3712-
// Here we avoid infinite recursion by remembering if we've
3713-
// seen this type already.
3714-
if !visited.contains(&id) {
3715-
visited.insert(id);
3716-
3717-
if let TypeOwner::Interface(interface) = ty.owner {
3718-
for function in resolve.interfaces[interface].functions.values() {
3719-
if let Some(resource) = function.kind.resource()
3720-
&& resource == id
3721-
{
3722-
for parameter in &function.params {
3723-
sort(resolve, parameter.ty, &mut *sorted, &mut *visited);
3724-
}
3725-
3726-
if let Some(ty) = function.result {
3727-
sort(resolve, ty, &mut *sorted, &mut *visited);
3728-
}
3637+
impl TypeIdVisitor for Visitor<'_> {
3638+
fn before_visit_type_id(&mut self, id: TypeId) -> bool {
3639+
let ty = &self.resolve.types[id];
3640+
if let TypeDefKind::Resource = &ty.kind {
3641+
// Here we avoid infinite recursion by remembering if we've seen
3642+
// this type already.
3643+
if self.visited.contains(&id) {
3644+
false
3645+
} else {
3646+
self.visited.insert(id);
3647+
3648+
// TypeIdVisitor does not consider the parameter and return
3649+
// types of resource associated functions to be transitive
3650+
// types, so we need to handle that ourselves here.
3651+
if let TypeOwner::Interface(interface) = ty.owner {
3652+
for function in self.resolve.interfaces[interface].functions.values() {
3653+
if let Some(resource) = function.kind.resource()
3654+
&& resource == id
3655+
{
3656+
for parameter in &function.params {
3657+
self.visit_type(self.resolve, &parameter.ty);
3658+
}
3659+
3660+
if let Some(ty) = function.result {
3661+
self.visit_type(self.resolve, &ty);
37293662
}
37303663
}
37313664
}
3732-
3733-
sorted.insert(id);
37343665
}
3666+
3667+
true
37353668
}
3736-
TypeDefKind::Stream(ty) | TypeDefKind::Future(ty) => {
3737-
if let Some(ty) = ty {
3738-
sort(resolve, *ty, sorted, visited);
3739-
}
3740-
sorted.insert(id);
3741-
}
3742-
kind => todo!("{kind:?}"),
3669+
} else {
3670+
true
37433671
}
37443672
}
3673+
3674+
fn after_visit_type_id(&mut self, id: TypeId) {
3675+
self.sorted.insert(id);
3676+
}
37453677
}
3678+
3679+
let mut visitor = Visitor {
3680+
resolve,
3681+
sorted: Default::default(),
3682+
visited: Default::default(),
3683+
};
3684+
3685+
for &id in types.values() {
3686+
visitor.visit_type_id(resolve, id);
3687+
}
3688+
3689+
let names = types
3690+
.iter()
3691+
.map(|(k, v)| (*v, k.as_str()))
3692+
.collect::<HashMap<_, _>>();
3693+
3694+
visitor
3695+
.sorted
3696+
.into_iter()
3697+
.filter_map(|v| names.get(&v).map(|k| (*k, v)))
3698+
.collect()
37463699
}

crates/test/src/cpp.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ impl LanguageMethods for Cpp {
5050
return false;
5151
}
5252
return match name {
53-
"issue1514-6.wit" | "map.wit" => true,
53+
"issue1514-6.wit" | "named-fixed-length-list.wit" | "map.wit" => true,
5454
_ => false,
5555
} || config.async_;
5656
}

0 commit comments

Comments
 (0)