Skip to content

Commit 6de5fbf

Browse files
authored
Disallow returns-of-borrows in WIT (#1469)
* Refactor how spans are held in `UnresolvedPackage` Put them in a `struct` with named fields and group them together by relevance. * Disallow returns-of-borrows in WIT Currently in the component model it's not valid to have a function that returns a `borrow` resource. In WIT, however, there's no protection currently against this until a component is actually made. Bindings generators additionally might panic and/or assume that they won't need to generate bindings for borrows. This commit implements a `Resolve`-level validation that a function never returns a `borrow<T>` transitively within it. This ensures that the error for returning a borrowed resource shows up earlier in the development cycle and additionally ensures that bindings generators don't have to each specifically handle this case. Closes bytecodealliance/wit-bindgen#907 * Fix test expectation
1 parent 1ef6026 commit 6de5fbf

28 files changed

Lines changed: 323 additions & 244 deletions

crates/wit-parser/src/ast/resolve.rs

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -64,23 +64,17 @@ pub struct Resolver<'a> {
6464
/// pointing to it if the item isn't actually defined.
6565
unknown_type_spans: Vec<Span>,
6666

67-
/// Spans for each world in `self.world` to assign for each import/export
68-
/// for later error reporting.
69-
world_item_spans: Vec<(Vec<Span>, Vec<Span>)>,
70-
7167
/// Spans for each world in `self.world`
72-
world_spans: Vec<Span>,
68+
world_spans: Vec<WorldSpan>,
7369

7470
/// The span of each interface's definition which is used for error
7571
/// reporting during the final `Resolve` phase.
76-
interface_spans: Vec<Span>,
72+
interface_spans: Vec<InterfaceSpan>,
7773

7874
/// Spans per entry in `self.foreign_deps` for where the dependency was
7975
/// introduced to print an error message if necessary.
8076
foreign_dep_spans: Vec<Span>,
8177

82-
include_world_spans: Vec<Span>,
83-
8478
/// A list of `TypeDefKind::Unknown` types which are required to be
8579
/// resources when this package is resolved against its dependencies.
8680
required_resource_types: Vec<(TypeId, Span)>,
@@ -221,12 +215,10 @@ impl<'a> Resolver<'a> {
221215
})
222216
.collect(),
223217
unknown_type_spans: mem::take(&mut self.unknown_type_spans),
224-
world_item_spans: mem::take(&mut self.world_item_spans),
225218
interface_spans: mem::take(&mut self.interface_spans),
226219
world_spans: mem::take(&mut self.world_spans),
227220
foreign_dep_spans: mem::take(&mut self.foreign_dep_spans),
228221
source_map: SourceMap::default(),
229-
include_world_spans: mem::take(&mut self.include_world_spans),
230222
required_resource_types: mem::take(&mut self.required_resource_types),
231223
})
232224
}
@@ -258,7 +250,7 @@ impl<'a> Resolver<'a> {
258250
id.package_name(),
259251
name.name
260252
);
261-
AstItem::World(self.alloc_world(name.span, true))
253+
AstItem::World(self.alloc_world(name.span))
262254
}
263255
WorldOrInterface::Interface | WorldOrInterface::Unknown => {
264256
// Currently top-level `use` always assumes an interface, so the
@@ -289,7 +281,10 @@ impl<'a> Resolver<'a> {
289281

290282
fn alloc_interface(&mut self, span: Span) -> InterfaceId {
291283
self.interface_types.push(IndexMap::new());
292-
self.interface_spans.push(span);
284+
self.interface_spans.push(InterfaceSpan {
285+
span,
286+
funcs: Vec::new(),
287+
});
293288
self.interfaces.alloc(Interface {
294289
name: None,
295290
types: IndexMap::new(),
@@ -299,11 +294,13 @@ impl<'a> Resolver<'a> {
299294
})
300295
}
301296

302-
fn alloc_world(&mut self, span: Span, dummy_span: bool) -> WorldId {
303-
self.world_spans.push(span);
304-
if dummy_span {
305-
self.world_item_spans.push((Vec::new(), Vec::new()));
306-
}
297+
fn alloc_world(&mut self, span: Span) -> WorldId {
298+
self.world_spans.push(WorldSpan {
299+
span,
300+
imports: Vec::new(),
301+
exports: Vec::new(),
302+
includes: Vec::new(),
303+
});
307304
self.worlds.alloc(World {
308305
name: String::new(),
309306
docs: Docs::default(),
@@ -461,8 +458,7 @@ impl<'a> Resolver<'a> {
461458
iface_id_order.push(id);
462459
}
463460
ast::AstItem::World(_) => {
464-
// No dummy span needs to be created because they will be created at `resolve_world`
465-
let id = self.alloc_world(package_items[name], false);
461+
let id = self.alloc_world(package_items[name]);
466462
self.worlds[id].name = name.to_string();
467463
let prev = ids.insert(name, AstItem::World(id));
468464
assert!(prev.is_none());
@@ -585,7 +581,7 @@ impl<'a> Resolver<'a> {
585581
_ => None,
586582
});
587583
for include in items {
588-
self.resolve_include(TypeOwner::World(world_id), include)?;
584+
self.resolve_include(world_id, include)?;
589585
}
590586

591587
let mut export_spans = Vec::new();
@@ -698,7 +694,8 @@ impl<'a> Resolver<'a> {
698694
assert!(prev.is_none());
699695
spans.push(kind.span());
700696
}
701-
self.world_item_spans.push((import_spans, export_spans));
697+
self.world_spans[world_id.index()].imports = import_spans;
698+
self.world_spans[world_id.index()].exports = export_spans;
702699
self.type_lookup.clear();
703700

704701
Ok(world_id)
@@ -772,6 +769,9 @@ impl<'a> Resolver<'a> {
772769
&f.func,
773770
FunctionKind::Freestanding,
774771
)?);
772+
self.interface_spans[interface_id.index()]
773+
.funcs
774+
.push(f.name.span);
775775
}
776776
ast::InterfaceItem::Use(_) => {}
777777
ast::InterfaceItem::TypeDef(ast::TypeDef {
@@ -781,6 +781,9 @@ impl<'a> Resolver<'a> {
781781
}) => {
782782
for func in r.funcs.iter() {
783783
funcs.push(self.resolve_resource_func(func, name)?);
784+
self.interface_spans[interface_id.index()]
785+
.funcs
786+
.push(func.named_func().name.span);
784787
}
785788
}
786789
ast::InterfaceItem::TypeDef(_) => {}
@@ -900,14 +903,9 @@ impl<'a> Resolver<'a> {
900903
}
901904

902905
/// For each name in the `include`, resolve the path of the include, add it to the self.includes
903-
fn resolve_include(&mut self, owner: TypeOwner, i: &ast::Include<'a>) -> Result<()> {
906+
fn resolve_include(&mut self, world_id: WorldId, i: &ast::Include<'a>) -> Result<()> {
904907
let (item, name, span) = self.resolve_ast_item_path(&i.from)?;
905908
let include_from = self.extract_world_from_item(&item, &name, span)?;
906-
self.include_world_spans.push(span);
907-
let world_id = match owner {
908-
TypeOwner::World(id) => id,
909-
_ => unreachable!(),
910-
};
911909
self.worlds[world_id].includes.push(include_from);
912910
self.worlds[world_id].include_names.push(
913911
i.names
@@ -918,6 +916,7 @@ impl<'a> Resolver<'a> {
918916
})
919917
.collect(),
920918
);
919+
self.world_spans[world_id.index()].includes.push(span);
921920
Ok(())
922921
}
923922

crates/wit-parser/src/lib.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,15 +109,27 @@ pub struct UnresolvedPackage {
109109
pub docs: Docs,
110110

111111
unknown_type_spans: Vec<Span>,
112-
world_item_spans: Vec<(Vec<Span>, Vec<Span>)>,
113-
interface_spans: Vec<Span>,
114-
world_spans: Vec<Span>,
112+
interface_spans: Vec<InterfaceSpan>,
113+
world_spans: Vec<WorldSpan>,
115114
foreign_dep_spans: Vec<Span>,
116115
source_map: SourceMap,
117-
include_world_spans: Vec<Span>,
118116
required_resource_types: Vec<(TypeId, Span)>,
119117
}
120118

119+
#[derive(Clone)]
120+
struct WorldSpan {
121+
span: Span,
122+
imports: Vec<Span>,
123+
exports: Vec<Span>,
124+
includes: Vec<Span>,
125+
}
126+
127+
#[derive(Clone)]
128+
struct InterfaceSpan {
129+
span: Span,
130+
funcs: Vec<Span>,
131+
}
132+
121133
#[derive(Debug, Copy, Clone)]
122134
#[cfg_attr(feature = "serde", derive(Serialize))]
123135
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]

0 commit comments

Comments
 (0)