Skip to content

Commit eabdf0e

Browse files
authored
Fix handling stability of use of "foreign" types (#2046)
This commit addresses an issue where stability attributes on a `use` didn't quite work as expected when a type to another package was referred to. This fix was to update the "merging" process to skip types being processed in one more location which involved threading some more contexts around. Additionally `use` items, when elaborated, now contain their stability instead of the default stability to ensure that's propagated correctly as well. cc #1995 but doesn't fix it
1 parent 823efcb commit eabdf0e

File tree

7 files changed

+141
-52
lines changed

7 files changed

+141
-52
lines changed

crates/wit-parser/src/ast.rs

Lines changed: 53 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ impl<'a> DeclList<'a> {
142142
&'b self,
143143
f: &mut dyn FnMut(
144144
Option<&'b Id<'a>>,
145+
&'b [Attribute<'a>],
145146
&'b UsePath<'a>,
146147
Option<&'b [UseName<'a>]>,
147148
WorldOrInterface,
@@ -158,49 +159,66 @@ impl<'a> DeclList<'a> {
158159
let mut exports = Vec::new();
159160
for item in world.items.iter() {
160161
match item {
161-
WorldItem::Use(u) => {
162-
f(None, &u.from, Some(&u.names), WorldOrInterface::Interface)?
163-
}
164-
WorldItem::Include(i) => {
165-
f(Some(&world.name), &i.from, None, WorldOrInterface::World)?
166-
}
162+
WorldItem::Use(u) => f(
163+
None,
164+
&u.attributes,
165+
&u.from,
166+
Some(&u.names),
167+
WorldOrInterface::Interface,
168+
)?,
169+
WorldItem::Include(i) => f(
170+
Some(&world.name),
171+
&i.attributes,
172+
&i.from,
173+
None,
174+
WorldOrInterface::World,
175+
)?,
167176
WorldItem::Type(_) => {}
168-
WorldItem::Import(Import { kind, .. }) => imports.push(kind),
169-
WorldItem::Export(Export { kind, .. }) => exports.push(kind),
177+
WorldItem::Import(Import {
178+
kind, attributes, ..
179+
}) => imports.push((kind, attributes)),
180+
WorldItem::Export(Export {
181+
kind, attributes, ..
182+
}) => exports.push((kind, attributes)),
170183
}
171184
}
172185

173-
let mut visit_kind = |kind: &'b ExternKind<'a>| match kind {
174-
ExternKind::Interface(_, items) => {
175-
for item in items {
176-
match item {
177-
InterfaceItem::Use(u) => f(
178-
None,
179-
&u.from,
180-
Some(&u.names),
181-
WorldOrInterface::Interface,
182-
)?,
183-
_ => {}
186+
let mut visit_kind =
187+
|kind: &'b ExternKind<'a>, attrs: &'b [Attribute<'a>]| match kind {
188+
ExternKind::Interface(_, items) => {
189+
for item in items {
190+
match item {
191+
InterfaceItem::Use(u) => f(
192+
None,
193+
&u.attributes,
194+
&u.from,
195+
Some(&u.names),
196+
WorldOrInterface::Interface,
197+
)?,
198+
_ => {}
199+
}
184200
}
201+
Ok(())
185202
}
186-
Ok(())
187-
}
188-
ExternKind::Path(path) => f(None, path, None, WorldOrInterface::Interface),
189-
ExternKind::Func(..) => Ok(()),
190-
};
203+
ExternKind::Path(path) => {
204+
f(None, attrs, path, None, WorldOrInterface::Interface)
205+
}
206+
ExternKind::Func(..) => Ok(()),
207+
};
191208

192-
for kind in imports {
193-
visit_kind(kind)?;
209+
for (kind, attrs) in imports {
210+
visit_kind(kind, attrs)?;
194211
}
195-
for kind in exports {
196-
visit_kind(kind)?;
212+
for (kind, attrs) in exports {
213+
visit_kind(kind, attrs)?;
197214
}
198215
}
199216
AstItem::Interface(i) => {
200217
for item in i.items.iter() {
201218
match item {
202219
InterfaceItem::Use(u) => f(
203220
Some(&i.name),
221+
&u.attributes,
204222
&u.from,
205223
Some(&u.names),
206224
WorldOrInterface::Interface,
@@ -212,7 +230,13 @@ impl<'a> DeclList<'a> {
212230
AstItem::Use(u) => {
213231
// At the top-level, we don't know if this is a world or an interface
214232
// It is up to the resolver to decides how to handle this ambiguity.
215-
f(None, &u.item, None, WorldOrInterface::Unknown)?;
233+
f(
234+
None,
235+
&u.attributes,
236+
&u.item,
237+
None,
238+
WorldOrInterface::Unknown,
239+
)?;
216240
}
217241

218242
AstItem::Package(pkg) => pkg.decl_list.for_each_path(f)?,

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ impl<'a> Resolver<'a> {
257257
let mut foreign_worlds = mem::take(&mut self.foreign_worlds);
258258
for decl_list in decl_lists {
259259
decl_list
260-
.for_each_path(&mut |_, path, _names, world_or_iface| {
260+
.for_each_path(&mut |_, _attrs, path, _names, world_or_iface| {
261261
let (id, name) = match path {
262262
ast::UsePath::Package { id, name } => (id, name),
263263
_ => return Ok(()),
@@ -433,7 +433,7 @@ impl<'a> Resolver<'a> {
433433

434434
// With this file's namespace information look at all `use` paths
435435
// and record dependencies between interfaces.
436-
decl_list.for_each_path(&mut |iface, path, _names, _| {
436+
decl_list.for_each_path(&mut |iface, _attrs, path, _names, _| {
437437
// If this import isn't contained within an interface then it's
438438
// in a world and it doesn't need to participate in our
439439
// topo-sort.
@@ -561,11 +561,12 @@ impl<'a> Resolver<'a> {
561561
fn populate_foreign_types(&mut self, decl_lists: &[ast::DeclList<'a>]) -> Result<()> {
562562
for (i, decl_list) in decl_lists.iter().enumerate() {
563563
self.cur_ast_index = i;
564-
decl_list.for_each_path(&mut |_, path, names, _| {
564+
decl_list.for_each_path(&mut |_, attrs, path, names, _| {
565565
let names = match names {
566566
Some(names) => names,
567567
None => return Ok(()),
568568
};
569+
let stability = self.stability(attrs)?;
569570
let (item, name, span) = self.resolve_ast_item_path(path)?;
570571
let iface = self.extract_iface_from_item(&item, &name, span)?;
571572
if !self.foreign_interfaces.contains(&iface) {
@@ -582,7 +583,7 @@ impl<'a> Resolver<'a> {
582583
}
583584
let id = self.types.alloc(TypeDef {
584585
docs: Docs::default(),
585-
stability: Default::default(),
586+
stability: stability.clone(),
586587
kind: TypeDefKind::Unknown,
587588
name: Some(name.name.name.to_string()),
588589
owner: TypeOwner::Interface(iface),

crates/wit-parser/src/resolve.rs

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1848,6 +1848,19 @@ package {name} is defined in two different locations:\n\
18481848
})
18491849
}
18501850

1851+
/// Convenience wrapper around `include_stability` specialized for types
1852+
/// with a more targeted error message.
1853+
fn include_type(&self, ty: &TypeDef, pkgid: PackageId, span: Span) -> Result<bool> {
1854+
self.include_stability(&ty.stability, &pkgid, Some(span))
1855+
.with_context(|| {
1856+
format!(
1857+
"failed to process feature gate for type [{}] in package [{}]",
1858+
ty.name.as_ref().map(String::as_str).unwrap_or("<unknown>"),
1859+
self.packages[pkgid].name,
1860+
)
1861+
})
1862+
}
1863+
18511864
/// Performs the "elaboration process" necessary for the `world_id`
18521865
/// specified to ensure that all of its transitive imports are listed.
18531866
///
@@ -2625,12 +2638,6 @@ impl Remap {
26252638
resolve: &mut Resolve,
26262639
unresolved: UnresolvedPackage,
26272640
) -> Result<PackageId> {
2628-
self.process_foreign_deps(resolve, &unresolved)?;
2629-
2630-
let foreign_types = self.types.len();
2631-
let foreign_interfaces = self.interfaces.len();
2632-
let foreign_worlds = self.worlds.len();
2633-
26342641
let pkgid = resolve.packages.alloc(Package {
26352642
name: unresolved.name.clone(),
26362643
docs: unresolved.docs.clone(),
@@ -2640,6 +2647,12 @@ impl Remap {
26402647
let prev = resolve.package_names.insert(unresolved.name.clone(), pkgid);
26412648
assert!(prev.is_none());
26422649

2650+
self.process_foreign_deps(resolve, pkgid, &unresolved)?;
2651+
2652+
let foreign_types = self.types.len();
2653+
let foreign_interfaces = self.interfaces.len();
2654+
let foreign_worlds = self.worlds.len();
2655+
26432656
// Copy over all types first, updating any intra-type references. Note
26442657
// that types are sorted topologically which means this iteration
26452658
// order should be sufficient. Also note though that the interface
@@ -2652,16 +2665,7 @@ impl Remap {
26522665
.zip(&unresolved.type_spans)
26532666
.skip(foreign_types)
26542667
{
2655-
if !resolve
2656-
.include_stability(&ty.stability, &pkgid, Some(*span))
2657-
.with_context(|| {
2658-
format!(
2659-
"failed to process feature gate for type [{}] in package [{}]",
2660-
ty.name.as_ref().map(String::as_str).unwrap_or("<unknown>"),
2661-
resolve.packages[pkgid].name,
2662-
)
2663-
})?
2664-
{
2668+
if !resolve.include_type(&ty, pkgid, *span)? {
26652669
self.types.push(None);
26662670
continue;
26672671
}
@@ -2838,6 +2842,7 @@ impl Remap {
28382842
fn process_foreign_deps(
28392843
&mut self,
28402844
resolve: &mut Resolve,
2845+
pkgid: PackageId,
28412846
unresolved: &UnresolvedPackage,
28422847
) -> Result<()> {
28432848
// Invert the `foreign_deps` map to be keyed by world id to get
@@ -2877,7 +2882,7 @@ impl Remap {
28772882

28782883
// Finally, iterate over all foreign-defined types and determine
28792884
// what they map to.
2880-
self.process_foreign_types(unresolved, resolve)?;
2885+
self.process_foreign_types(unresolved, pkgid, resolve)?;
28812886

28822887
for (id, span) in unresolved.required_resource_types.iter() {
28832888
let mut id = self.map_type(*id, Some(*span))?;
@@ -2988,16 +2993,25 @@ impl Remap {
29882993
fn process_foreign_types(
29892994
&mut self,
29902995
unresolved: &UnresolvedPackage,
2996+
pkgid: PackageId,
29912997
resolve: &mut Resolve,
29922998
) -> Result<(), anyhow::Error> {
2993-
for (unresolved_type_id, unresolved_ty) in unresolved.types.iter() {
2999+
for ((unresolved_type_id, unresolved_ty), span) in
3000+
unresolved.types.iter().zip(&unresolved.type_spans)
3001+
{
29943002
// All "Unknown" types should appear first so once we're no longer
29953003
// in unknown territory it's package-defined types so break out of
29963004
// this loop.
29973005
match unresolved_ty.kind {
29983006
TypeDefKind::Unknown => {}
29993007
_ => break,
30003008
}
3009+
3010+
if !resolve.include_type(unresolved_ty, pkgid, *span)? {
3011+
self.types.push(None);
3012+
continue;
3013+
}
3014+
30013015
let unresolved_iface_id = match unresolved_ty.owner {
30023016
TypeOwner::Interface(id) => id,
30033017
_ => unreachable!(),
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package wasmtime:test;
2+
3+
interface types {
4+
@unstable(feature = inactive)
5+
use wasi:dep2/stable@0.2.3.{unstable-resource};
6+
}
7+
8+
package wasi:dep2@0.2.3 {
9+
interface stable {
10+
@unstable(feature = inactive)
11+
resource unstable-resource;
12+
}
13+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"worlds": [],
3+
"interfaces": [
4+
{
5+
"name": "stable",
6+
"types": {},
7+
"functions": {},
8+
"package": 0
9+
},
10+
{
11+
"name": "types",
12+
"types": {},
13+
"functions": {},
14+
"package": 1
15+
}
16+
],
17+
"types": [],
18+
"packages": [
19+
{
20+
"name": "wasi:[email protected]",
21+
"interfaces": {
22+
"stable": 0
23+
},
24+
"worlds": {}
25+
},
26+
{
27+
"name": "wasmtime:test",
28+
"interfaces": {
29+
"types": 1
30+
},
31+
"worlds": {}
32+
}
33+
]
34+
}

crates/wit-parser/tests/ui/parse-fail/bad-pkg6.wit.result

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/bad-pkg6]: package 'foo:bar' not found. known packages:
22
foo:baz
3+
foo:foo
34

45
--> tests/ui/parse-fail/bad-pkg6/root.wit:3:7
56
|

crates/wit-parser/tests/ui/parse-fail/unresolved-interface4.wit.result

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
package 'some:dependency' not found. no known packages.
1+
package 'some:dependency' not found. known packages:
2+
foo:foo
3+
24
--> tests/ui/parse-fail/unresolved-interface4.wit:6:10
35
|
46
6 | import some:dependency/iface;

0 commit comments

Comments
 (0)