Skip to content

Commit 50667ed

Browse files
authored
Merge pull request #467 from alexcrichton/clarify-options
Clarify validation rules of canonical options (take 2)
2 parents 8f9f881 + 5f42f93 commit 50667ed

File tree

1 file changed

+64
-11
lines changed

1 file changed

+64
-11
lines changed

design/mvp/CanonicalABI.md

Lines changed: 64 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ being specified here.
3131
* [Flat Lowering](#flat-lowering)
3232
* [Lifting and Lowering Values](#lifting-and-lowering-values)
3333
* [Canonical definitions](#canonical-definitions)
34+
* [`canonopt` Validation](#canonopt-validation)
3435
* [`canon lift`](#canon-lift)
3536
* [`canon lower`](#canon-lower)
3637
* [`canon resource.new`](#canon-resourcenew)
@@ -2705,19 +2706,51 @@ Using the above supporting definitions, we can describe the static and dynamic
27052706
semantics of component-level [`canon`] definitions. The following subsections
27062707
cover each of these `canon` cases.
27072708

2709+
### `canonopt` Validation
2710+
2711+
Canonical options, often referred to as `$opts` in the definitions below,
2712+
can be specified at most once in any particular list of options. For example
2713+
specifying `string-encoding=utf8` twice is an error. Each individual option, if
2714+
present, is validated as such:
2715+
2716+
* `string-encoding=N` - can be passed at most once, regardless of `N`.
2717+
* `memory` - this is a subtype of `(memory 1)`
2718+
* `realloc` - the function has type `(func (param i32 i32 i32 i32) (result i32))`
2719+
* if `realloc` is present, then `memory` must be present
2720+
* `post-return` - only allowed on [`canon lift`](#canon-lift), which has rules
2721+
for validation
2722+
* 🔀 `async` - cannot be present with `post-return`
2723+
* 🔀 `callback` - the function has type `(func (param i32 i32 i32 i32) (result
2724+
i32))` and cannot be present without `async` and is only allowed with [`canon
2725+
lift`](#canon-lift)
2726+
2727+
Additionally some options are required depending on lift/lower operations
2728+
performed for a component. These are defined as:
2729+
2730+
* `lower(T)`
2731+
* requires `memory` if `T` contains a `list` or `string`
2732+
2733+
* `lift(T)`
2734+
* requires `realloc` if `T` contains a `list` or `string`
2735+
2736+
27082737
### `canon lift`
27092738

27102739
For a canonical definition:
27112740
```wat
27122741
(canon lift $callee:<funcidx> $opts:<canonopt>* (func $f (type $ft)))
27132742
```
2714-
validation specifies:
2743+
2744+
In addition to [general validation of `$opts`](#canonopt-validation) the additional
2745+
validation is performed:
2746+
27152747
* `$callee` must have type `flatten_functype($opts, $ft, 'lift')`
27162748
* `$f` is given type `$ft`
2717-
* a `memory` is present if required by lifting and is a subtype of `(memory 1)`
2718-
* a `realloc` is present if required by lifting and has type `(func (param i32 i32 i32 i32) (result i32))`
2719-
* if `async` is set, a `post-return` function may not be set
27202749
* if a `post-return` is present, it has type `(func (param flatten_functype({}, $ft, 'lift').results))`
2750+
* requires options based on [`lift(param)`](#canonopt-validation) for all parameters in `ft`
2751+
* requires options based on [`lower(result)`](#canonopt-validation) if `ft` has a result
2752+
* if `len(flatten_types(ft.param_types())) > MAX_FLAT_PARAMS`, `realloc` is required
2753+
* if `len(flatten_types(ft.result_types())) > MAX_FLAT_RESULTS`, `memory` is required
27212754

27222755
When instantiating component instance `$inst`:
27232756
* Define `$f` to be the partially-bound closure `canon_lift($opts, $inst, $ft, $callee)`
@@ -2874,12 +2907,16 @@ For a canonical definition:
28742907
```wat
28752908
(canon lower $callee:<funcidx> $opts:<canonopt>* (core func $f))
28762909
```
2877-
where `$callee` has type `$ft`, validation specifies:
2910+
2911+
In addition to [general validation of `$opts`](#canonopt-validation) the additional
2912+
validation is performed where `$callee` has type `$ft`:
2913+
28782914
* `$f` is given type `flatten_functype($opts, $ft, 'lower')`
2879-
* a `memory` is present if required by lifting and is a subtype of `(memory 1)`
2880-
* a `realloc` is present if required by lifting and has type `(func (param i32 i32 i32 i32) (result i32))`
2881-
* there is no `post-return` in `$opts`
2882-
* if `contains_async_value($ft)`, then `$opts.async` must be set
2915+
* requires options [based on `lower(param)`](#canonopt-validation) for all parameters in `ft`
2916+
* requires options [based on `lift(result)`](#canonopt-validation) if `ft` has a result
2917+
* if `len(flatten_types(ft.param_types())) > max_flat_params`, `memory` is required
2918+
* if `len(flatten_types(ft.result_types())) > max_flat_results`, `realloc` is required
2919+
* 🔀 if `async` is specified, `memory` must be present
28832920

28842921
When instantiating component instance `$inst`:
28852922
* Define `$f` to be the partially-bound closure: `canon_lower($opts, $ft, $callee)`
@@ -3189,9 +3226,13 @@ For a canonical definition:
31893226
```wat
31903227
(canon task.return (result $t)? $opts (core func $f))
31913228
```
3192-
validation specifies:
3229+
3230+
In addition to [general validation of `$opts`](#canonopt-validation) validation
3231+
specifies:
3232+
31933233
* `$f` is given type `flatten_functype($opts, (func (param $t)?), 'lower')`
31943234
* `$opts` may only contain `memory` and `string-encoding`
3235+
* [`lift($f.result)` above](#canonopt-validation) defines required options
31953236

31963237
Calling `$f` invokes the following function which uses `Task.return_` to lift
31973238
and pass the results to the caller:
@@ -3450,8 +3491,12 @@ For canonical definitions:
34503491
(canon stream.read $t $opts (core func $f))
34513492
(canon stream.write $t $opts (core func $f))
34523493
```
3453-
validation specifies:
3494+
In addition to [general validation of `$opts`](#canonopt-validation) validation
3495+
specifies:
34543496
* `$f` is given type `(func (param i32 i32 i32) (result i32))`
3497+
* [`lower($t)` above](#canonopt-validation) defines required options for `stream.write`
3498+
* [`lift($t)` above](#canonopt-validation) defines required options for `stream.read`
3499+
* `memory` is required to be present
34553500

34563501
For canonical definitions:
34573502
```wat
@@ -3460,6 +3505,9 @@ For canonical definitions:
34603505
```
34613506
validation specifies:
34623507
* `$f` is given type `(func (param i32 i32) (result i32))`
3508+
* [`lower($t)` above](#canonopt-validation) defines required options for `future.write`
3509+
* [`lift($t)` above](#canonopt-validation) defines required options for `future.read`
3510+
* `memory` is required to be present
34633511

34643512
The implementation of these four built-ins all funnel down to a single
34653513
parameterized `copy` function:
@@ -3693,6 +3741,8 @@ For a canonical definition:
36933741
```
36943742
validation specifies:
36953743
* `$f` is given type `(func (param i32 i32) (result i32))`
3744+
* `async` is not present
3745+
* `memory` must be present
36963746

36973747
Calling `$f` calls the following function which uses the `$opts` immediate to
36983748
(non-deterministically) lift the debug message, create a new `ErrorContext`
@@ -3732,6 +3782,9 @@ For a canonical definition:
37323782
```
37333783
validation specifies:
37343784
* `$f` is given type `(func (param i32 i32))`
3785+
* `async` is not present
3786+
* `memory` must be present
3787+
* `realloc` must be present
37353788

37363789
Calling `$f` calls the following function which uses the `$opts` immediate to
37373790
lowers the `ErrorContext`'s debug message. While *producing* an `error-context`

0 commit comments

Comments
 (0)