-
Notifications
You must be signed in to change notification settings - Fork 90
Interface version canonicalization #536
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 | ||||
---|---|---|---|---|---|---|
|
@@ -371,10 +371,13 @@ flags are set. | |||||
(See [Import and Export Definitions](Explainer.md#import-and-export-definitions) | ||||||
in the explainer.) | ||||||
```ebnf | ||||||
import ::= in:<importname'> ed:<externdesc> => (import in ed) | ||||||
export ::= en:<exportname'> si:<sortidx> ed?:<externdesc>? => (export en si ed?) | ||||||
importname' ::= 0x00 len:<u32> in:<importname> => in (if len = |in|) | ||||||
exportname' ::= 0x00 len:<u32> en:<exportname> => en (if len = |en|) | ||||||
import ::= in:<importname'> ed:<externdesc> => (import in ed) | ||||||
export ::= en:<exportname'> si:<sortidx> ed?:<externdesc>? => (export en si ed?) | ||||||
importname' ::= 0x00 len:<u32> in:<importname> => in (if len = |in|) | ||||||
| 0x01 len:<u32> in:<importname> vs:<versionsuffix'> => in vs (if len = |in|) | ||||||
exportname' ::= 0x00 len:<u32> en:<exportname> => en (if len = |en|) | ||||||
| 0x01 len:<u32> en:<exportname> vs:<versionsuffix'> => in vs (if len = |in|) | ||||||
versionsuffix' ::= len:<u32> vs:<semver suffix> => (versionsuffix vs) (if len = |vs|) | ||||||
``` | ||||||
|
||||||
Notes: | ||||||
|
@@ -399,7 +402,10 @@ Notes: | |||||
`(result (own $R))`, where `$R` is the resource labeled `r`. | ||||||
* Validation of `[method]` names requires the first parameter of the function | ||||||
to be `(param "self" (borrow $R))`, where `$R` is the resource labeled `r`. | ||||||
* `<valid semver>` is as defined by [https://semver.org](https://semver.org/) | ||||||
* Validation requires that `versionsuffix` is preceded by an `interfaceversion` | ||||||
with a `canonversion` and that the concatenation of the `canonversion` and the | ||||||
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.
Suggested change
|
||||||
`versionsuffix` results in a `valid semver` as defined by | ||||||
[https://semver.org](https://semver.org/) | ||||||
* `<integrity-metadata>` is as defined by the | ||||||
[SRI](https://www.w3.org/TR/SRI/#dfn-integrity-metadata) spec. | ||||||
|
||||||
|
@@ -494,7 +500,9 @@ named once. | |||||
|
||||||
* The opcodes (for types, canon built-ins, etc) should be re-sorted | ||||||
* The two `list` type codes should be merged into one with an optional immediate. | ||||||
* The `0x00` prefix byte of `importname'` and `exportname'` will be removed or repurposed. | ||||||
* The `0x00` variant of `importname'` and `exportname'` will be removed. Any | ||||||
remaining variant(s) will be renumbered or the prefix byte will be removed or | ||||||
repurposed. | ||||||
|
||||||
|
||||||
[`core:byte`]: https://webassembly.github.io/spec/core/binary/values.html#binary-byte | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,6 +33,7 @@ more user-focused explanation, take a look at the | |
* [Start definitions](#-start-definitions) | ||
* [Import and export definitions](#import-and-export-definitions) | ||
* [Name uniqueness](#name-uniqueness) | ||
* [Canonical interface name](#canonical-interface-name) | ||
* [Component invariants](#component-invariants) | ||
* [JavaScript embedding](#JavaScript-embedding) | ||
* [JS API](#JS-API) | ||
|
@@ -294,7 +295,7 @@ sort ::= core <core:sort> | |
| type | ||
| component | ||
| instance | ||
inlineexport ::= (export <exportname> <sortidx>) | ||
inlineexport ::= (export "<exportname>" <versionsuffix>? <sortidx>) | ||
``` | ||
Because component-level function, type and instance definitions are different | ||
than core-level function, type and instance definitions, they are put into | ||
|
@@ -574,8 +575,8 @@ instancedecl ::= core-prefix(<core:type>) | |
| <alias> | ||
| <exportdecl> | ||
| <value> 🪙 | ||
importdecl ::= (import <importname> bind-id(<externdesc>)) | ||
exportdecl ::= (export <exportname> bind-id(<externdesc>)) | ||
importdecl ::= (import "<importname>" <versionsuffix>? bind-id(<externdesc>)) | ||
exportdecl ::= (export "<exportname>" <versionsuffix>? bind-id(<externdesc>)) | ||
externdesc ::= (<sort> (type <u32>) ) | ||
| core-prefix(<core:moduletype>) | ||
| <functype> | ||
|
@@ -2242,8 +2243,9 @@ the identifier `$x`). In the case of exports, the `<id>?` right after the | |
preceding definition being exported (e.g., `(export $x "x" (func $f))` binds a | ||
new identifier `$x`). | ||
```ebnf | ||
import ::= (import "<importname>" bind-id(<externdesc>)) | ||
export ::= (export <id>? "<exportname>" <sortidx> <externdesc>?) | ||
import ::= (import "<importname>" <versionsuffix>? bind-id(<externdesc>)) | ||
export ::= (export <id>? "<exportname>" <versionsuffix>? <sortidx> <externdesc>?) | ||
versionsuffix ::= (versionsuffix "<semver suffix>") | ||
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. Should |
||
``` | ||
All import names are required to be [strongly-unique]. Separately, all export | ||
names are also required to be [strongly-unique]. The rest of the grammar for | ||
|
@@ -2276,17 +2278,23 @@ fragment ::= <word> | |
| <acronym> | ||
word ::= [a-z] [0-9a-z]* | ||
acronym ::= [A-Z] [0-9A-Z]* | ||
interfacename ::= <namespace> <label> <projection> <version>? | ||
| <namespace>+ <label> <projection>+ <version>? 🪺 | ||
interfacename ::= <namespace> <label> <projection> <interfaceversion>? | ||
| <namespace>+ <label> <projection>+ <interfaceversion>? 🪺 | ||
namespace ::= <words> ':' | ||
words ::= <word> | ||
| <words> '-' <word> | ||
projection ::= '/' <label> | ||
version ::= '@' <valid semver> | ||
# FIXME: surrounding alignment | ||
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. TODO after final review |
||
interfaceversion ::= '@' <valid semver> | ||
| '@' <canonversion> | ||
canonversion ::= [1-9] [0-9]* | ||
| '0.' [1-9] [0-9]* | ||
| '0.0.' [1-9] [0-9]* | ||
Comment on lines
+2288
to
+2292
Contributor
Author
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. There is some ambiguity here; 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. Good point and I think you're right; it's fine if we word the validation rules in terms of "matching |
||
depname ::= 'unlocked-dep=<' <pkgnamequery> '>' | ||
| 'locked-dep=<' <pkgname> '>' ( ',' <hashname> )? | ||
pkgnamequery ::= <pkgpath> <verrange>? | ||
pkgname ::= <pkgpath> <version>? | ||
pkgname ::= <pkgpath> <pkgversion>? | ||
pkgversion ::= '@' <valid semver> | ||
pkgpath ::= <namespace> <words> | ||
| <namespace>+ <words> <projection>* 🪺 | ||
verrange ::= '@*' | ||
|
@@ -2539,6 +2547,46 @@ annotations. For example, the validation rules for `[constructor]foo` require | |
for details. | ||
|
||
|
||
### Canonical Interface Name | ||
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. Can you find the place in the preceding "Import and export definitions" section where |
||
|
||
An `interfacename` (as defined above) is **canonical** iff it either: | ||
|
||
- has no `interfaceversion` | ||
- has an `interfaceversion` matching the `canonversion` production | ||
|
||
The purpose of `canonversion` is to simplify the matching of compatible import | ||
and export versions. For example, if a guest imports some interface from | ||
`wasi:http/[email protected]` and a host provides the (subtype-compatible) interface | ||
`wasi:http/[email protected]`, we'd like to make it easy for the host to link with the | ||
guest. The `canonversion` for both of these interfaces would be `0.2`, so this | ||
linking could be done by matching canonical interface names literally. | ||
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. Could you also mention the more-nuanced "forward compatibility" case (a component imports the new version, but uses only the functions present in the hold version with compatible types)? |
||
|
||
Any `valid semver` (as used in WIT) can be canonicalized by splitting it into | ||
two parts - the `canonversion` prefix and the remaining `semver suffix`. Using | ||
the `<major>.<minor>.<patch>` syntax of [Semantic Versioning 2.0], the split | ||
point is chosen as follows: | ||
|
||
- if `major` > 0, split immediately after `major` | ||
- `1.2.3` → `1` / `.2.3` | ||
- otherwise if `minor` > 0, split immediately after `minor` | ||
- `0.2.6-rc.1` → `0.2` / `.6-rc.1` | ||
- otherwise, split immediately after `patch` | ||
- `0.0.1-alpha` → `0.0.1` / `-alpha` | ||
|
||
When a version is canonicalized, any `semver suffix` that was split off of the | ||
version should be preserved in the `versionsuffix` field of any resulting | ||
`import`s and `export`s. This gives component runtimes and other tools access to | ||
the original version for error messages, documentation, and other development | ||
purposes. Where a `versionsuffix` is present the preceding `interfacename` must | ||
have a `canonversion`, and the concatenation of the `canonversion` and | ||
`versionsuffix` must be a `valid semver`. | ||
|
||
For compatibility with older versions of this spec, non-canonical | ||
`interfacename`s (with `interfaceversion`s matching any `valid semver`) are | ||
temporarily permitted. These non-canonical names may trigger warnings and will | ||
start being rejected some time after after [WASI Preview 3] is released. | ||
|
||
|
||
## Component Invariants | ||
|
||
As a consequence of the shared-nothing design described above, all calls into | ||
|
@@ -2894,6 +2942,7 @@ For some use-case-focused, worked examples, see: | |
[`rectype`]: https://webassembly.github.io/gc/core/text/types.html#text-rectype | ||
[shared-everything-threads]: https://github.com/WebAssembly/shared-everything-threads | ||
[WASI Preview 2]: https://github.com/WebAssembly/WASI/tree/main/wasip2#readme | ||
[WASI Preview 3]: https://github.com/WebAssembly/WASI/tree/main/wasip2#looking-forward-to-preview-3 | ||
[reference types]: https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md | ||
|
||
[Strongly-unique]: #name-uniqueness | ||
|
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.
<valid semver>
wasn't referenced in this file.