-
Notifications
You must be signed in to change notification settings - Fork 111
Add [implements=<I>]L plainname for multiple imports #613
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,7 +25,7 @@ document, a pseudo-formal [grammar specification][lexical-structure], and | |
| additionally a specification of the [package format][package-format] of a WIT | ||
| package suitable for distribution. | ||
|
|
||
| See [Gated Features] for an explanation of 🔧. | ||
| See [Gated Features] for an explanation of 🔧 and 🏷️. | ||
|
|
||
| [IDL]: https://en.wikipedia.org/wiki/Interface_description_language | ||
| [components]: https://github.com/webassembly/component-model | ||
|
|
@@ -366,6 +366,55 @@ world union-my-world-b { | |
| } | ||
| ``` | ||
|
|
||
| 🏷️ When a world being included contains plain-named imports or exports that | ||
| reference a named interface (using the `id: use-path` syntax), the `with` | ||
| keyword renames the plain-name label while preserving the underlying | ||
| `[implements=<I>]` annotation in the encoding. For example: | ||
|
|
||
| ```wit | ||
| package local:demo; | ||
|
|
||
| interface store { | ||
| get: func(key: string) -> option<string>; | ||
| } | ||
|
|
||
| world base { | ||
| import cache: store; | ||
| } | ||
|
|
||
| world extended { | ||
| include base with { cache as my-cache } | ||
| } | ||
| ``` | ||
|
|
||
| In this case, `extended` has a single import with the plain name `my-cache` | ||
| that implements `local:demo/store`, equivalent to writing | ||
| `import my-cache: store;` directly. | ||
|
|
||
| Unlike interface names (which are automatically de-duplicated when two | ||
| `include`s import the same interface), plain names cannot be de-duplicated | ||
| and will conflict. For example: | ||
|
|
||
| ```wit | ||
| world base-a { | ||
| import cache: store; | ||
| } | ||
|
|
||
| world base-b { | ||
| import cache: store; | ||
| } | ||
|
|
||
| world conflict { | ||
| include base-a; | ||
| include base-b; // error: plain name 'cache' conflicts | ||
| } | ||
|
|
||
| world resolved { | ||
| include base-a; | ||
| include base-b with { cache as other-cache } // ok: renamed to avoid conflict | ||
| } | ||
| ``` | ||
|
|
||
| `with` cannot be used to rename interface names, however, so the following | ||
| world would be invalid: | ||
| ```wit | ||
|
|
@@ -1381,9 +1430,30 @@ export-item ::= 'export' id ':' extern-type | |
| import-item ::= 'import' id ':' extern-type | ||
| | 'import' use-path ';' | ||
|
|
||
| extern-type ::= func-type ';' | 'interface' '{' interface-items* '}' | ||
| extern-type ::= func-type ';' | 'interface' '{' interface-items* '}' | use-path ';' 🏷️ | ||
| ``` | ||
|
|
||
| 🏷️ The third case of `extern-type` allows a named interface to be imported or | ||
| exported with a custom [plain name]. For example: | ||
|
|
||
| ```wit | ||
| world my-world { | ||
| import primary: wasi:keyvalue/store; | ||
| import secondary: wasi:keyvalue/store; | ||
| export my-handler: wasi:http/handler; | ||
| } | ||
| ``` | ||
|
|
||
| Here, `primary` and `secondary` are two distinct imports that both have the | ||
| instance type of the `wasi:keyvalue/store` interface. The plain name of the | ||
| import is the `id` before the colon (e.g., `primary`), not the interface name. | ||
| This contrasts with `import wasi:keyvalue/store;` (without the `id :` prefix), | ||
| which would create a single import using the full interface name | ||
| `wasi:keyvalue/store`. Similarly, the export `my-handler` has the instance type | ||
| of `wasi:http/handler` but uses the plain name `my-handler` instead of the full | ||
| interface name, which is useful when a component wants to export the same | ||
| interface multiple times or simply use a more descriptive name. | ||
|
|
||
| Note that worlds can import types and define their own types to be exported | ||
| from the root of a component and used within functions imported and exported. | ||
| The `interface` item here additionally defines the grammar for IDs used to refer | ||
|
|
@@ -2061,6 +2131,52 @@ This duplication is useful in the case of cross-package references or split | |
| packages, allowing a compiled `world` definition to be fully self-contained and | ||
| able to be used to compile a component without additional type information. | ||
|
|
||
| 🏷️ When a world imports or exports a named interface with a custom plain name | ||
| (using the `id: use-path` syntax), the encoding uses the `[implements=<I>]` | ||
| annotation defined in [Explainer.md](Explainer.md#import-and-export-definitions) to indicate which | ||
| interface the instance implements. For example, the following WIT: | ||
|
|
||
| ```wit | ||
| package local:demo; | ||
|
|
||
| interface store { | ||
| get: func(key: string) -> option<string>; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just realized that there's a pretty nuanced technical design point (that iiuc the current impl is getting getting right atm) that this example should explicate via the generated WAT: Could you expand this example to include a Next, after the WAT, could you add a second variation of this example which factors out the |
||
| } | ||
|
|
||
| world w { | ||
| import one: store; | ||
| import two: store; | ||
| } | ||
| ``` | ||
|
|
||
| is encoded as: | ||
|
|
||
| ```wat | ||
| (component | ||
| (type (export "w") (component | ||
| (export "local:demo/w" (component | ||
| (import "[implements=<local:demo/store>]one" (instance | ||
| (export "get" (func (param "key" string) (result (option string)))) | ||
| )) | ||
| (import "[implements=<local:demo/store>]two" (instance | ||
| (export "get" (func (param "key" string) (result (option string)))) | ||
| )) | ||
| )) | ||
| )) | ||
| (type (export "store") (component | ||
| (export "local:demo/store" (instance | ||
| (export "get" (func (param "key" string) (result (option string)))) | ||
| )) | ||
| )) | ||
| ) | ||
| ``` | ||
|
|
||
| The `[implements=<local:demo/store>]` prefix tells bindings generators and | ||
| toolchains which interface each plain-named instance import implements, while | ||
| the labels `one` and `two` provide distinct plain names. This is a case of | ||
| the general `[implements=<interfacename>]label` pattern described in | ||
| [Explainer.md](Explainer.md#import-and-export-definitions). | ||
|
|
||
| Putting this all together, the following WIT definitions: | ||
|
|
||
| ```wit | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thinking more about this example/rule in the context of duplicate-name-conflicts: could you expand this example to have two
includes that contain a conflict for the plain-namecacheand explicitly mention that this would be an error without thewith(b/c we can't de-duplicate plain names like we can with pure interface names).