Skip to content

Commit d19614d

Browse files
committed
Add 'optional' imports/exports
1 parent 22e082c commit d19614d

3 files changed

Lines changed: 56 additions & 13 deletions

File tree

design/mvp/CanonicalABI.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ specified here.
6868
* [`canon thread.yield-then-resume`](#-canon-threadyield-then-resume) 🧵
6969
* [`canon thread.suspend-then-promote`](#-canon-threadsuspend-then-promote) 🧵
7070
* [`canon thread.yield-then-promote`](#-canon-threadyield-then-promote) 🧵
71+
* [`canon optional.present`](#-canon-optionalpresent)
7172
* [`canon error-context.new`](#-canon-error-contextnew) 📝
7273
* [`canon error-context.debug-message`](#-canon-error-contextdebug-message) 📝
7374
* [`canon error-context.drop`](#-canon-error-contextdrop) 📝
@@ -3579,6 +3580,10 @@ validation is performed:
35793580
* if `len(flatten_types(ft.param_types())) > MAX_FLAT_PARAMS`, `realloc` is required
35803581
* 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
35813582

3583+
TODO: if `$ft` is optional and one of its referenced resource types is imported and
3584+
"none", the `canon lift`ed function becomes "none"
3585+
TODO: define some `refers_to_non_existent_resource`, `assert(not refers_to_non_existent_resource(ft))`
3586+
35823587
Note that an `async`-lifted function whose result type requires a memory to lift
35833588
(either because it contains lists or strings or because the number of flattened
35843589
types exceeds `MAX_FLAT_PARAMS`) must include a `memory` option, and that option
@@ -3816,10 +3821,13 @@ runtime Core WebAssembly arguments.
38163821
Based on this, `canon_lower` is defined in chunks as follows. First, like most
38173822
Canonical ABI functions callable from Core WebAssembly, lowered imports may not
38183823
be called during `post-return` or `realloc`:
3824+
TODO: mention optional
38193825
```python
38203826
def canon_lower(callee, ft, opts, flat_args: list[CoreValType]) -> list[CoreValType]:
38213827
thread = current_thread()
38223828
trap_if(not thread.task.inst.may_leave)
3829+
assert(ft.optional or callee is not None)
3830+
trap_if(callee is None)
38233831
```
38243832

38253833
The component-level function type maps to a Core WebAssembly function type using
@@ -5110,6 +5118,19 @@ prepared to propagate cancellation, they can omit `cancellable` so that
51105118
cancellation is instead delivered at a later `cancellable` call.
51115119

51125120

5121+
### `canon optional.present`
5122+
5123+
For a canonical definition:
5124+
```wat
5125+
(canon optional.present $sortidx (core global $present))
5126+
```
5127+
validation specifies:
5128+
* `$sortidx` must ... and be `optional`
5129+
* `$present` is given type `(global i32)`
5130+
5131+
TODO: describe
5132+
5133+
51135134
### 📝 `canon error-context.new`
51145135

51155136
For a canonical definition:

design/mvp/Explainer.md

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ more user-focused explanation, take a look at the
2727
* [Canonical built-ins](#canonical-built-ins)
2828
* [Resource built-ins](#resource-built-ins)
2929
* [Concurrency built-ins](#-concurrency-built-ins)
30+
* [Optionality built-ins](#-optionality-built-ins)
3031
* [Error Context built-ins](#-error-context-built-ins)
3132
* [Value definitions](#-value-definitions)
3233
* [Start definitions](#-start-definitions)
@@ -69,6 +70,7 @@ subsequent WASI Developer Preview minor releases:
6970
* 🐘: [memory64]
7071
* 🗺️: the `map` type
7172
* 🏷️: `implements` annotations for plain-named interface imports/exports
73+
* ❓: `optional` imports and exports
7274

7375

7476
## Grammar
@@ -298,6 +300,7 @@ instanceexpr ::= (instantiate <componentidx> <instantiatearg>*)
298300
| <inlineexport>*
299301
instantiatearg ::= (with <name> <sortidx>)
300302
| (with <name> (instance <inlineexport>*))
303+
| (with <name>) ❓
301304
name ::= <core:name>
302305
sortidx ::= (<sort> <u32>)
303306
sort ::= core <core:sort>
@@ -607,9 +610,13 @@ valtype ::= <typeidx>
607610
keytype ::= bool | s8 | u8 | s16 | u16 | s32 | u32 | s64 | u64 | char | string 🗺️
608611
resourcetype ::= (resource (rep i32) (dtor <core:funcidx>)?)
609612
| (resource (rep i64) (dtor <core:funcidx>)?) 🐘
610-
functype ::= (func async? (param <labellit> <valtype>)* (result <valtype>)?)
613+
functype ::= (func <optional?> <async?> (param <labellit> <valtype>)* (result <valtype>)?)
614+
optional? ::= ϵ
615+
| optional ❓
616+
async? ::= ϵ
617+
| async 🔀
611618
componenttype ::= (component <componentdecl>*)
612-
instancetype ::= (instance <instancedecl>*)
619+
instancetype ::= (instance <optional?> <instancedecl>*)
613620
componentdecl ::= <importdecl>
614621
| <instancedecl>
615622
instancedecl ::= core-prefix(<core:type>)
@@ -626,7 +633,7 @@ externtype ::= (<sort> (type <u32>) )
626633
| (value <valuebound>) 🪙
627634
| (type <typebound>)
628635
typebound ::= (eq <typeidx>)
629-
| (sub resource)
636+
| (sub <optional?> resource)
630637
valuebound ::= (eq <valueidx>) 🪙
631638
| <valtype> 🪙
632639
@@ -1298,6 +1305,9 @@ replaced by `$R` when validating the instantiations of `$c1` and `$c2`. These
12981305
type-checking rules for instantiating type imports mirror the *elimination*
12991306
rule of [universal types] (∀T).
13001307

1308+
TODO: if don't provide type, substitute incompatible type; prevent functions
1309+
from being supplied...
1310+
13011311
Importantly, this type substitution performed by the parent is not visible to
13021312
the child at validation- or run-time. In particular, there are no runtime
13031313
casts that can "see through" to the original type parameter, avoiding
@@ -1544,6 +1554,7 @@ canon ::= ...
15441554
| (canon thread.yield-then-resume cancellable? (core func <id>?)) 🧵
15451555
| (canon thread.suspend-then-promote cancellable? (core func <id>?)) 🧵
15461556
| (canon thread.yield-then-promote cancellable? (core func <id>?)) 🧵
1557+
| (canon optional.present <sortidx> (core global <id>?)) ❓
15471558
| (canon error-context.new <canonopt>* (core func <id>?)) 📝
15481559
| (canon error-context.debug-message <canonopt>* (core func <id>?)) 📝
15491560
| (canon error-context.drop (core func <id>?)) 📝
@@ -2330,6 +2341,13 @@ For details, see [`canon_thread_available_parallelism`] in the Canonical ABI
23302341
explainer.
23312342

23322343

2344+
##### ❓ Optionality built-ins
2345+
2346+
###### `optional.present`
2347+
2348+
TODO
2349+
2350+
23332351
##### 📝 Error Context built-ins
23342352

23352353
###### 📝 `error-context.new`

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)