@@ -33,6 +33,7 @@ more user-focused explanation, take a look at the
33
33
* [ Start definitions] ( #-start-definitions )
34
34
* [ Import and export definitions] ( #import-and-export-definitions )
35
35
* [ Name uniqueness] ( #name-uniqueness )
36
+ * [ Canonical interface name] ( #-canonical-interface-name )
36
37
* [ Component invariants] ( #component-invariants )
37
38
* [ JavaScript embedding] ( #JavaScript-embedding )
38
39
* [ JS API] ( #JS-API )
@@ -55,6 +56,7 @@ implemented, considered stable and included in a future milestone:
55
56
* 🧵: threading built-ins
56
57
* 🔧: fixed-length lists
57
58
* 📝: the ` error-context ` type
59
+ * 🔗: canonical interface names
58
60
59
61
(Based on the previous [ scoping and layering] proposal to the WebAssembly CG,
60
62
this repo merges and supersedes the [ module-linking] and [ interface-types]
@@ -294,7 +296,8 @@ sort ::= core <core:sort>
294
296
| type
295
297
| component
296
298
| instance
297
- inlineexport ::= (export <exportname> <sortidx>)
299
+ inlineexport ::= (export "<exportname>" <sortidx>)
300
+ | (export "<exportname>" <versionsuffix> <sortidx>) 🔗
298
301
```
299
302
Because component-level function, type and instance definitions are different
300
303
than core-level function, type and instance definitions, they are put into
@@ -574,8 +577,10 @@ instancedecl ::= core-prefix(<core:type>)
574
577
| <alias>
575
578
| <exportdecl>
576
579
| <value> 🪙
577
- importdecl ::= (import <importname> bind-id(<externdesc>))
578
- exportdecl ::= (export <exportname> bind-id(<externdesc>))
580
+ importdecl ::= (import "<importname>" bind-id(<externdesc>))
581
+ | (import "<importname>" <versionsuffix> bind-id(<externdesc>)) 🔗
582
+ exportdecl ::= (export "<exportname>" bind-id(<externdesc>))
583
+ | (export "<exportname>" <versionsuffix> bind-id(<externdesc>)) 🔗
579
584
externdesc ::= (<sort> (type <u32>) )
580
585
| core-prefix(<core:moduletype>)
581
586
| <functype>
@@ -988,6 +993,10 @@ and `$C1` is a subtype of `$C2`:
988
993
)
989
994
```
990
995
996
+ 🔗 Note that [ canonical interface names] ( #-canonical-interface-name ) may be
997
+ annotated with a ` versionsuffix ` which is ignored for type checking except to
998
+ improve diagnostic messages.
999
+
991
1000
When we next consider type imports and exports, there are two distinct
992
1001
subcases of ` typebound ` to consider: ` eq ` and ` sub ` .
993
1002
@@ -2264,8 +2273,11 @@ the identifier `$x`). In the case of exports, the `<id>?` right after the
2264
2273
preceding definition being exported (e.g., ` (export $x "x" (func $f)) ` binds a
2265
2274
new identifier ` $x ` ).
2266
2275
``` ebnf
2267
- import ::= (import "<importname>" bind-id(<externdesc>))
2268
- export ::= (export <id>? "<exportname>" <sortidx> <externdesc>?)
2276
+ import ::= (import "<importname>" bind-id(<externdesc>))
2277
+ | (import "<importname>" <versionsuffix> bind-id(<externdesc>)) 🔗
2278
+ export ::= (export <id>? "<exportname>" <sortidx> <externdesc>?)
2279
+ | (export <id>? "<exportname>" <versionsuffix> <sortidx> <externdesc>?) 🔗
2280
+ versionsuffix ::= (versionsuffix "<semversuffix>") 🔗
2269
2281
```
2270
2282
All import names are required to be [ strongly-unique] . Separately, all export
2271
2283
names are also required to be [ strongly-unique] . The rest of the grammar for
@@ -2279,47 +2291,53 @@ interpreted as a *lexical* grammar defining a single token and thus whitespace
2279
2291
is not automatically inserted, all terminals are single-quoted, and everything
2280
2292
unquoted is a meta-character.
2281
2293
``` ebnf
2282
- exportname ::= <plainname>
2283
- | <interfacename>
2284
- importname ::= <exportname>
2285
- | <depname>
2286
- | <urlname>
2287
- | <hashname>
2288
- plainname ::= <label>
2289
- | '[async]' <label> 🔀
2290
- | '[constructor]' <label>
2291
- | '[method]' <label> '.' <label>
2292
- | '[async method]' <label> '.' <label> 🔀
2293
- | '[static]' <label> '.' <label>
2294
- | '[async static]' <label> '.' <label> 🔀
2295
- label ::= <fragment>
2296
- | <label> '-' <fragment>
2297
- fragment ::= <word>
2298
- | <acronym>
2299
- word ::= [a-z] [0-9a-z]*
2300
- acronym ::= [A-Z] [0-9A-Z]*
2301
- interfacename ::= <namespace> <label> <projection> <version>?
2302
- | <namespace>+ <label> <projection>+ <version>? 🪺
2303
- namespace ::= <words> ':'
2304
- words ::= <word>
2305
- | <words> '-' <word>
2306
- projection ::= '/' <label>
2307
- version ::= '@' <valid semver>
2308
- depname ::= 'unlocked-dep=<' <pkgnamequery> '>'
2309
- | 'locked-dep=<' <pkgname> '>' ( ',' <hashname> )?
2310
- pkgnamequery ::= <pkgpath> <verrange>?
2311
- pkgname ::= <pkgpath> <version>?
2312
- pkgpath ::= <namespace> <words>
2313
- | <namespace>+ <words> <projection>* 🪺
2314
- verrange ::= '@*'
2315
- | '@{' <verlower> '}'
2316
- | '@{' <verupper> '}'
2317
- | '@{' <verlower> ' ' <verupper> '}'
2318
- verlower ::= '>=' <valid semver>
2319
- verupper ::= '<' <valid semver>
2320
- urlname ::= 'url=<' <nonbrackets> '>' (',' <hashname>)?
2321
- nonbrackets ::= [^<>]*
2322
- hashname ::= 'integrity=<' <integrity-metadata> '>'
2294
+ exportname ::= <plainname>
2295
+ | <interfacename>
2296
+ importname ::= <exportname>
2297
+ | <depname>
2298
+ | <urlname>
2299
+ | <hashname>
2300
+ plainname ::= <label>
2301
+ | '[async]' <label> 🔀
2302
+ | '[constructor]' <label>
2303
+ | '[method]' <label> '.' <label>
2304
+ | '[async method]' <label> '.' <label> 🔀
2305
+ | '[static]' <label> '.' <label>
2306
+ | '[async static]' <label> '.' <label> 🔀
2307
+ label ::= <fragment>
2308
+ | <label> '-' <fragment>
2309
+ fragment ::= <word>
2310
+ | <acronym>
2311
+ word ::= [a-z] [0-9a-z]*
2312
+ acronym ::= [A-Z] [0-9A-Z]*
2313
+ interfacename ::= <namespace> <label> <projection> <interfaceversion>?
2314
+ | <namespace>+ <label> <projection>+ <interfaceversion>? 🪺
2315
+ namespace ::= <words> ':'
2316
+ words ::= <word>
2317
+ | <words> '-' <word>
2318
+ projection ::= '/' <label>
2319
+ interfaceversion ::= '@' <valid semver>
2320
+ | '@' <canonversion> 🔗
2321
+ canonversion ::= [1-9] [0-9]* 🔗
2322
+ | '0.' [1-9] [0-9]* 🔗
2323
+ | '0.0.' [1-9] [0-9]* 🔗
2324
+ semversuffix ::= [0-9A-Za-z.+-]* 🔗
2325
+ depname ::= 'unlocked-dep=<' <pkgnamequery> '>'
2326
+ | 'locked-dep=<' <pkgname> '>' ( ',' <hashname> )?
2327
+ pkgnamequery ::= <pkgpath> <verrange>?
2328
+ pkgname ::= <pkgpath> <pkgversion>?
2329
+ pkgversion ::= '@' <valid semver>
2330
+ pkgpath ::= <namespace> <words>
2331
+ | <namespace>+ <words> <projection>* 🪺
2332
+ verrange ::= '@*'
2333
+ | '@{' <verlower> '}'
2334
+ | '@{' <verupper> '}'
2335
+ | '@{' <verlower> ' ' <verupper> '}'
2336
+ verlower ::= '>=' <valid semver>
2337
+ verupper ::= '<' <valid semver>
2338
+ urlname ::= 'url=<' <nonbrackets> '>' (',' <hashname>)?
2339
+ nonbrackets ::= [^<>]*
2340
+ hashname ::= 'integrity=<' <integrity-metadata> '>'
2323
2341
```
2324
2342
Components provide six options for naming imports:
2325
2343
* a ** plain name** that leaves it up to the developer to "read the docs"
@@ -2394,7 +2412,9 @@ tooling as "registries":
2394
2412
parameter of [ ` WebAssembly.instantiate() ` ] )
2395
2413
2396
2414
The ` valid semver ` production is as defined by the [ Semantic Versioning 2.0]
2397
- spec and is meant to be interpreted according to that specification. The
2415
+ spec and is meant to be interpreted according to that specification. The use of
2416
+ ` valid semver ` in ` interfaceversion ` is temporary for backward compatibility;
2417
+ see [ Canonical interface name] ( #-canonical-interface-name ) below (🔗). The
2398
2418
` verrange ` production embeds a minimal subset of the syntax for version ranges
2399
2419
found in common package managers like ` npm ` and ` cargo ` and is meant to be
2400
2420
interpreted with the same [ semantics] [ SemVerRange ] . (Mostly this
@@ -2561,6 +2581,53 @@ annotations. For example, the validation rules for `[constructor]foo` require
2561
2581
for details.
2562
2582
2563
2583
2584
+ ### 🔗 Canonical Interface Name
2585
+
2586
+ An ` interfacename ` (as defined above) is ** canonical** iff it either:
2587
+
2588
+ - has no ` interfaceversion `
2589
+ - has an ` interfaceversion ` matching the ` canonversion ` production
2590
+
2591
+ The purpose of ` canonversion ` is to simplify the matching of compatible import
2592
+ and export versions. For example, if a guest imports some interface from
2593
+ ` wasi:http/[email protected] ` and a host provides the (subtype-compatible) interface
2594
+ ` wasi:http/[email protected] ` , we'd like to make it easy for the host to link with the
2595
+ guest. The ` canonversion ` for both of these interfaces would be ` 0.2 ` , so this
2596
+ linking could be done by matching canonical interface names literally.
2597
+ Symmetrically, if a host provides
` wasi:http/[email protected] ` and a guest imports
2598
+ ` wasi:http/[email protected] ` , so long as the guest only uses the subset of
2599
+ functions defined in
` wasi:http/[email protected] ` (which is checked by normal
2600
+ component type validation), linking succeeds. Thus, including only the
2601
+ canonicalized version in the name allows both backwards and (limited)
2602
+ forwards compatibility using only trivial string equality (as well as the
2603
+ type checking already required).
2604
+
2605
+ Any ` valid semver ` (as used in WIT) can be canonicalized by splitting it into
2606
+ two parts - the ` canonversion ` prefix and the remaining ` semversuffix ` . Using
2607
+ the ` <major>.<minor>.<patch> ` syntax of [ Semantic Versioning 2.0] , the split
2608
+ point is chosen as follows:
2609
+
2610
+ - if ` major ` > 0, split immediately after ` major `
2611
+ - ` 1.2.3 ` &rarr ; ` 1 ` / ` .2.3 `
2612
+ - otherwise if ` minor ` > 0, split immediately after ` minor `
2613
+ - ` 0.2.6-rc.1 ` &rarr ; ` 0.2 ` / ` .6-rc.1 `
2614
+ - otherwise, split immediately after ` patch `
2615
+ - ` 0.0.1-alpha ` &rarr ; ` 0.0.1 ` / ` -alpha `
2616
+
2617
+ When a version is canonicalized, any ` semversuffix ` that was split off of the
2618
+ version should be preserved in the ` versionsuffix ` field of any resulting
2619
+ ` import ` s and ` export ` s. This gives component runtimes and other tools access to
2620
+ the original version for error messages, documentation, and other development
2621
+ purposes. Where a ` versionsuffix ` is present the preceding ` interfacename ` must
2622
+ have a ` canonversion ` , and the concatenation of the ` canonversion ` and
2623
+ ` versionsuffix ` must be a ` valid semver ` .
2624
+
2625
+ For compatibility with older versions of this spec, non-canonical
2626
+ ` interfacename ` s (with ` interfaceversion ` s matching any ` valid semver ` ) are
2627
+ temporarily permitted. These non-canonical names may trigger warnings and will
2628
+ start being rejected some time after after [ WASI Preview 3] is released.
2629
+
2630
+
2564
2631
## Component Invariants
2565
2632
2566
2633
As a consequence of the shared-nothing design described above, all calls into
@@ -2916,6 +2983,7 @@ For some use-case-focused, worked examples, see:
2916
2983
[ `rectype` ] : https://webassembly.github.io/gc/core/text/types.html#text-rectype
2917
2984
[ shared-everything-threads ] : https://github.com/WebAssembly/shared-everything-threads
2918
2985
[ WASI Preview 2 ] : https://github.com/WebAssembly/WASI/tree/main/wasip2#readme
2986
+ [ WASI Preview 3 ] : https://github.com/WebAssembly/WASI/tree/main/wasip2#looking-forward-to-preview-3
2919
2987
[ reference types ] : https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md
2920
2988
2921
2989
[ Strongly-unique ] : #name-uniqueness
0 commit comments