Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 49 additions & 5 deletions crates/wit-parser/src/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3174,11 +3174,55 @@ impl Remap {

let pkg = &resolve.packages[pkgid];
let span = &unresolved.interface_spans[unresolved_iface_id.index()];
let iface_id = pkg
.interfaces
.get(interface)
.copied()
.ok_or_else(|| Error::new(span.span, "interface not found in package"))?;

// This closure examines the unresolved worlds' imports and exports and returns true
// if all of the references to unresolved_iface_id are disabled by feature gating.
// If any enabled references exist, or no references (gated or otherwise) exist, return false.
let is_gated = |resolve: &Resolve| -> Result<bool> {
let mut found_gated_ref = false;

// Search for unresolved_iface_id in the set of all unresolved worlds' imports and exports
for (_, world) in &unresolved.worlds {
let world_is_enabled =
resolve.include_stability(&world.stability, &pkgid, None)?;

for (_, item) in world.imports.iter().chain(world.exports.iter()) {
if let WorldItem::Interface { id, stability } = item {
// Found unresolved_iface_id within the set of worlds' imports and exports
if *id == unresolved_iface_id {
let item_is_enabled =
resolve.include_stability(stability, &pkgid, None)?;

// A reference to unresolved_iface_id exists, and it is not disabled by feature-gating, so return Ok(false)
if world_is_enabled && item_is_enabled {
return Ok(false);
}

found_gated_ref = true;
}
}
}
}

Ok(found_gated_ref)
};

let iface_id = match pkg.interfaces.get(interface) {
Some(id) => *id,
None => {
if is_gated(resolve)? {
// The interface's references are disabled by feature-gating so use
// 'None' as a placeholder as this reference will not be used
assert_eq!(self.interfaces.len(), unresolved_iface_id.index());
self.interfaces.push(None);
continue;
} else {
// Enabled references to the absent interface must be present, so fail
bail!(Error::new(span.span, "interface not found in package"));
}
}
};

assert_eq!(self.interfaces.len(), unresolved_iface_id.index());
self.interfaces.push(Some(iface_id));
}
Expand Down
17 changes: 17 additions & 0 deletions crates/wit-parser/tests/ui/foreign-deps-gated.wit
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package a:b1;

world the-world {
include a:b2/the-world;
}

package a:b2 {
world the-world {
@unstable(feature = disabled)
import a:b3/thing;
}
}

package a:b3 {
@unstable(feature = disabled)
interface thing {}
}
39 changes: 39 additions & 0 deletions crates/wit-parser/tests/ui/foreign-deps-gated.wit.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"worlds": [
{
"name": "the-world",
"imports": {},
"exports": {},
"package": 1
},
{
"name": "the-world",
"imports": {},
"exports": {},
"package": 2
}
],
"interfaces": [],
"types": [],
"packages": [
{
"name": "a:b3",
"interfaces": {},
"worlds": {}
},
{
"name": "a:b2",
"interfaces": {},
"worlds": {
"the-world": 0
}
},
{
"name": "a:b1",
"interfaces": {},
"worlds": {
"the-world": 1
}
}
]
}