Skip to content

Commit 7eed4ab

Browse files
committed
Remove 'across component boundaries' exception, add example and test
1 parent 3ba5089 commit 7eed4ab

3 files changed

Lines changed: 352 additions & 72 deletions

File tree

design/mvp/Binary.md

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -116,24 +116,23 @@ Notes:
116116

117117
(See [Alias Definitions](Explainer.md#alias-definitions) in the explainer.)
118118
```ebnf
119-
alias ::= s:<sort> t:<aliastarget> => (alias t (s))
120-
aliastarget ::= 0x00 i:<instanceidx> n:<name> => export i n
121-
| 0x01 i:<core:instanceidx> n:<core:name> => core export i n
122-
| 0x02 ct:<u32> idx:<u32> => outer ct idx
119+
alias ::= s:<sort> 0x00 i:<instanceidx> n:<name> => (alias export i n (s))
120+
| s:<sort> 0x01 i:<core:instanceidx> n:<core:name> => (alias core export i n (s))
121+
| s:<sort> 0x02 ct:<u32> idx:<u32> => (alias outer ct idx (s)) (if s in outeraliassort)
123122
```
124123
Notes:
125124
* Reused Core binary rules: (variable-length encoded) [`core:u32`]
126-
* For `export` aliases, `i` is validated to refer to an instance in the
127-
instance index space that exports `n` with the specified `sort`.
128-
* For `outer` aliases, `ct` is validated to be *less or equal than* the number
129-
of enclosing `component`s and `type`s and `i` is validated to be a valid index
130-
in the `sort` index space of the targeted `component`/`type` (counting
131-
outward, starting with `0` referring to the current `component`/`type`).
132-
* For `outer` aliases, validation restricts the `sort` to one of `type`,
133-
`module` or `component`.
134-
* For `outer` aliases that reach across a `component` boundary (as opposed to
135-
a `type` boundary), validation additionally requires that any outer-aliased
136-
`type` does not transitively refer to a `resource` type.
125+
* For (`core`) `export` aliases, `i` is validated to refer to a (core) instance
126+
in the (core) instance index space that exports `n` with the specified `sort`.
127+
* For `outer` aliases:
128+
* `ct` is validated to be *less than or equal to* the number of enclosing
129+
"scopes" (where a "scope" is one of: a `component` definition, a `component`
130+
type, an `instance` type)
131+
* `i` is validated to be a valid index in the `s` index space of the target
132+
scope (counting outward, starting with `0` referring to the current scope)
133+
* if `ct` is greater than 0 and crosses a component (as opposed to type)
134+
boundary and `s` is `type`, the target type may not transitively refer to a
135+
resource type.
137136

138137

139138
## Type Definitions
@@ -149,8 +148,7 @@ core:moduledecl ::= 0x00 i:<core:import> => i
149148
| 0x01 t:<core:type> => t
150149
| 0x02 a:<core:alias> => a
151150
| 0x03 e:<core:exportdecl> => e
152-
core:alias ::= s:<core:sort> t:<core:aliastarget> => (alias t (s))
153-
core:aliastarget ::= 0x01 ct:<u32> idx:<u32> => outer ct idx
151+
core:alias ::= 0x10 0x01 ct:<u32> idx:<u32> => (alias outer ct idx (type))
154152
core:importdecl ::= i:<core:import> => i
155153
core:exportdecl ::= n:<core:name> t:<core:externtype> => (export n t)
156154
```
@@ -171,8 +169,9 @@ Notes:
171169
core type index space will not contain any core module types.
172170
* As described in the explainer, each module type is validated with an
173171
initially-empty type index space.
174-
* `alias` declarators currently only allow `outer` `type` aliases but
175-
would add `export` aliases when core wasm adds type exports.
172+
* In `core:alias`, the first `0x10` is the opcode for `type` in `core:sort` and
173+
`0x01` is an opcode to distinguish `outer` aliases from potential future
174+
`export` aliases.
176175

177176
```ebnf
178177
type ::= dt:<deftype> => (type dt)
@@ -260,11 +259,13 @@ Notes:
260259
[TODO](Concurrency.md#TODO).
261260
* Validation of `resourcetype` requires the destructor (if present) to have
262261
type `[i32] -> []`.
263-
* Validation of `instancedecl` (currently) only allows the `type` and
264-
`instance` sorts in `alias` declarators.
262+
* In addition to the validation rules for `alias` *definitions* mentioned above,
263+
validation of `alias` *declarators* also requires:
264+
* `export` aliases only alias the `instance` and `type` sorts
265+
* `outer` aliases only alias the `core type` and `type` sorts
265266
* As described in the explainer, each component and instance type is validated
266-
with an initially-empty type index space. Outer aliases can be used to pull
267-
in type definitions from containing components.
267+
with an initially-empty type index space. (Outer aliases can be used to pull
268+
in type definitions from containing `component` and `type` scopes.)
268269
* `exportdecl` introduces a new type index that can be used by subsequent type
269270
definitions. In the `(eq i)` case, the new type index is effectively an alias
270271
to type `i`. In the `(sub resource)` case, the new type index refers to a

design/mvp/Explainer.md

Lines changed: 98 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -338,10 +338,13 @@ there are three kinds of "targets" for an alias: the `export` of a component
338338
instance, the `core export` of a core module instance and a definition of an
339339
`outer` component (containing the current component):
340340
```ebnf
341-
alias ::= (alias <aliastarget> (<sort> <id>?))
342-
aliastarget ::= export <instanceidx> <name>
343-
| core export <core:instanceidx> <core:name>
344-
| outer <u32> <u32>
341+
alias ::= (alias export <instanceidx> <name> (<sort> <id>?))
342+
| (alias core export <core:instanceidx> <core:name> (core <core:sort> <id>?))
343+
| (alias outer <u32> <u32> (<outeraliassort> <id>?))
344+
outeraliassort ::= core module
345+
| core type
346+
| component
347+
| type
345348
```
346349
If present, the `id` of the alias is bound to the new index added by the alias
347350
and can be used anywhere a normal `id` can be used.
@@ -351,37 +354,44 @@ target instance and has a matching sort.
351354

352355
In the case of `outer` aliases, the `u32` pair serves as a [de Bruijn index],
353356
with the first `u32` being the number of enclosing `component`s or `type`s to
354-
skip and the second `u32` being an index into the target's sort's index space.
355-
In particular, the first `u32` can be `0`, in which case the outer alias refers
356-
to the current `component`/`type`. To maintain the acyclicity of module
357-
instantiation, outer aliases are only allowed to refer to *preceding* outer
358-
definitions.
359-
360-
Components containing outer aliases effectively produce a [closure] at
361-
instantiation time, including a copy of the outer-aliased definitions. Because
362-
components, like modules, are pure values, outer aliases that reach across
363-
`component` boundaries are restricted to only refer to pure definitions:
364-
modules, components, and types that do not transitively refer to a `resource`
365-
type. (As described in the next section, resource types are *generative* and
366-
thus not pure.) For example, in the following component, `$alias{1,2,3,4,5}` are
367-
allowed (b/c they only reach across a `type` boundary) while `$alias{6,7}` are
368-
disallowed (b/c they reach across a `component` boundary):
357+
skip and the second `u32` being an index into the target's `outeraliassort`'s
358+
index space. In particular, the first `u32` can be `0`, in which case the outer
359+
alias refers to the current `component`/`type`. To maintain the acyclicity of
360+
module instantiation, outer aliases are only allowed to refer to *preceding*
361+
outer definitions. `outer` aliases are currently restricted to only refer to
362+
the 4 `outeraliassort`s, as opposed to the full set of `sort`s, but this
363+
may be relaxed in the future if needed.
364+
365+
To ensure that nested components can be arbitrarily "unbundled" (transforming
366+
inline `component` definitions into `import`s of out-of-line `component`
367+
definitions), `outer` aliases that cross component boundaries must only refer to
368+
definitions that can be substituted inline, if needed for unbundling. Of the
369+
available `outeraliassort`s: `core module`, `core type` and `component`
370+
definitions are *always* substitutable. However, due to the *generativity* of
371+
`resource` types (discussed in the next section), `type` definitions that
372+
transitively refer to a `resource` type may *not* be `outer`-aliased and are
373+
thus rejected by validation.
374+
375+
For example, in the following component, `$T2` and `$T3` cannot be `outer`-
376+
aliased by `$E`:
369377
```wat
370378
(component $C
371379
(component $D)
372-
(type $T (record (field "x" u32) (field "y" u32)))
373-
(type $R (resource (rep i32)))
374-
(type $B (borrow $R))
375-
(type (component
376-
(alias outer $C $T (type $alias1))
377-
(alias outer $C $R (type $alias2))
378-
(alias outer $C $B (type $alias3))
379-
))
380-
(component
381-
(alias outer $C $D (component $alias4))
382-
(alias outer $C $T (type $alias5))
383-
;; (alias outer $C $R (type $alias6)) ❌
384-
;; (alias outer $C $B (type $alias7)) ❌
380+
(type $T1 (record (field "x" u32) (field "y" u32)))
381+
(type $T2 (resource (rep i32)))
382+
(type $T3 (borrow $T2))
383+
(import "f" (func $f))
384+
(alias outer $C $D (component $D'))
385+
(alias outer $C $T1 (type $T1'))
386+
(alias outer $C $T2 (type $T2'))
387+
(alias outer $C $T3 (type $T3'))
388+
;; (alias outer $C $f (func $f)) ❌ 'func' not in 'outeraliassort'
389+
(component $E
390+
(alias outer $C $D (component $D))
391+
(alias outer $C $T1 (type $T1))
392+
;; (alias outer $C $T2 (type $T2)) ❌ resource type
393+
;; (alias outer $C $T3 (type $T3)) ❌ refers to resource type
394+
;; (alias outer $C $f (func $f)) ❌ 'func' not in 'outeraliassort'
385395
)
386396
)
387397
```
@@ -492,8 +502,7 @@ core:moduledecl ::= <core:importdecl>
492502
| <core:type>
493503
| <core:alias>
494504
| <core:exportdecl>
495-
core:alias ::= (alias <core:aliastarget> (<core:sort> <id>?))
496-
core:aliastarget ::= outer <u32> <u32>
505+
core:alias ::= (alias outer <u32> <u32> (type <id>?))
497506
core:importdecl ::= (import <core:name> <core:name> <core:externtype>)
498507
core:exportdecl ::= (export <core:name> strip-id(<core:externtype>))
499508
@@ -539,11 +548,9 @@ In this example, `$M` has a distinct type index space from `$C`, where element
539548
implicitly-created `func` type referring to both.
540549

541550
Lastly, the `core:alias` module declarator allows a module type definition to
542-
reuse (rather than redefine) type definitions in the enclosing component's core
543-
type index space via `outer` `type` alias. In the MVP, validation restricts
544-
`core:alias` module declarators to *only* allow `outer` `type` aliases (into an
545-
enclosing component's or component-type's core type index space). In the
546-
future, more kinds of aliases would be meaningful and allowed.
551+
reuse (rather than redefine) `type` definitions in the enclosing component's
552+
`core type` index space via `outer` alias. In the future, more kinds and sorts
553+
of aliases may be useful and added.
547554

548555
As an example, the following component defines two semantically-equivalent
549556
module types, where the former defines the function type via `type` declarator
@@ -914,20 +921,62 @@ to some preceding type definition. This allows:
914921
could generate in C++ a `typedef std::vector<uint64_t> bytes` or in JS an
915922
exported field named `bytes` that aliases `Uint64Array`.
916923

917-
Relaxing the restrictions of `core:alias` declarators mentioned above, `alias`
918-
declarators allow both `outer` and `export` aliases of `type` and `instance`
919-
sorts. This allows the type exports of `instance`-typed import and export
920-
declarators to be used by subsequent declarators in the type:
924+
The `alias` declarator reuses the syntax for component-level `alias` definitions
925+
so that `export` and `outer` aliases can be used inside `component` and
926+
`instance` *types*. For example, `export` aliases are necessary to define the
927+
type of a component that uses an imported `resource` type in an exported
928+
function parameter type:
921929
```wat
922930
(component
923-
(import "fancy-fs" (instance $fancy-fs
924-
(export "fs" (instance $fs
931+
(type $CT (component
932+
(import "fs" (instance $fs
925933
(export "file" (type (sub resource)))
926-
;; ...
934+
;; file methods
927935
))
928-
(alias export $fs "file" (type $file))
929-
(export "fancy-op" (func (param "f" (borrow $file))))
936+
(alias export $fs "file" (type $fileT))
937+
(export "process" (func (param "file" (borrow $fileT))))
938+
))
939+
(import "fs-component" (component (type $CT)))
940+
)
941+
```
942+
Similarly, `outer` aliases are necessary to define an `instance` or `component`
943+
type that uses a `resource` type defined or imported by the containing
944+
component, since `instance` and `component` types start with empty type index
945+
spaces:
946+
```wat
947+
(component $C
948+
(import "r" (type $R (sub resource)))
949+
(type $IT (instance
950+
(alias outer $C $R (type $R))
951+
(export "process" (func (param "input" (borrow $R))))
930952
))
953+
(import "uses-r" (instance (type $IT)))
954+
)
955+
```
956+
In terms of validation, `alias` declarators inherit all the previously-mentioned
957+
validation rules of `alias` definitions and add the following rules:
958+
* `alias export` declarators may only alias the `instance` and `type` sorts
959+
* `alias outer` declarators may only alias the `core type` and `type` sorts
960+
961+
```wat
962+
(component $C
963+
(component $D)
964+
(type $T1 (record (field "x" u32) (field "y" u32)))
965+
(type $T2 (resource (rep i32)))
966+
(type $T3 (borrow $T2))
967+
(type (component
968+
;; (alias outer $C $D (component $D)) ❌ not allowed inside type
969+
(alias outer $C $T1 (type $T1))
970+
(alias outer $C $T2 (type $T2))
971+
(alias outer $C $T3 (type $T3))
972+
))
973+
(component
974+
(type (component
975+
(alias outer $C $T1 (type $T1))
976+
;; (alias outer $C $T2 (type $T2)) ❌ resource type
977+
;; (alias outer $C $T3 (type $T3)) ❌ refers to resource type
978+
))
979+
)
931980
)
932981
```
933982

@@ -3290,7 +3339,6 @@ For some use-case-focused, worked examples, see:
32903339

32913340
[Kebab Case]: https://en.wikipedia.org/wiki/Letter_case#Kebab_case
32923341
[De Bruijn Index]: https://en.wikipedia.org/wiki/De_Bruijn_index
3293-
[Closure]: https://en.wikipedia.org/wiki/Closure_(computer_programming)
32943342
[Empty Type]: https://en.wikipedia.org/w/index.php?title=Empty_type
32953343
[IEEE754]: https://en.wikipedia.org/wiki/IEEE_754
32963344
[Unicode Scalar Values]: https://unicode.org/glossary/#unicode_scalar_value
@@ -3306,6 +3354,7 @@ For some use-case-focused, worked examples, see:
33063354
[Existential Types]: https://en.wikipedia.org/wiki/System_F
33073355
[Unit]: https://en.wikipedia.org/wiki/Unit_type
33083356
[Trampolines]: https://en.wikipedia.org/wiki/Trampoline_(computing)
3357+
[Free Variables]: https://en.wikipedia.org/wiki/Free_variables_and_bound_variables
33093358

33103359
[Generative]: https://www.researchgate.net/publication/2426300_A_Syntactic_Theory_of_Type_Generativity_and_Sharing
33113360
[Avoidance Problem]: https://counterexamples.org/avoidance.html

0 commit comments

Comments
 (0)