Add support for package-scope WIT types - #2607
Open
yordis wants to merge 6 commits into
Open
Conversation
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Bless CLI nominal JSON expectations for Package.types, and drop the interfaces foreign-use fixture whose parse/decode prints cannot match under inline encoding. Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
yordis
force-pushed
the
yordis/top-level-type-694
branch
from
August 18, 2026 15:37
e49b637 to
4db4f5b
Compare
Align the encoding with the approved package-scope types design in WebAssembly/component-model#699. Instead of inlining a package-scope type into every interface/world instance and re-exporting it, a package-scope type is now encoded like a `use` of an interface without the wrapping instance: the definition is restated and bound with an `eq` import named by its fully-qualified `namespace:package/name`, so nothing has to be supplied to satisfy it. The referencing interface or world aliases that import into its instance/component type. A package-scope type that depends on one from another package puts the `import` on the package's own component, since there is no wrapping component-type to hold it there. Decoding recognizes those qualified type imports as package-scope dependencies and keeps ownership with the defining package, dropping the previous inline-coalescing pass. The printer emits the corresponding top-level `use` before the definitions that reference it. This makes the encoded output valid per Component Model validation and round-trips through decode/encode. Add golden fixtures mirroring the approved WIT.md examples plus unit tests covering foreign use, foreign dependency, versioned names, the export-before-use ordering, the resource rejection, and that `component new` exports the interface directly without inventing a types interface. Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
yordis
commented
Aug 18, 2026
| types, | ||
| } | ||
| } else if !types.is_empty() { | ||
| bail!( |
Contributor
Author
There was a problem hiding this comment.
This is odd; so waiting for Luke's direction here
Previously a package containing only package-scope types (no interfaces or worlds) could be encoded but not decoded, because the package name is only recoverable from the fully-qualified export inside an interface's or world's component type and such a package has neither. Generalize the encoding for that case: each package-scope type is additionally bound with a self-referential `eq` import named by its fully-qualified `namespace:package/name`, placed right after the type's export so V2 format sniffing still sees a label as the first export. Later types reference the imported index so every import satisfies the component model's named-type validation rules. Packages that do have an interface or world encode byte-identically to before. Decoding detects a self-import by resolving its `eq` bound back to one of the package's own exported types and recovers the package name from the import, keeping foreign package-scope dependencies (whose bounds are restated definitions) on the existing path. The types-only bail is now only reachable for binaries produced before these imports existed. Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Cover the remaining matrix of package-scope types mixed with classic
`use iface.{...}` projections: same-interface use, world-level use,
resource projection use, and a foreign package-scope use alongside a
local interface projection. Each fixture encodes both the instance
import path and the package-scope `eq` type import on the same wrapping
component-type and round-trips through encode/decode/print.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds support for declaring
record,variant,enum,flags, andtypealiases directly at package scope in WIT, and encodes/decodes them following the
approved design in WebAssembly/component-model#699.
A package-scope type is encoded like a
useof aninterface, just without thewrapping
instance: the definition is restated locally and bound with aneqimport named by its fully-qualified
namespace:package/name. Because the typeis structural, the
eqbound means nothing has to be supplied to satisfy theimport. A referencing
interfaceorworldaliases that import into itsinstance/component type; a
worldplaces the import inside its inner exportedcomponent-type.
This replaces the earlier approach of inlining a package-scope type into every
interface/world instance and re-exporting it, which did not pass Component Model
validation.
Encoding
Given:
the package-scope
pointis exported once at the top level and imported witheqinto the wrapping component-type:A package-scope type that depends on one from another package puts the
importon the package's own component, since there is no wrapping component-type to
hold it. Decoding recognizes qualified type imports (both nested and at the
package root) as package-scope dependencies and keeps ownership with the
defining package; the previous inline-coalescing pass in the decoder is removed.
The printer emits the corresponding top-level
usebefore the definitions thatreference it.
Types-only packages
Decoding recovers the package name from the fully-qualified export inside an
interface's or world's component type, so a package with only package-scope
types would otherwise have no package name in the binary at all. For that case
the encoding is generalized (as discussed with Luke): each type is additionally
bound with a self-referential
eqimport named by its fully-qualified name,which is where the package name is recovered from on decode:
Later types reference the imported index so every import satisfies the
component model's named-type validation rules, and the import is placed after
the export so V2 format sniffing still sees a label first. Packages that do
have an interface or world encode byte-identically to the approved WIT.md
examples; the self-imports may be worth a small follow-up note in the spec's
Package Format section.
Tests
(
package-scope-spec-interface,package-scope-spec-world), a types-onlyfixture (
package-scope-types-only), plus the existing package-scopefixtures re-blessed to the
eq-import encoding. All round-trip throughencode → validate → decode → print → re-encode.
use iface.{...}projections on the same wrapping component-type:package-scope-with-iface-use,package-scope-with-world-use,package-scope-with-resource-use, andpackage-scope-mixed-use(foreignpackage-scope
useplus a local interface projection).useof a package-scope type, a package-scopetype defined in terms of a foreign one (import on the package component),
versioned fully-qualified names, the export-before-use ordering for a type
referring to another, types-only round-trips (with and without a foreign
dependency), rejection of a
resourceat package scope, and that building acomponent (
component new) exports the interface directly without inventinga types interface (WIT: allow type declarations at package scope WebAssembly/component-model#694).
References