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

WIT: Implement @since and @unstable annotations #1508

Merged
merged 11 commits into from
May 28, 2024
6 changes: 3 additions & 3 deletions crates/wit-component/src/dummy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub fn dummy_module(resolve: &Resolve, world: WorldId) -> Vec<u8> {
push_tys(&mut wat, "result", &sig.results);
wat.push_str("))\n");
}
WorldItem::Interface(import) => {
WorldItem::Interface { id: import, .. } => {
let name = resolve.name_world_key(name);
for (_, func) in resolve.interfaces[*import].functions.iter() {
let sig = resolve.wasm_signature(AbiVariant::GuestImport, func);
Expand All @@ -39,7 +39,7 @@ pub fn dummy_module(resolve: &Resolve, world: WorldId) -> Vec<u8> {
// Import any resource-related functions for exports.
for (name, export) in world.exports.iter() {
let export = match export {
WorldItem::Interface(export) => *export,
WorldItem::Interface { id, .. } => *id,
_ => continue,
};
let module = format!("[export]{}", resolve.name_world_key(name));
Expand All @@ -64,7 +64,7 @@ pub fn dummy_module(resolve: &Resolve, world: WorldId) -> Vec<u8> {
WorldItem::Function(func) => {
push_func(&mut wat, &func.name, resolve, func);
}
WorldItem::Interface(export) => {
WorldItem::Interface { id: export, .. } => {
let name = resolve.name_world_key(name);
for (_, func) in resolve.interfaces[*export].functions.iter() {
let name = func.core_export_name(Some(&name));
Expand Down
8 changes: 4 additions & 4 deletions crates/wit-component/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ impl<'a> EncodingState<'a> {
for (name, item) in resolve.worlds[world].imports.iter() {
let func = match item {
WorldItem::Function(f) => f,
WorldItem::Interface(_) | WorldItem::Type(_) => continue,
WorldItem::Interface { .. } | WorldItem::Type(_) => continue,
};
let name = resolve.name_world_key(name);
if !info.lowerings.contains_key(&name) {
Expand Down Expand Up @@ -751,8 +751,8 @@ impl<'a> EncodingState<'a> {
self.component
.export(&export_string, ComponentExportKind::Func, idx, None);
}
WorldItem::Interface(export) => {
self.encode_interface_export(&export_string, module, *export)?;
WorldItem::Interface { id, .. } => {
self.encode_interface_export(&export_string, module, *id)?;
}
WorldItem::Type(_) => unreachable!(),
}
Expand Down Expand Up @@ -2001,7 +2001,7 @@ impl ComponentEncoder {
.with_context(|| {
format!("failed to merge WIT packages of adapter `{name}` into main packages")
})?
.worlds[metadata.world.index()];
.map_world(metadata.world, None)?;
self.metadata
.resolve
.merge_worlds(world, self.metadata.world)
Expand Down
18 changes: 9 additions & 9 deletions crates/wit-component/src/encoding/wit/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ pub fn encode_component(resolve: &Resolve, package: PackageId) -> Result<Compone
};
encoder.run()?;

let package_docs = PackageDocs::extract(resolve, package);
let package_metadata = PackageMetadata::extract(resolve, package);
encoder.component.custom_section(&CustomSection {
name: PackageDocs::SECTION_NAME.into(),
data: package_docs.encode()?.into(),
name: PackageMetadata::SECTION_NAME.into(),
data: package_metadata.encode()?.into(),
});

Ok(encoder.component)
Expand Down Expand Up @@ -351,9 +351,9 @@ pub fn encode_world(resolve: &Resolve, world_id: WorldId) -> Result<ComponentTyp
let name = resolve.name_world_key(name);
log::trace!("encoding import {name}");
let ty = match import {
WorldItem::Interface(i) => {
component.interface = Some(*i);
let idx = component.encode_instance(*i)?;
WorldItem::Interface { id, .. } => {
component.interface = Some(*id);
let idx = component.encode_instance(*id)?;
ComponentTypeRef::Instance(idx)
}
WorldItem::Function(f) => {
Expand All @@ -376,9 +376,9 @@ pub fn encode_world(resolve: &Resolve, world_id: WorldId) -> Result<ComponentTyp
let name = resolve.name_world_key(name);
log::trace!("encoding export {name}");
let ty = match export {
WorldItem::Interface(i) => {
component.interface = Some(*i);
let idx = component.encode_instance(*i)?;
WorldItem::Interface { id, .. } => {
component.interface = Some(*id);
let idx = component.encode_instance(*id)?;
ComponentTypeRef::Instance(idx)
}
WorldItem::Function(f) => {
Expand Down
6 changes: 3 additions & 3 deletions crates/wit-component/src/encoding/wit/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ pub fn encode_component(resolve: &Resolve, package: PackageId) -> Result<Compone
};
encoder.run()?;

let package_docs = PackageDocs::extract(resolve, package);
let package_metadata = PackageMetadata::extract(resolve, package);
encoder.component.custom_section(&CustomSection {
name: PackageDocs::SECTION_NAME.into(),
data: package_docs.encode()?.into(),
name: PackageMetadata::SECTION_NAME.into(),
data: package_metadata.encode()?.into(),
});

Ok(encoder.component)
Expand Down
18 changes: 10 additions & 8 deletions crates/wit-component/src/encoding/world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,9 @@ impl<'a> ComponentWorld<'a> {
.iter()
.all(|name| match &resolve.worlds[world].exports[name] {
WorldItem::Function(_) => false,
WorldItem::Interface(id) => resolve.interfaces[*id].functions.is_empty(),
WorldItem::Interface { id, .. } => {
resolve.interfaces[*id].functions.is_empty()
}
WorldItem::Type(_) => true,
})
};
Expand Down Expand Up @@ -209,7 +211,7 @@ impl<'a> ComponentWorld<'a> {
for name in required_exports {
match &resolve.worlds[world].exports[name] {
WorldItem::Function(func) => add_func(func, None),
WorldItem::Interface(id) => {
WorldItem::Interface { id, .. } => {
let name = resolve.name_world_key(name);
for (_, func) in resolve.interfaces[*id].functions.iter() {
add_func(func, Some(&name));
Expand Down Expand Up @@ -277,11 +279,11 @@ impl<'a> ComponentWorld<'a> {
let empty = IndexSet::new();
let import_map_key = match item {
WorldItem::Function(_) | WorldItem::Type(_) => None,
WorldItem::Interface(_) => Some(name),
WorldItem::Interface { .. } => Some(name),
};
let interface_id = match item {
WorldItem::Function(_) | WorldItem::Type(_) => None,
WorldItem::Interface(id) => Some(*id),
WorldItem::Interface { id, .. } => Some(*id),
};
let required = required
.get(import_map_key.as_deref().unwrap_or(BARE_FUNC_MODULE_NAME))
Expand All @@ -300,7 +302,7 @@ impl<'a> ComponentWorld<'a> {
WorldItem::Type(ty) => {
interface.add_type(required, resolve, *ty);
}
WorldItem::Interface(id) => {
WorldItem::Interface { id, .. } => {
for (_name, ty) in resolve.interfaces[*id].types.iter() {
interface.add_type(required, resolve, *ty);
}
Expand Down Expand Up @@ -344,7 +346,7 @@ impl<'a> ComponentWorld<'a> {
for (name, item) in resolve.worlds[world].exports.iter() {
log::trace!("add live world export `{}`", resolve.name_world_key(name));
let id = match item {
WorldItem::Interface(id) => id,
WorldItem::Interface { id, .. } => id,
WorldItem::Function(_) | WorldItem::Type(_) => {
live.add_world_item(resolve, item);
continue;
Expand Down Expand Up @@ -400,7 +402,7 @@ impl<'a> ComponentWorld<'a> {
log::trace!("add live function import `{name}`");
live.add_func(resolve, func);
}
WorldItem::Interface(id) => {
WorldItem::Interface { id, .. } => {
let required = match required.get(name.as_str()) {
Some(set) => set,
None => continue,
Expand Down Expand Up @@ -431,7 +433,7 @@ impl<'a> ComponentWorld<'a> {
for (_name, item) in exports.iter() {
let id = match item {
WorldItem::Function(_) => continue,
WorldItem::Interface(id) => *id,
WorldItem::Interface { id, .. } => *id,
WorldItem::Type(_) => unreachable!(),
};
let mut set = HashSet::new();
Expand Down
11 changes: 6 additions & 5 deletions crates/wit-component/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ impl Default for Bindgen {
includes: Default::default(),
include_names: Default::default(),
package: Some(package),
stability: Default::default(),
});
resolve.packages[package]
.worlds
Expand Down Expand Up @@ -306,7 +307,7 @@ impl Bindgen {
.resolve
.merge(resolve)
.context("failed to merge WIT package sets together")?
.worlds[world.index()];
.map_world(world, None)?;
self.resolve
.merge_worlds(world, self.world)
.context("failed to merge worlds from two documents")?;
Expand Down Expand Up @@ -361,8 +362,8 @@ impl ModuleMetadata {
.insert((BARE_FUNC_MODULE_NAME.to_string(), name.clone()), encoding);
assert!(prev.is_none());
}
WorldItem::Interface(i) => {
for (func, _) in resolve.interfaces[*i].functions.iter() {
WorldItem::Interface { id, .. } => {
for (func, _) in resolve.interfaces[*id].functions.iter() {
let prev = ret
.import_encodings
.insert((name.clone(), func.clone()), encoding);
Expand All @@ -381,8 +382,8 @@ impl ModuleMetadata {
let prev = ret.export_encodings.insert(name.clone(), encoding);
assert!(prev.is_none());
}
WorldItem::Interface(i) => {
for (_, func) in resolve.interfaces[*i].functions.iter() {
WorldItem::Interface { id, .. } => {
for (_, func) in resolve.interfaces[*id].functions.iter() {
let name = func.core_export_name(Some(&name)).into_owned();
let prev = ret.export_encodings.insert(name, encoding);
assert!(prev.is_none());
Expand Down
55 changes: 42 additions & 13 deletions crates/wit-component/src/printing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ impl WitPrinter {
self.output.push_str("\n\n");
for (name, id) in pkg.interfaces.iter() {
self.print_docs(&resolve.interfaces[*id].docs);
self.print_stability(&resolve.interfaces[*id].stability);
self.output.push_str("interface ");
self.print_name(name);
self.output.push_str(" {\n");
Expand All @@ -74,6 +75,7 @@ impl WitPrinter {

for (name, id) in pkg.worlds.iter() {
self.print_docs(&resolve.worlds[*id].docs);
self.print_stability(&resolve.worlds[*id].stability);
self.output.push_str("world ");
self.print_name(name);
self.output.push_str(" {\n");
Expand Down Expand Up @@ -125,6 +127,7 @@ impl WitPrinter {
for (name, func) in freestanding {
self.new_item();
self.print_docs(&func.docs);
self.print_stability(&func.stability);
self.print_name(name);
self.output.push_str(": ");
self.print_function(resolve, func)?;
Expand All @@ -147,7 +150,7 @@ impl WitPrinter {
// Partition types defined in this interface into either those imported
// from foreign interfaces or those defined locally.
let mut types_to_declare = Vec::new();
let mut types_to_import: Vec<(_, Vec<_>)> = Vec::new();
let mut types_to_import: Vec<(_, &_, Vec<_>)> = Vec::new();
for (name, ty_id) in types {
let ty = &resolve.types[ty_id];
if let TypeDefKind::Type(Type::Id(other)) = ty.kind {
Expand All @@ -159,13 +162,17 @@ impl WitPrinter {
.name
.as_ref()
.ok_or_else(|| anyhow!("cannot import unnamed type"))?;
if let Some((owner, list)) = types_to_import.last_mut() {
if *owner == other_owner {
if let Some((owner, stability, list)) = types_to_import.last_mut() {
if *owner == other_owner && ty.stability == **stability {
list.push((name, other_name));
continue;
}
}
types_to_import.push((other_owner, vec![(name, other_name)]));
types_to_import.push((
other_owner,
&ty.stability,
vec![(name, other_name)],
));
continue;
}
_ => {}
Expand All @@ -181,8 +188,9 @@ impl WitPrinter {
TypeOwner::World(id) => resolve.worlds[id].package.unwrap(),
TypeOwner::None => unreachable!(),
};
for (owner, tys) in types_to_import {
for (owner, stability, tys) in types_to_import {
self.any_items = true;
self.print_stability(stability);
write!(&mut self.output, "use ")?;
let id = match owner {
TypeOwner::Interface(id) => id,
Expand Down Expand Up @@ -212,6 +220,7 @@ impl WitPrinter {
for id in types_to_declare {
self.new_item();
self.print_docs(&resolve.types[id].docs);
self.print_stability(&resolve.types[id].stability);
match resolve.types[id].kind {
TypeDefKind::Resource => self.print_resource(
resolve,
Expand All @@ -236,17 +245,16 @@ impl WitPrinter {
}
self.output.push_str(" {\n");
for func in funcs {
self.print_docs(&func.docs);
self.print_stability(&func.stability);

match &func.kind {
FunctionKind::Constructor(_) => {
self.print_docs(&func.docs);
}
FunctionKind::Constructor(_) => {}
FunctionKind::Method(_) => {
self.print_docs(&func.docs);
self.print_name(func.item_name());
self.output.push_str(": ");
}
FunctionKind::Static(_) => {
self.print_docs(&func.docs);
self.print_name(func.item_name());
self.output.push_str(": ");
self.output.push_str("static ");
Expand Down Expand Up @@ -367,21 +375,22 @@ impl WitPrinter {
// Print inline item docs
if matches!(name, WorldKey::Name(_)) {
self.print_docs(match item {
WorldItem::Interface(id) => &resolve.interfaces[*id].docs,
WorldItem::Interface { id, .. } => &resolve.interfaces[*id].docs,
WorldItem::Function(f) => &f.docs,
// Types are handled separately
WorldItem::Type(_) => unreachable!(),
});
}

self.print_stability(item.stability(resolve));
self.output.push_str(desc);
self.output.push_str(" ");
match name {
WorldKey::Name(name) => {
self.print_name(name);
self.output.push_str(": ");
match item {
WorldItem::Interface(id) => {
WorldItem::Interface { id, .. } => {
assert!(resolve.interfaces[*id].name.is_none());
writeln!(self.output, "interface {{")?;
self.print_interface(resolve, *id)?;
Expand All @@ -398,7 +407,7 @@ impl WitPrinter {
}
WorldKey::Interface(id) => {
match item {
WorldItem::Interface(id2) => assert_eq!(id, id2),
WorldItem::Interface { id: id2, .. } => assert_eq!(id, id2),
_ => unreachable!(),
}
self.print_path_to_interface(resolve, *id, cur_pkg)?;
Expand Down Expand Up @@ -868,6 +877,26 @@ impl WitPrinter {
}
}
}

fn print_stability(&mut self, stability: &Stability) {
match stability {
Stability::Unknown => {}
Stability::Stable { since, feature } => {
self.output.push_str("@since(version = ");
self.output.push_str(&since.to_string());
if let Some(feature) = feature {
self.output.push_str(", feature = ");
self.output.push_str(feature);
}
self.output.push_str(")\n");
}
Stability::Unstable { feature } => {
self.output.push_str("@unstable(feature = ");
self.output.push_str(feature);
self.output.push_str(")\n");
}
}
}
}

fn resource_func(f: &Function) -> Option<TypeId> {
Expand Down