diff --git a/crates/wit-parser/src/lib.rs b/crates/wit-parser/src/lib.rs index 5f8aa6c9f4..5c23108be7 100644 --- a/crates/wit-parser/src/lib.rs +++ b/crates/wit-parser/src/lib.rs @@ -1243,6 +1243,10 @@ impl Stability { pub fn is_unknown(&self) -> bool { matches!(self, Stability::Unknown) } + + pub fn is_stable(&self) -> bool { + matches!(self, Stability::Stable { .. }) + } } impl Default for Stability { diff --git a/crates/wit-parser/src/resolve.rs b/crates/wit-parser/src/resolve.rs index a4ff8a155a..b47dfba324 100644 --- a/crates/wit-parser/src/resolve.rs +++ b/crates/wit-parser/src/resolve.rs @@ -3448,6 +3448,7 @@ impl Remap { let include_world_id = self.map_world(include_world, Some(span))?; let include_world = &resolve.worlds[include_world_id]; let mut names_ = names.to_owned(); + let is_external_include = world.package != include_world.package; // remove all imports and exports that match the names we're including for import in include_world.imports.iter() { @@ -3465,11 +3466,25 @@ impl Remap { // copy the imports and exports from the included world into the current world for import in include_world.imports.iter() { - self.resolve_include_item(names, &mut world.imports, import, span, "import")?; + self.resolve_include_item( + names, + &mut world.imports, + import, + span, + "import", + is_external_include, + )?; } for export in include_world.exports.iter() { - self.resolve_include_item(names, &mut world.exports, export, span, "export")?; + self.resolve_include_item( + names, + &mut world.exports, + export, + span, + "export", + is_external_include, + )?; } Ok(()) } @@ -3481,6 +3496,7 @@ impl Remap { item: (&WorldKey, &WorldItem), span: Span, item_type: &str, + is_external_include: bool, ) -> Result<()> { match item.0 { WorldKey::Name(n) => { @@ -3515,7 +3531,7 @@ impl Remap { }, ) => { assert_eq!(*aid, *bid); - merge_stability(astability, bstability)?; + merge_include_stability(astability, bstability, is_external_include)?; } (WorldItem::Interface { .. }, _) => unreachable!(), (WorldItem::Function(_), _) => unreachable!(), @@ -3948,25 +3964,18 @@ fn update_stability(from: &Stability, into: &mut Stability) -> Result<()> { bail!("mismatch in stability from '{:?}' to '{:?}'", from, into) } -/// Compares the two attributes and if the `from` is more stable than the `into` then -/// it will elevate the `into` to the same stability. -/// This should be used after its already been confirmed that the types are the same and -/// should be apart of the component because versions/features are enabled. -fn merge_stability(from: &Stability, into: &mut Stability) -> Result<()> { - // If the two stability annotations are equal then - // there's nothing to do here. - if from == into { - return Ok(()); - } - - // if the from is more stable elevate stability of into - if from > into { - *into = from.clone(); +fn merge_include_stability( + from: &Stability, + into: &mut Stability, + is_external_include: bool, +) -> Result<()> { + if is_external_include && from.is_stable() { + log::trace!("dropped stability from external package"); + *into = Stability::Unknown; return Ok(()); } - // otherwise `into`` already has higher stability - return Ok(()); + return update_stability(from, into); } /// An error that can be returned during "world elaboration" during various diff --git a/crates/wit-parser/tests/ui/gated-include.wit b/crates/wit-parser/tests/ui/gated-include.wit new file mode 100644 index 0000000000..74df394572 --- /dev/null +++ b/crates/wit-parser/tests/ui/gated-include.wit @@ -0,0 +1,67 @@ +package wasmtime:test@0.1.0; + +interface unknown-stability-interface { + resource unknown-stability-resource { + } + stable-func: func(); +} + +@unstable(feature = active) +interface unstable-interface { + @unstable(feature = active) + resource unstable-resource { + } + @unstable(feature = active) + unstable-func: func(); +} + +@since(version = 0.1.0) +interface stable-interface { + @since(version = 0.1.0) + resource stable-resource { + } + @since(version = 0.1.0) + stable-func: func(); +} + +world unknown-stability { + import unknown-stability-interface; +} + +world unstable { + @unstable(feature = active) + import unstable-interface; +} + +world stable{ + @since(version = 0.1.0) + import stable-interface; +} + +world simple-include { + include unstable; + include stable; + include unknown-stability; +} + +world unstable-include-in-package +{ + include unstable; +} + +world dup-include-in-package { + include simple-include; + include unstable-include-in-package; +} + +world dup-use-package { + @unstable(feature = active) + use stable-interface.{stable-resource}; + include simple-include; +} + +world dup-use-package-ordered { + include simple-include; + @unstable(feature = active) + use stable-interface.{stable-resource}; +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/gated-include.wit.json b/crates/wit-parser/tests/ui/gated-include.wit.json new file mode 100644 index 0000000000..5f00420fe1 --- /dev/null +++ b/crates/wit-parser/tests/ui/gated-include.wit.json @@ -0,0 +1,346 @@ +{ + "worlds": [ + { + "name": "unknown-stability", + "imports": { + "interface-0": { + "interface": { + "id": 0 + } + } + }, + "exports": {}, + "package": 0 + }, + { + "name": "unstable", + "imports": { + "interface-1": { + "interface": { + "id": 1, + "stability": { + "unstable": { + "feature": "active" + } + } + } + } + }, + "exports": {}, + "package": 0 + }, + { + "name": "stable", + "imports": { + "interface-2": { + "interface": { + "id": 2, + "stability": { + "stable": { + "since": "0.1.0" + } + } + } + } + }, + "exports": {}, + "package": 0 + }, + { + "name": "simple-include", + "imports": { + "interface-1": { + "interface": { + "id": 1, + "stability": { + "unstable": { + "feature": "active" + } + } + } + }, + "interface-2": { + "interface": { + "id": 2, + "stability": { + "stable": { + "since": "0.1.0" + } + } + } + }, + "interface-0": { + "interface": { + "id": 0 + } + } + }, + "exports": {}, + "package": 0 + }, + { + "name": "unstable-include-in-package", + "imports": { + "interface-1": { + "interface": { + "id": 1, + "stability": { + "unstable": { + "feature": "active" + } + } + } + } + }, + "exports": {}, + "package": 0 + }, + { + "name": "dup-include-in-package", + "imports": { + "interface-1": { + "interface": { + "id": 1, + "stability": { + "unstable": { + "feature": "active" + } + } + } + }, + "interface-2": { + "interface": { + "id": 2, + "stability": { + "stable": { + "since": "0.1.0" + } + } + } + }, + "interface-0": { + "interface": { + "id": 0 + } + } + }, + "exports": {}, + "package": 0 + }, + { + "name": "dup-use-package", + "imports": { + "interface-1": { + "interface": { + "id": 1, + "stability": { + "unstable": { + "feature": "active" + } + } + } + }, + "interface-2": { + "interface": { + "id": 2, + "stability": { + "stable": { + "since": "0.1.0" + } + } + } + }, + "interface-0": { + "interface": { + "id": 0 + } + }, + "stable-resource": { + "type": 3 + } + }, + "exports": {}, + "package": 0 + }, + { + "name": "dup-use-package-ordered", + "imports": { + "interface-1": { + "interface": { + "id": 1, + "stability": { + "unstable": { + "feature": "active" + } + } + } + }, + "interface-2": { + "interface": { + "id": 2, + "stability": { + "stable": { + "since": "0.1.0" + } + } + } + }, + "interface-0": { + "interface": { + "id": 0 + } + }, + "stable-resource": { + "type": 4 + } + }, + "exports": {}, + "package": 0 + } + ], + "interfaces": [ + { + "name": "unknown-stability-interface", + "types": { + "unknown-stability-resource": 0 + }, + "functions": { + "stable-func": { + "name": "stable-func", + "kind": "freestanding", + "params": [] + } + }, + "package": 0 + }, + { + "name": "unstable-interface", + "types": { + "unstable-resource": 1 + }, + "functions": { + "unstable-func": { + "name": "unstable-func", + "kind": "freestanding", + "params": [], + "stability": { + "unstable": { + "feature": "active" + } + } + } + }, + "stability": { + "unstable": { + "feature": "active" + } + }, + "package": 0 + }, + { + "name": "stable-interface", + "types": { + "stable-resource": 2 + }, + "functions": { + "stable-func": { + "name": "stable-func", + "kind": "freestanding", + "params": [], + "stability": { + "stable": { + "since": "0.1.0" + } + } + } + }, + "stability": { + "stable": { + "since": "0.1.0" + } + }, + "package": 0 + } + ], + "types": [ + { + "name": "unknown-stability-resource", + "kind": "resource", + "owner": { + "interface": 0 + } + }, + { + "name": "unstable-resource", + "kind": "resource", + "owner": { + "interface": 1 + }, + "stability": { + "unstable": { + "feature": "active" + } + } + }, + { + "name": "stable-resource", + "kind": "resource", + "owner": { + "interface": 2 + }, + "stability": { + "stable": { + "since": "0.1.0" + } + } + }, + { + "name": "stable-resource", + "kind": { + "type": 2 + }, + "owner": { + "world": 6 + }, + "stability": { + "unstable": { + "feature": "active" + } + } + }, + { + "name": "stable-resource", + "kind": { + "type": 2 + }, + "owner": { + "world": 7 + }, + "stability": { + "unstable": { + "feature": "active" + } + } + } + ], + "packages": [ + { + "name": "wasmtime:test@0.1.0", + "interfaces": { + "unknown-stability-interface": 0, + "unstable-interface": 1, + "stable-interface": 2 + }, + "worlds": { + "unknown-stability": 0, + "unstable": 1, + "stable": 2, + "simple-include": 3, + "unstable-include-in-package": 4, + "dup-include-in-package": 5, + "dup-use-package": 6, + "dup-use-package-ordered": 7 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/gated-include-use-with-stable.wit b/crates/wit-parser/tests/ui/multi-package-gated-include.wit similarity index 63% rename from crates/wit-parser/tests/ui/gated-include-use-with-stable.wit rename to crates/wit-parser/tests/ui/multi-package-gated-include.wit index 159ffb3987..2dd3ff4178 100644 --- a/crates/wit-parser/tests/ui/gated-include-use-with-stable.wit +++ b/crates/wit-parser/tests/ui/multi-package-gated-include.wit @@ -4,13 +4,36 @@ world test{ @unstable(feature = active) include wasi:unstable/imports@0.2.3; include wasi:foo/imports@0.2.3; -} + include wasi:someother/imports@0.2.3; +} -world test-ordered{ +world test-ordered { + include wasi:someother/imports@0.2.3; include wasi:foo/imports@0.2.3; @unstable(feature = active) include wasi:unstable/imports@0.2.3; -} +} + +world test-no-stability { + include wasi:someother/imports@0.2.3; + include wasi:foo/imports@0.2.3; + include wasi:unstable/imports@0.2.3; +} + +world test-only-stable { + include wasi:foo/imports@0.2.3; +} + +world test-only-stable-with-feature { + @unstable(feature = active) + include wasi:foo/imports@0.2.3; +} + +// in test this results in world with nothing +world test-only-stable-with-in-active-feature { + @unstable(feature = in-active) + include wasi:foo/imports@0.2.3; +} package wasi:unstable@0.2.3 { @unstable(feature = active) @@ -24,6 +47,22 @@ package wasi:unstable@0.2.3 { } } +package wasi:someother@0.2.3 { + @since(version = 0.2.0) + world imports { + import someother; + } + + @since(version = 0.2.0) + interface someother { + @since(version = 0.2.0) + resource someother-resource { + } + } +} + + + package wasi:foo@0.2.3 { @since(version = 0.2.0) world imports { @@ -40,7 +79,7 @@ package wasi:dep2@0.2.3 { @since(version = 0.2.0) import stable; } - @since(version = 0.2.1) + @since(version = 0.2.0) interface stable { resource stable-resource { } diff --git a/crates/wit-parser/tests/ui/gated-include-use-with-stable.wit.json b/crates/wit-parser/tests/ui/multi-package-gated-include.wit.json similarity index 64% rename from crates/wit-parser/tests/ui/gated-include-use-with-stable.wit.json rename to crates/wit-parser/tests/ui/multi-package-gated-include.wit.json index b7f857b1ad..fc9171853b 100644 --- a/crates/wit-parser/tests/ui/gated-include-use-with-stable.wit.json +++ b/crates/wit-parser/tests/ui/multi-package-gated-include.wit.json @@ -61,12 +61,7 @@ "imports": { "interface-2": { "interface": { - "id": 2, - "stability": { - "stable": { - "since": "0.2.0" - } - } + "id": 2 } }, "interface-1": { @@ -93,6 +88,23 @@ } } }, + { + "name": "imports", + "imports": { + "interface-3": { + "interface": { + "id": 3 + } + } + }, + "exports": {}, + "package": 4, + "stability": { + "stable": { + "since": "0.2.0" + } + } + }, { "name": "imports", "imports": { @@ -127,17 +139,17 @@ } }, "stable-resource": { - "type": 3 + "type": 4 }, "unversioned-resource": { - "type": 4 + "type": 5 }, "unstable-resource": { - "type": 5 + "type": 6 } }, "exports": {}, - "package": 4, + "package": 5, "stability": { "unstable": { "feature": "active" @@ -151,8 +163,8 @@ "interface": { "id": 2, "stability": { - "stable": { - "since": "0.2.0" + "unstable": { + "feature": "active" } } } @@ -177,28 +189,38 @@ } } }, + "interface-3": { + "interface": { + "id": 3 + } + }, "stable-resource": { - "type": 3 + "type": 4 }, "unversioned-resource": { - "type": 4 + "type": 5 }, "unstable-resource": { - "type": 5 + "type": 6 } }, "exports": {}, - "package": 5 + "package": 6 }, { "name": "test-ordered", "imports": { + "interface-3": { + "interface": { + "id": 3 + } + }, "interface-2": { "interface": { "id": 2, "stability": { - "stable": { - "since": "0.2.0" + "unstable": { + "feature": "active" } } } @@ -224,17 +246,131 @@ } }, "stable-resource": { - "type": 3 + "type": 4 }, "unversioned-resource": { - "type": 4 + "type": 5 }, "unstable-resource": { + "type": 6 + } + }, + "exports": {}, + "package": 6 + }, + { + "name": "test-no-stability", + "imports": { + "interface-3": { + "interface": { + "id": 3 + } + }, + "interface-2": { + "interface": { + "id": 2, + "stability": { + "unstable": { + "feature": "active" + } + } + } + }, + "interface-1": { + "interface": { + "id": 1, + "stability": { + "unstable": { + "feature": "active" + } + } + } + }, + "interface-0": { + "interface": { + "id": 0, + "stability": { + "unstable": { + "feature": "active" + } + } + } + }, + "stable-resource": { + "type": 4 + }, + "unversioned-resource": { "type": 5 + }, + "unstable-resource": { + "type": 6 + } + }, + "exports": {}, + "package": 6 + }, + { + "name": "test-only-stable", + "imports": { + "interface-2": { + "interface": { + "id": 2 + } + }, + "interface-1": { + "interface": { + "id": 1 + } + }, + "interface-0": { + "interface": { + "id": 0, + "stability": { + "unstable": { + "feature": "active" + } + } + } + } + }, + "exports": {}, + "package": 6 + }, + { + "name": "test-only-stable-with-feature", + "imports": { + "interface-2": { + "interface": { + "id": 2 + } + }, + "interface-1": { + "interface": { + "id": 1 + } + }, + "interface-0": { + "interface": { + "id": 0, + "stability": { + "unstable": { + "feature": "active" + } + } + } } }, "exports": {}, - "package": 5 + "package": 6 + }, + { + "name": "test-only-stable-with-in-active-feature", + "imports": {}, + "exports": {}, + "package": 6, + "docs": { + "contents": "in test this results in world with nothing" + } } ], "interfaces": [ @@ -267,10 +403,23 @@ "functions": {}, "stability": { "stable": { - "since": "0.2.1" + "since": "0.2.0" } }, "package": 2 + }, + { + "name": "someother", + "types": { + "someother-resource": 3 + }, + "functions": {}, + "stability": { + "stable": { + "since": "0.2.0" + } + }, + "package": 4 } ], "types": [ @@ -300,13 +449,25 @@ "interface": 2 } }, + { + "name": "someother-resource", + "kind": "resource", + "owner": { + "interface": 3 + }, + "stability": { + "stable": { + "since": "0.2.0" + } + } + }, { "name": "stable-resource", "kind": { "type": 2 }, "owner": { - "world": 4 + "world": 5 }, "stability": { "unstable": { @@ -320,7 +481,7 @@ "type": 1 }, "owner": { - "world": 4 + "world": 5 }, "stability": { "unstable": { @@ -334,7 +495,7 @@ "type": 0 }, "owner": { - "world": 4 + "world": 5 }, "stability": { "unstable": { @@ -378,19 +539,32 @@ "imports": 3 } }, + { + "name": "wasi:someother@0.2.3", + "interfaces": { + "someother": 3 + }, + "worlds": { + "imports": 4 + } + }, { "name": "wasi:unstable@0.2.3", "interfaces": {}, "worlds": { - "imports": 4 + "imports": 5 } }, { "name": "wasmtime:test", "interfaces": {}, "worlds": { - "test": 5, - "test-ordered": 6 + "test": 6, + "test-ordered": 7, + "test-no-stability": 8, + "test-only-stable": 9, + "test-only-stable-with-feature": 10, + "test-only-stable-with-in-active-feature": 11 } } ]