Skip to content

Commit f7c2303

Browse files
authored
Clarify 'alias outer' rules (#675)
1 parent 269f5d2 commit f7c2303

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
@@ -339,10 +339,13 @@ there are three kinds of "targets" for an alias: the `export` of a component
339339
instance, the `core export` of a core module instance and a definition of an
340340
`outer` component (containing the current component):
341341
```ebnf
342-
alias ::= (alias <aliastarget> (<sort> <id>?))
343-
aliastarget ::= export <instanceidx> <name>
344-
| core export <core:instanceidx> <core:name>
345-
| outer <u32> <u32>
342+
alias ::= (alias export <instanceidx> <name> (<sort> <id>?))
343+
| (alias core export <core:instanceidx> <core:name> (core <core:sort> <id>?))
344+
| (alias outer <u32> <u32> (<outeraliassort> <id>?))
345+
outeraliassort ::= core module
346+
| core type
347+
| component
348+
| type
346349
```
347350
If present, the `id` of the alias is bound to the new index added by the alias
348351
and can be used anywhere a normal `id` can be used.
@@ -352,37 +355,44 @@ target instance and has a matching sort.
352355

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

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

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

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

@@ -3322,7 +3371,6 @@ For some use-case-focused, worked examples, see:
33223371

33233372
[Kebab Case]: https://en.wikipedia.org/wiki/Letter_case#Kebab_case
33243373
[De Bruijn Index]: https://en.wikipedia.org/wiki/De_Bruijn_index
3325-
[Closure]: https://en.wikipedia.org/wiki/Closure_(computer_programming)
33263374
[Empty Type]: https://en.wikipedia.org/w/index.php?title=Empty_type
33273375
[IEEE754]: https://en.wikipedia.org/wiki/IEEE_754
33283376
[Unicode Scalar Values]: https://unicode.org/glossary/#unicode_scalar_value
@@ -3338,6 +3386,7 @@ For some use-case-focused, worked examples, see:
33383386
[Existential Types]: https://en.wikipedia.org/wiki/System_F
33393387
[Unit]: https://en.wikipedia.org/wiki/Unit_type
33403388
[Trampolines]: https://en.wikipedia.org/wiki/Trampoline_(computing)
3389+
[Free Variables]: https://en.wikipedia.org/wiki/Free_variables_and_bound_variables
33413390

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

0 commit comments

Comments
 (0)