Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nested interfaces in wit #1624

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

macovedj
Copy link
Contributor

This PR enables the ability to describe nested interfaces in wit via the nest keyword.

package foo:bar;

interface baz {
  nest other:pkg/qux
}

This would indicate that that the instance associated with baz would export the instance associated with interface qux from package other:pkg.

(component 
  (type instance
    (type instance 
    ... definition of "other:pkg/qux" 
    )
   (export "other:pkg/qux" type 0)
  )
  (export "foo:bar/baz" type 0)
)

As I understand it, most use cases most immediately benefit from nesting interfaces from foreign packages, so I started with that, though we could certainly extend this PR or have follow ups to support any combo of locally defined/inlined/anonymous interfaces being nested.

This issue points out that wit currently is not able to express nested instances that can be expressed in wat/binary, so wit-bindgen can't be used by language toolchains to generate that binary. This syntax can be leveraged so that the unlocked dependency syntax referenced in the linked issue can specify the exports it expects in the imports it's describing.

Copy link
Member

@alexcrichton alexcrichton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've done a bit of a cursory review to start off with but I think that this still has a few missing pieces. For example src/resolve.rs in the wit-parser care will need to be updated to handle this new features of interfaces in a number of locations.

At a high level though I think it would be best to propose this feature on the component-model repository first. There's a number of high-level questions about how to design this feature that I think should be thought through such as:

  • Is the syntax nest a:b/c; what everyone agrees on?
  • Should nest a; be allowed?
  • Should nest a { /* ... */ } be allowed?
  • How will code generators for guest langauges map this?

Those are at least the questions off the top of my head which I think would be best to settle first before finishing up the implementation here. A PR to the component model repository would also help flesh out the wasm-encoding of this WIT construct.

Comment on lines +578 to +585
let id = parse_id(tokens)?;
tokens.expect(Token::Colon)?;
// `foo:bar/baz@1.0`
let namespace = id;
let pkg_name = parse_id(tokens)?;
tokens.expect(Token::Slash)?;
let name = parse_id(tokens)?;
let version = parse_opt_version(tokens)?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that this is a duplication of UseName's internal parsing, but could UseName be used here instead? That would enable consistently being able to refer to both foreign and local interfaces with nest

Comment on lines +305 to +328
decl_list
.for_each_nest(|nest: &Nest| {
let deps = foreign_deps
.entry(nest.id.package_name())
.or_insert_with(|| {
self.foreign_dep_spans.push(nest.id.span);
IndexMap::new()
});
let id = *deps.entry(nest.name.name).or_insert_with(|| {
log::trace!(
"creating an interface for foreign dep: {}/{}",
nest.id.package_name(),
nest.name.name
);

AstItem::Interface(self.alloc_interface(nest.name.span))
});
match id {
AstItem::Interface(id) => foreign_interfaces.insert(id),
AstItem::World(_) => unreachable!(),
};
Ok(())
})
.unwrap();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think ideally if nest used a UsePath then thiscould go away, along with the for_each_nest method?

Comment on lines +402 to +415
for nest_item in i.items.iter() {
if let InterfaceItem::Nest(n) = nest_item {
if package_items.insert(n.name.name, n.name.span).is_some() {
bail!(Error::new(
n.name.span,
format!("duplicate item named `{}`", n.name.name),
))
}
let prev = decl_list_ns.insert(n.name.name, ());
assert!(prev.is_none());
let prev = order.insert(n.name.name, Vec::new());
assert!(prev.is_none());
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this is quite right because this seems like it would be an interface-level validation rather than a package-level validation which I think this loop is doing.

let id = self.alloc_interface(package_items[name]);
self.interfaces[id].name = Some(name.to_string());
for item in &i.items {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this loop and processing nest items in general would be best done during the elaboration of an interface to uniformly handle it next to other interface constructs

Comment on lines +417 to +418
pub package_name: PackageName,
pub iface_name: String,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think both of these fields can be elided in favor of looking them up through the id here

self.print_stability(&item.1.stability);
self.print_docs(&item.1.docs);
self.output.push_str("nest ");
self.print_name(item.0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that this is quite right because this should print nest a:b/c; or similar so I think an interface id needs to be printed here rather than just the string name

@macovedj
Copy link
Contributor Author

Sounds good! I can work on opening something up over there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants