Skip to content

Commit b220724

Browse files
committed
Add 'optional' imports/exports
1 parent 06e3db0 commit b220724

4 files changed

Lines changed: 85 additions & 17 deletions

File tree

‎design/mvp/Binary.md‎

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -217,13 +217,20 @@ labellit ::= len:<u32> l:<label> => "l" (if len = |l|
217217
valtype ::= i:<typeidx> => i
218218
| pvt:<primvaltype> => pvt
219219
resourcetype ::= 0x3f t:<core:valtype> f?:<core:funcidx>? => (resource (rep t) (dtor f)?)
220-
functype ::= 0x40 ps:<paramlist> rs:<resultlist> => (func ps rs)
221-
| 0x43 ps:<paramlist> rs:<resultlist> => (func async ps rs)
220+
functype ::= 0x40 pr:<paramsresult> => (func pr)
221+
| 0x43 pr:<paramsresult> => (func async pr)
222+
| 0x44 i*:<funcimms> pr:<paramsresult> => (func i* pr)
223+
funcimms ::= 0x00 =>
224+
| 0x01 => optional
225+
| 0x02 => async
226+
| 0x03 => optional async
227+
paramsresult ::= p*:<paramlist> r?:<result?> => p* r?
222228
paramlist ::= lt*:vec(<labelvaltype>) => (param lt)*
223-
resultlist ::= 0x00 t:<valtype> => (result t)
229+
result? ::= 0x00 t:<valtype> => (result t)
224230
| 0x01 0x00 =>
225231
componenttype ::= 0x41 cd*:vec(<componentdecl>) => (component cd*)
226232
instancetype ::= 0x42 id*:vec(<instancedecl>) => (instance id*)
233+
| 0x45 0x01 id*:vec(<instancedecl>) => (instance optional id*)
227234
componentdecl ::= 0x03 id:<importdecl> => id
228235
| id:<instancedecl> => id
229236
instancedecl ::= 0x00 t:<core:type> => t
@@ -240,6 +247,7 @@ externtype ::= 0x00 0x11 i:<core:typeidx> => (core module (type
240247
| 0x05 i:<typeidx> => (instance (type i))
241248
typebound ::= 0x00 i:<typeidx> => (eq i)
242249
| 0x01 => (sub resource)
250+
| 0x02 0x01 => (sub optional resource)
243251
valuebound ::= 0x00 i:<valueidx> => (eq i) 🪙
244252
| 0x01 t:<valtype> => t 🪙
245253
```
@@ -301,6 +309,7 @@ canon ::= 0x00 0x00 f:<core:funcidx> opts:<opts> ft:<typeidx> => (canon lift
301309
| 0x02 rt:<typeidx> => (canon resource.new rt (core func))
302310
| 0x03 rt:<typeidx> => (canon resource.drop rt (core func))
303311
| 0x04 rt:<typeidx> => (canon resource.rep rt (core func))
312+
| 0x07 si:<sortidx> => (canon optional.present si (core global)) ❓
304313
| 0x24 => (canon backpressure.inc (core func)) 🔀
305314
| 0x25 => (canon backpressure.dec (core func)) 🔀
306315
| 0x09 rs:<resultlist> opts:<opts> => (canon task.return rs opts (core func)) 🔀
@@ -564,7 +573,7 @@ named once.
564573

565574
* The opcodes (for types, canon built-ins, etc) should be re-sorted
566575
* The two `list` type codes should be merged into one with an optional immediate
567-
and similarly for `func`.
576+
and similarly for `func`, `instance` and `typebound`.
568577
* The redundant `0x00` and `0x01` opcodes of `nameattributes` will be merged.
569578
* The vestigial `0x00` in `thread.*` and `waitable-set.*` built-ins may be
570579
removed.

‎design/mvp/CanonicalABI.md‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ specified here.
4040
* [`canon resource.new`](#canon-resourcenew)
4141
* [`canon resource.drop`](#canon-resourcedrop)
4242
* [`canon resource.rep`](#canon-resourcerep)
43+
* [`canon optional.present`](#-canon-optionalpresent) ❓
4344
* [`canon context.get`](#-canon-contextget) 🔀
4445
* [`canon context.set`](#-canon-contextset) 🔀
4546
* [`canon backpressure.{inc,dec}`](#-canon-backpressureincdec) 🔀
@@ -3367,6 +3368,10 @@ validation is performed:
33673368
* if `len(flatten_types(ft.param_types())) > MAX_FLAT_PARAMS`, `realloc` is required
33683369
* if `len(flatten_types(ft.result_type())) > max` (where `max = MAX_FLAT_RESULTS` for sync lifts, and `max = MAX_FLAT_PARAMS` for async lifts), `memory` is required
33693370

3371+
TODO: if `$ft` is optional and one of its referenced resource types is imported and
3372+
"none", the `canon lift`ed function becomes "none"
3373+
TODO: define some `refers_to_non_existent_resource`, `assert(not refers_to_non_existent_resource(ft))`
3374+
33703375
Note that an `async`-lifted function whose result type requires a memory to lift
33713376
(either because it contains lists or strings or because the number of flattened
33723377
types exceeds `MAX_FLAT_PARAMS`) must include a `memory` option, and that option
@@ -3612,10 +3617,13 @@ runtime Core WebAssembly arguments.
36123617
Based on this, `canon_lower` is defined in chunks as follows. First, like most
36133618
Canonical ABI functions callable from Core WebAssembly, lowered imports may not
36143619
be called during `post-return` or `realloc`:
3620+
TODO: mention optional
36153621
```python
36163622
def canon_lower(callee, ft, opts, flat_args: list[CoreValType]) -> list[CoreValType]:
36173623
thread = current_thread()
36183624
trap_if(not thread.task.inst.may_leave)
3625+
assert(ft.optional or callee is not None)
3626+
trap_if(callee is None)
36193627
```
36203628

36213629
The component-level function type maps to a Core WebAssembly function type using
@@ -3830,6 +3838,24 @@ Note that the "locally-defined" requirement above ensures that only the
38303838
component instance defining a resource can access its representation.
38313839

38323840

3841+
### ❓ `canon optional.present`
3842+
3843+
For a canonical definition:
3844+
```wat
3845+
(canon optional.present $sortidx (core global $present))
3846+
```
3847+
validation specifies:
3848+
* `$sortidx` must refer to a `(func optional ...)`, `(instance optional ...)` or
3849+
`(type (sub optional ...))`
3850+
* `$present` is given type `(global i32)`
3851+
3852+
The new immutable global `$present` is appended to the core global index space
3853+
and is either `1` or `0` depending on whether the [`optional`] `$sortidx` is
3854+
present or not, resp. Core wasm code can then import this synthesized global and
3855+
use it to conditionalize calls to any `optional` function (which would otherwise
3856+
trap if called).
3857+
3858+
38333859
### 🔀 `canon context.get`
38343860

38353861
For a canonical definition:
@@ -4963,6 +4989,7 @@ def canon_thread_available_parallelism():
49634989
[`canonopt`]: Explainer.md#canonical-definitions
49644990
[`canon`]: Explainer.md#canonical-definitions
49654991
[Type Definitions]: Explainer.md#type-definitions
4992+
[`optional`]: Explainer.md#optionality
49664993
[Component Invariant]: Explainer.md#component-invariants
49674994
[JavaScript Embedding]: Explainer.md#JavaScript-embedding
49684995
[ESM-integration]: Explainer.md#esm-integration

‎design/mvp/Explainer.md‎

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@ more user-focused explanation, take a look at the
2020
* [Asynchronous value types](#asynchronous-value-types)
2121
* [Specialized value types](#specialized-value-types)
2222
* [Definition types](#definition-types)
23+
* [Optionality](#optionality)
2324
* [Declarators](#declarators)
2425
* [Type checking](#type-checking)
2526
* [Canonical definitions](#canonical-definitions)
2627
* [Canonical ABI](#canonical-abi)
2728
* [Canonical built-ins](#canonical-built-ins)
2829
* [Resource built-ins](#resource-built-ins)
30+
* [Optionality built-ins](#-optionality-built-ins)
2931
* [Concurrency built-ins](#-concurrency-built-ins)
3032
* [Error Context built-ins](#-error-context-built-ins)
3133
* [Value definitions](#-value-definitions)
@@ -77,6 +79,7 @@ shipped as part of a future WASI Developer Preview release:
7779
* 🐘: [memory64]
7880
* 📡: getters and setters
7981
* ➡️: `stream.forward` and `future.forward` built-ins
82+
* ❓: `optional` imports and exports
8083

8184

8285
## Grammar
@@ -323,6 +326,7 @@ instanceexpr ::= (instantiate <componentidx> <instantiatearg>*)
323326
| <inlineexport>*
324327
instantiatearg ::= (with <name> <externidx>)
325328
| (with <name> (instance <inlineexport>*))
329+
| (with <name>) ❓
326330
name ::= <core:name>
327331
inlineexport ::= (export <externnamelit> <externidx>)
328332
| (export <externnamelit> <versionsuffix> <externidx>) 🔗
@@ -377,6 +381,8 @@ the `foo` function of its child component `$C` and re-export it directly from
377381
)
378382
```
379383

384+
TODO: mention `alias export` of `optional` `instance` ~~> optional X (disallow X=component for now)
385+
380386
Additional syntactic sugar is added for allowing export aliases to be defined
381387
*inline* as a syntactic generalization of the `{X}sortidx` grammar rules
382388
defined [above](#index-spaces) for each core- and component-level sort `X`:
@@ -453,6 +459,8 @@ aliased by `$E`:
453459
)
454460
```
455461

462+
TODO: anything interesting here when reaching out of optional scope?
463+
456464
For `outer` aliases, there is also inline syntactic sugar, which is simply to
457465
use the identifier of the outer definition, resolved using normal lexical
458466
scoping rules. For example, the following component:
@@ -636,9 +644,13 @@ valtype ::= <typeidx>
636644
keytype ::= bool | s8 | u8 | s16 | u16 | s32 | u32 | s64 | u64 | char | string 🗺️
637645
resourcetype ::= (resource (rep i32) (dtor core-prefix(<core:funcidx>))?)
638646
| (resource (rep i64) (dtor core-prefix(<core:funcidx>))?) 🐘
639-
functype ::= (func async? (param <labellit> <valtype>)* (result <valtype>)?)
647+
functype ::= (func <optional?> <async?> (param <labellit> <valtype>)* (result <valtype>)?)
648+
optional? ::= ϵ
649+
| optional ❓
650+
async? ::= ϵ
651+
| async 🔀
640652
componenttype ::= (component <componentdecl>*)
641-
instancetype ::= (instance <instancedecl>*)
653+
instancetype ::= (instance <optional?> <instancedecl>*)
642654
componentdecl ::= <importdecl>
643655
| <instancedecl>
644656
instancedecl ::= core-prefix(<core:type>)
@@ -655,7 +667,7 @@ externtype ::= (<sort> (type <idx>) )
655667
| (value <valuebound>) 🪙
656668
| (type <typebound>)
657669
typebound ::= (eq <typeidx>)
658-
| (sub resource)
670+
| (sub <optional?> resource)
659671
valuebound ::= (eq <valueidx>) 🪙
660672
| <valtype> 🪙
661673
@@ -914,6 +926,12 @@ declarators. The meanings of these declarators is basically the same as the
914926
core module declarators introduced above, but expanded to cover the additional
915927
capabilities of the component model.
916928

929+
#### Optionality
930+
931+
TODO: describe
932+
933+
See [`optional.test`](#-optionality-built-ins) below for more details.
934+
917935
#### Declarators
918936

919937
The `importdecl` and `exportdecl` declarators correspond to component `import`
@@ -1332,6 +1350,9 @@ replaced by `$R` when validating the instantiations of `$c1` and `$c2`. These
13321350
type-checking rules for instantiating type imports mirror the *elimination*
13331351
rule of [universal types] (∀T).
13341352

1353+
TODO: if don't provide type, substitute incompatible type; prevent functions
1354+
from being supplied...
1355+
13351356
Importantly, this type substitution performed by the parent is not visible to
13361357
the child at validation- or run-time. In particular, there are no runtime
13371358
casts that can "see through" to the original type parameter, avoiding
@@ -1555,6 +1576,7 @@ canon ::= ...
15551576
| (canon resource.new <typeidx> (core func <id>?))
15561577
| (canon resource.drop <typeidx> (core func <id>?))
15571578
| (canon resource.rep <typeidx> (core func <id>?))
1579+
| (canon optional.present <sortidx> (core global <id>?)) ❓
15581580
| (canon context.get <core:valtype> <u32> (core func <id>?)) 🔀
15591581
| (canon context.set <core:valtype> <u32> (core func <id>?)) 🔀
15601582
| (canon backpressure.inc (core func <id>?)) 🔀
@@ -1681,6 +1703,12 @@ transferring ownership of the newly-created resource to the export's caller.
16811703

16821704
For details, see [`canon_resource_rep`] in the Canonical ABI explainer.
16831705

1706+
##### ❓ Optionality built-ins
1707+
1708+
###### ❓ `optional.present`
1709+
1710+
TODO
1711+
16841712
##### 🔀🧵 Concurrency built-ins
16851713

16861714
See the [concurrency explainer] for background.

‎design/mvp/WIT.md‎

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,9 @@ world union-my-world {
308308
}
309309
```
310310

311+
TODO: add `optional` to some of the `include` examples above (unions *both* imports and exports)
312+
TODO: add a note that `include` does not produce subtype or supertype, but other ways to combine worlds (`meet` and `join`) could be added in the future
313+
311314
### De-duplication of interfaces
312315

313316
If two worlds share an imported or exported [interface name], then the union of
@@ -339,6 +342,8 @@ world union-my-world-b {
339342
}
340343
```
341344

345+
TODO: mention merging of `optional` and non-`optional` ~~> non-`optional`
346+
342347
### Name Conflicts and `with`
343348

344349
When two or more included Worlds have the same name for an import or export
@@ -436,12 +441,6 @@ world invalid-union-world {
436441
437442
```
438443

439-
### A Note on Subtyping
440-
441-
In the future, when `optional` export is supported, the world author may explicitly mark exports as optional to make a component targeting an included World a subtype of the union World.
442-
443-
For now, we are not following the subtyping rules for the `include` statement. That is, the `include` statement does not imply any subtyping relationship between the included worlds and the union world.
444-
445444
## WIT Packages and `use`
446445
[use]: #wit-packages-and-use
447446

@@ -563,6 +562,8 @@ interface my-interface {
563562
}
564563
```
565564

565+
TODO: `use` resolution when only used from `optional`y-imported interfaces --> `optional`
566+
566567
#### Top-level `use`
567568

568569
If a package being referred to has a version number, then using the above syntax
@@ -1075,6 +1076,7 @@ keyword ::= 'as'
10751076
| 'list'
10761077
| 'map'
10771078
| 'option'
1079+
| 'optional'
10781080
| 'own'
10791081
| 'package'
10801082
| 'record'
@@ -1441,10 +1443,10 @@ world-definition ::= export-item
14411443
| typedef-item
14421444
| include-item
14431445
1444-
export-item ::= external-id? 'export' id ':' extern-type
1445-
| 'export' use-path ';'
1446-
import-item ::= external-id? 'import' id ':' extern-type
1447-
| 'import' use-path ';'
1446+
export-item ::= external-id? 'export' id ':' 'optional'? extern-type
1447+
| 'export' 'optional'? use-path ';'
1448+
import-item ::= external-id? 'import' id ':' 'optional'? extern-type
1449+
| 'import' 'optional'? use-path ';'
14481450
14491451
external-id ::= '@external-id' '(' string-literal ')' 🏷️
14501452
@@ -1508,6 +1510,8 @@ world my-world {
15081510
}
15091511
```
15101512

1513+
TODO: note `optional` and what it means
1514+
15111515
[`componenttype`]: Explainer.md#type-definitions
15121516

15131517
## Item: `include`

0 commit comments

Comments
 (0)