Skip to content

Commit 551e876

Browse files
authored
Remove subtyping (#87)
Per the vote on #69, this PR removes subtyping from the proposal. List of changes: * Syntax: - remove `nullref` type - rename `anyref` type to `externref` - extend `ref.null` and `ref.is_null` instructions with new immediate of the form `func` or `extern` (this will later have to generalise to a `constype` per the [typed references proposal](https://github.com/WebAssembly/function-references)) * Typing rules: - `ref.null`, `ref.is_null`: determine reference type based on new immediate - `select`, `call_indirect`, `table.copy`, `table.init`: drop subtyping - `br_table`: revert to rule requiring same label types - `elem` segment: drop subtyping - `global` import: drop subtyping (link time) * Remove subtyping rules and bottom type. * Revert typing algorithm (interpreter and spec appendix). * JS API: - remove `"nullref"` - rename `"anyref"` to `"externref"` * Scripts: - rename `ref` result to `ref.extern` - rename `ref.host` value to `ref.extern` - drop subtyping from invocation type check * JS translation: - extend harness with separate eq functions for each ref type * Adjust tests: - apply syntax changes - remove tests for subtyping - change tests exercising subtyping in other ways
1 parent c0f30ca commit 551e876

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+580
-931
lines changed

document/core/appendix/algorithm.rst

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,29 +22,24 @@ Data Structures
2222
~~~~~~~~~~~~~~~
2323

2424
Types are representable as an enumeration.
25-
A simple subtyping check can be defined on these types.
2625

2726
.. code-block:: pseudo
2827
29-
type val_type = I32 | I64 | F32 | F64 | Anyref | Funcref | Nullref | Bot
28+
type val_type = I32 | I64 | F32 | F64 | Funcref | Externref
3029
3130
func is_num(t : val_type) : bool =
32-
return t = I32 || t = I64 || t = F32 || t = F64 || t = Bot
31+
return t = I32 || t = I64 || t = F32 || t = F64
3332
3433
func is_ref(t : val_type) : bool =
35-
return t = Anyref || t = Funcref || t = Nullref || t = Bot
36-
37-
func matches(t1 : val_type, t2 : val_type) : bool =
38-
return t1 = t2 || t1 = Bot ||
39-
(t1 = Nullref && is_ref(t2)) || (is_ref(t1) && t2 = Anyref)
34+
return t = Funcref || t = Externref
4035
4136
The algorithm uses two separate stacks: the *value stack* and the *control stack*.
4237
The former tracks the :ref:`types <syntax-valtype>` of operand values on the :ref:`stack <stack>`,
4338
the latter surrounding :ref:`structured control instructions <syntax-instr-control>` and their associated :ref:`blocks <syntax-instr-control>`.
4439

4540
.. code-block:: pseudo
4641
47-
type val_stack = stack(val_type)
42+
type val_stack = stack(val_type | Unknown)
4843
4944
type ctrl_stack = stack(ctrl_frame)
5045
type ctrl_frame = {
@@ -54,7 +49,8 @@ the latter surrounding :ref:`structured control instructions <syntax-instr-contr
5449
unreachable : bool
5550
}
5651
57-
For each value, the value stack records its :ref:`value type <syntax-valtype>`.
52+
For each value, the value stack records its :ref:`value type <syntax-valtype>`, or :code:`Unknown` when the type is not known.
53+
5854

5955
For each entered block, the control stack records a *control frame* with the type of the associated :ref:`label <syntax-label>` (used to type-check branches), the result type of the block (used to check its result), the height of the operand stack at the start of the block (used to check that operands do not underflow the current block), and a flag recording whether the remainder of the block is unreachable (used to handle :ref:`stack-polymorphic <polymorphism>` typing after branches).
6056

@@ -73,17 +69,19 @@ However, these variables are not manipulated directly by the main checking funct
7369

7470
.. code-block:: pseudo
7571
76-
func push_val(type : val_type) =
72+
func push_val(type : val_type | Unknown) =
7773
vals.push(type)
7874
79-
func pop_val() : val_type =
80-
if (vals.size() = ctrls[0].height && ctrls[0].unreachable) return Bot
75+
func pop_val() : val_type | Unknown =
76+
if (vals.size() = ctrls[0].height && ctrls[0].unreachable) return Unknown
8177
error_if(vals.size() = ctrls[0].height)
8278
return vals.pop()
8379
84-
func pop_val(expect : val_type) : val_type =
80+
func pop_val(expect : val_type | Unknown) : val_type | Unknown =
8581
let actual = pop_val()
86-
error_if(not matches(actual, expect))
82+
if (actual = Unknown) return expect
83+
if (expect = Unknown) return actual
84+
error_if(actual =/= expect)
8785
return actual
8886
8987
func push_vals(types : list(val_type)) = foreach (t in types) push_val(t)
@@ -97,10 +95,10 @@ Pushing an operand value simply pushes the respective type to the value stack.
9795
Popping an operand value checks that the value stack does not underflow the current block and then removes one type.
9896
But first, a special case is handled where the block contains no known values, but has been marked as unreachable.
9997
That can occur after an unconditional branch, when the stack is typed :ref:`polymorphically <polymorphism>`.
100-
In that case, the :code:`Bot` type is returned, because that is a *principal* choice trivially satisfying all use constraints.
98+
In that case, an unknown type is returned.
10199

102100
A second function for popping an operand value takes an expected type, which the actual operand type is checked against.
103-
The types may differ by subtyping, including the case where the actual type is :code:`Bot`, and thereby matches unconditionally.
101+
The types may differ in case one of them is Unknown.
104102
The function returns the actual type popped from the stack.
105103

106104
Finally, there are accumulative functions for pushing or popping multiple operand types.
@@ -143,7 +141,7 @@ In that case, all existing operand types are purged from the value stack, in ord
143141
.. note::
144142
Even with the unreachable flag set, consecutive operands are still pushed to and popped from the operand stack.
145143
That is necessary to detect invalid :ref:`examples <polymorphism>` like :math:`(\UNREACHABLE~(\I32.\CONST)~\I64.\ADD)`.
146-
However, a polymorphic stack cannot underflow, but instead generates :code:`Bot` types as needed.
144+
However, a polymorphic stack cannot underflow, but instead generates :code:`Unknown` types as needed.
147145

148146

149147
.. index:: opcode
@@ -175,8 +173,8 @@ Other instructions are checked in a similar manner.
175173
let t1 = pop_val()
176174
let t2 = pop_val()
177175
error_if(not (is_num(t1) && is_num(t2)))
178-
error_if(t1 =/= t2 && t1 =/= Bot && t2 =/= Bot)
179-
push_val(if (t1 = Bot) t2 else t1)
176+
error_if(t1 =/= t2 && t1 =/= Unknown && t2 =/= Unknown)
177+
push_val(if (t1 = Unknown) t2 else t1)
180178
181179
case (select t)
182180
pop_val(I32)
@@ -217,14 +215,11 @@ Other instructions are checked in a similar manner.
217215
      push_vals(ctrls[n].label_types)
218216
219217
   case (br_table n* m)
220-
pop_val(I32)
221218
      error_if(ctrls.size() < m)
222-
let arity = ctrls[m].label_types.size()
223219
      foreach (n in n*)
224-
        error_if(ctrls.size() < n)
225-
        error_if(ctrls[n].label_types.size() =/= arity)
226-
push_vals(pop_vals(ctrls[n].label_types))
227-
pop_vals(ctrls[m].label_types)
220+
        error_if(ctrls.size() < n || ctrls[n].label_types =/= ctrls[m].label_types)
221+
pop_val(I32)
222+
      pop_vals(ctrls[m].label_types)
228223
      unreachable()
229224
230225
.. note::

document/core/appendix/index-instructions.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,8 +215,8 @@ Instruction Binary Opcode Type
215215
(reserved) :math:`\hex{CD}`
216216
(reserved) :math:`\hex{CE}`
217217
(reserved) :math:`\hex{CF}`
218-
:math:`\REFNULL` :math:`\hex{D0}` :math:`[] \to [\NULLREF]` :ref:`validation <valid-ref.null>` :ref:`execution <exec-ref.null>`
219-
:math:`\REFISNULL` :math:`\hex{D1}` :math:`[\ANYREF] \to [\I32]` :ref:`validation <valid-ref.is_null>` :ref:`execution <exec-ref.is_null>`
218+
:math:`\REFNULL~t` :math:`\hex{D0}` :math:`[] \to [t]` :ref:`validation <valid-ref.null>` :ref:`execution <exec-ref.null>`
219+
:math:`\REFISNULL~t` :math:`\hex{D1}` :math:`[t] \to [\I32]` :ref:`validation <valid-ref.is_null>` :ref:`execution <exec-ref.is_null>`
220220
:math:`\REFFUNC~x` :math:`\hex{D2}` :math:`[] \to [\FUNCREF]` :ref:`validation <valid-ref.func>` :ref:`execution <exec-ref.func>`
221221
:math:`\MEMORYINIT` :math:`\hex{FC08}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation <valid-memory.init>` :ref:`execution <exec-memory.init>`
222222
:math:`\DATADROP` :math:`\hex{FC09}` :math:`[] \to []` :ref:`validation <valid-data.drop>` :ref:`execution <exec-data.drop>`

document/core/appendix/index-rules.rst

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,6 @@ Matching
8282
=============================================== ===============================================================================
8383
Construct Judgement
8484
=============================================== ===============================================================================
85-
:ref:`Number type <match-numtype>` :math:`\vdashnumtypematch \numtype_1 \matchesvaltype \numtype_2`
86-
:ref:`Reference type <match-reftype>` :math:`\vdashreftypematch \reftype_1 \matchesvaltype \reftype_2`
87-
:ref:`Value type <match-valtype>` :math:`\vdashvaltypematch \valtype_1 \matchesvaltype \valtype_2`
88-
:ref:`Result type <match-resulttype>` :math:`\vdashresulttypematch [t_1^?] \matchesresulttype [t_2^?]`
8985
:ref:`External type <match-externtype>` :math:`\vdashexterntypematch \externtype_1 \matchesexterntype \externtype_2`
9086
:ref:`Limits <match-limits>` :math:`\vdashlimitsmatch \limits_1 \matcheslimits \limits_2`
9187
=============================================== ===============================================================================

document/core/appendix/index-types.rst

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@ Category Constructor
1414
:ref:`Number type <syntax-numtype>` |F64| :math:`\hex{7C}` (-4 as |Bs7|)
1515
(reserved) :math:`\hex{7B}` .. :math:`\hex{71}`
1616
:ref:`Reference type <syntax-reftype>` |FUNCREF| :math:`\hex{70}` (-16 as |Bs7|)
17-
:ref:`Reference type <syntax-reftype>` |ANYREF| :math:`\hex{6F}` (-17 as |Bs7|)
18-
:ref:`Reference type <syntax-reftype>` |NULLREF| :math:`\hex{6E}` (-18 as |Bs7|)
19-
(reserved) :math:`\hex{6D}` .. :math:`\hex{61}`
17+
:ref:`Reference type <syntax-reftype>` |EXTERNREF| :math:`\hex{6F}` (-17 as |Bs7|)
18+
(reserved) :math:`\hex{6E}` .. :math:`\hex{61}`
2019
:ref:`Function type <syntax-functype>` :math:`[\valtype^\ast] \to [\valtype^\ast]` :math:`\hex{60}` (-32 as |Bs7|)
2120
(reserved) :math:`\hex{5F}` .. :math:`\hex{41}`
2221
:ref:`Result type <syntax-resulttype>` :math:`[\epsilon]` :math:`\hex{40}` (-64 as |Bs7|)

document/core/appendix/properties.rst

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,7 @@ Module instances are classified by *module contexts*, which are regular :ref:`co
215215

216216
* For each :ref:`reference <syntax-ref>` :math:`\reff_i` in the table's elements :math:`\reff^n`:
217217

218-
* The :ref:`reference <syntax-ref>` :math:`\reff_i` must be :ref:`valid <valid-ref>` with some :ref:`reference type <syntax-reftype>` :math:`t'_i`.
219-
220-
* The :ref:`reference type <syntax-reftype>` :math:`t'_i` must :ref:`match <match-reftype>` the :ref:`reference type <syntax-reftype>` :math:`t`.
218+
* The :ref:`reference <syntax-ref>` :math:`\reff_i` must be :ref:`valid <valid-ref>` with :ref:`reference type <syntax-reftype>` :math:`t`.
221219

222220
* Then the table instance is valid with :ref:`table type <syntax-tabletype>` :math:`\limits~t`.
223221

@@ -227,9 +225,7 @@ Module instances are classified by *module contexts*, which are regular :ref:`co
227225
\qquad
228226
n = \limits.\LMIN
229227
\qquad
230-
(S \vdash \reff : t')^n
231-
\qquad
232-
(\vdashreftypematch t' \matchesvaltype t)^n
228+
(S \vdash \reff : t)^n
233229
}{
234230
S \vdashtableinst \{ \TITYPE~(\limits~t), \TIELEM~\reff^n \} : \limits~t
235231
}
@@ -265,19 +261,15 @@ Module instances are classified by *module contexts*, which are regular :ref:`co
265261

266262
* The :ref:`global type <syntax-globaltype>` :math:`\mut~t` must be :ref:`valid <valid-globaltype>`.
267263

268-
* The :ref:`value <syntax-val>` :math:`\val` must be :ref:`valid <valid-val>` with some :ref:`value type <syntax-valtype>` :math:`t'`.
269-
270-
* The :ref:`value type <syntax-valtype>` :math:`t'` must :ref:`match <match-valtype>` the :ref:`value type <syntax-valtype>` :math:`t`.
264+
* The :ref:`value <syntax-val>` :math:`\val` must be :ref:`valid <valid-val>` with :ref:`value type <syntax-valtype>` :math:`t`.
271265

272266
* Then the global instance is valid with :ref:`global type <syntax-globaltype>` :math:`\mut~t`.
273267

274268
.. math::
275269
\frac{
276270
\vdashglobaltype \mut~t \ok
277271
\qquad
278-
S \vdashval \val : t'
279-
\qquad
280-
\vdashvaltypematch t' \matchesvaltype t
272+
S \vdashval \val : t
281273
}{
282274
S \vdashglobalinst \{ \GITYPE~(\mut~t), \GIVALUE~\val \} : \mut~t
283275
}
@@ -291,17 +283,13 @@ Module instances are classified by *module contexts*, which are regular :ref:`co
291283

292284
* For each :ref:`reference <syntax-ref>` :math:`\reff_i` in the elements :math:`\reff^n`:
293285

294-
* The :ref:`reference <syntax-ref>` :math:`\reff_i` must be :ref:`valid <valid-ref>` with some :ref:`reference type <syntax-reftype>` :math:`t'_i`.
295-
296-
* The :ref:`reference type <syntax-reftype>` :math:`t'_i` must :ref:`match <match-reftype>` the :ref:`reference type <syntax-reftype>` :math:`t`.
286+
* The :ref:`reference <syntax-ref>` :math:`\reff_i` must be :ref:`valid <valid-ref>` with :ref:`reference type <syntax-reftype>` :math:`t`.
297287

298288
* Then the table instance is valid.
299289

300290
.. math::
301291
\frac{
302-
(S \vdash \reff : t')^\ast
303-
\qquad
304-
(\vdashreftypematch t' \matchesvaltype t)^\ast
292+
(S \vdash \reff : t)^\ast
305293
}{
306294
S \vdasheleminst \{ \EITYPE~t, \EIELEM~\reff^\ast \} \ok
307295
}
@@ -535,17 +523,17 @@ To that end, all previous typing judgements :math:`C \vdash \X{prop}` are genera
535523
}
536524
537525
538-
.. index:: host address
526+
.. index:: extern address
539527

540-
:math:`\REFHOST~\hostaddr`
541-
..........................
528+
:math:`\REFEXTERNADDR~\externaddr`
529+
..................................
542530

543-
* The instruction is valid with type :math:`[] \to [\ANYREF]`.
531+
* The instruction is valid with type :math:`[] \to [\EXTERNREF]`.
544532

545533
.. math::
546534
\frac{
547535
}{
548-
S; C \vdashadmininstr \REFHOST~\hostaddr : [] \to [\ANYREF]
536+
S; C \vdashadmininstr \REFEXTERNADDR~\externaddr : [] \to [\EXTERNREF]
549537
}
550538
551539

document/core/binary/instructions.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ Reference Instructions
7676
.. math::
7777
\begin{array}{llclll}
7878
\production{instruction} & \Binstr &::=& \dots \\ &&|&
79-
\hex{D0} &\Rightarrow& \REFNULL \\ &&|&
80-
\hex{D1} &\Rightarrow& \REFISNULL \\ &&|&
79+
\hex{D0}~~t{:}\Breftype &\Rightarrow& \REFNULL~t \\ &&|&
80+
\hex{D1}~~t{:}\Breftype &\Rightarrow& \REFISNULL~t \\ &&|&
8181
\hex{D2}~~x{:}\Bfuncidx &\Rightarrow& \REFFUNC~x \\
8282
\end{array}
8383

document/core/binary/types.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ Reference Types
4242
\begin{array}{llclll@{\qquad\qquad}l}
4343
\production{reference type} & \Breftype &::=&
4444
\hex{70} &\Rightarrow& \FUNCREF \\ &&|&
45-
\hex{6F} &\Rightarrow& \ANYREF \\ &&|&
46-
\hex{6E} &\Rightarrow& \NULLREF \\
45+
\hex{6F} &\Rightarrow& \EXTERNREF \\
4746
\end{array}
4847
4948

document/core/exec/instructions.rst

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -192,25 +192,25 @@ Reference Instructions
192192

193193
.. _exec-ref.null:
194194

195-
:math:`\REFNULL`
196-
................
195+
:math:`\REFNULL~t`
196+
..................
197197

198-
1. Push the value :math:`\REFNULL` to the stack.
198+
1. Push the value :math:`\REFNULL~t` to the stack.
199199

200200
.. note::
201201
No formal reduction rule is required for this instruction, since the |REFNULL| instruction is already a :ref:`value <syntax-val>`.
202202

203203

204204
.. _exec-ref.is_null:
205205

206-
:math:`\REFISNULL`
207-
..................
206+
:math:`\REFISNULL~t`
207+
....................
208208

209209
1. Assert: due to :ref:`validation <valid-ref.is_null>`, a :ref:`reference value <syntax-ref>` is on the top of the stack.
210210

211211
2. Pop the value :math:`\val` from the stack.
212212

213-
3. If :math:`\val` is |REFNULL|, then:
213+
3. If :math:`\val` is :math:`\REFNULL~t`, then:
214214

215215
a. Push the value :math:`\I32.\CONST~1` to the stack.
216216

@@ -220,10 +220,10 @@ Reference Instructions
220220

221221
.. math::
222222
\begin{array}{lcl@{\qquad}l}
223-
\val~\REFISNULL &\stepto& \I32.\CONST~1
224-
& (\iff \val = \REFNULL) \\
225-
\val~\REFISNULL &\stepto& \I32.\CONST~0
226-
& (\iff \val \neq \REFNULL) \\
223+
\val~\REFISNULL~t &\stepto& \I32.\CONST~1
224+
& (\iff \val = \REFNULL~t) \\
225+
\val~\REFISNULL~t &\stepto& \I32.\CONST~0
226+
& (\otherwise) \\
227227
\end{array}
228228
229229
@@ -1768,7 +1768,7 @@ Control Instructions
17681768

17691769
11. Let :math:`r` be the :ref:`reference <syntax-ref>` :math:`\X{tab}.\TIELEM[i]`.
17701770

1771-
12. If :math:`r` is |REFNULL|, then:
1771+
12. If :math:`r` is :math:`\REFNULL~t`, then:
17721772

17731773
a. Trap.
17741774

document/core/exec/modules.rst

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -110,15 +110,15 @@ The following auxiliary typing rules specify this typing relation relative to a
110110
111111
.. _valid-ref:
112112

113-
:ref:`Null References <syntax-ref>` :math:`\REFNULL`
114-
....................................................
113+
:ref:`Null References <syntax-ref>` :math:`\REFNULL~t`
114+
......................................................
115115

116-
* The value is valid with :ref:`reference type <syntax-reftype>` :math:`\NULLREF`.
116+
* The value is valid with :ref:`reference type <syntax-reftype>` :math:`t`.
117117

118118
.. math::
119119
\frac{
120120
}{
121-
S \vdashval \REFNULL : \NULLREF
121+
S \vdashval \REFNULL~t : t
122122
}
123123
124124
@@ -137,15 +137,15 @@ The following auxiliary typing rules specify this typing relation relative to a
137137
}
138138
139139
140-
:ref:`Host References <syntax-ref.host>` :math:`\REFHOST~a`
141-
...........................................................
140+
:ref:`External References <syntax-ref.extern>` :math:`\REFEXTERNADDR~a`
141+
.......................................................................
142142

143-
* The value is valid with :ref:`reference type <syntax-reftype>` :math:`\ANYREF`.
143+
* The value is valid with :ref:`reference type <syntax-reftype>` :math:`\EXTERNREF`.
144144

145145
.. math::
146146
\frac{
147147
}{
148-
S \vdashval \REFHOST~a : \ANYREF
148+
S \vdashval \REFEXTERNADDR~a : \EXTERNREF
149149
}
150150
151151
@@ -447,7 +447,10 @@ and list of :ref:`reference <syntax-ref>` vectors for the module's :ref:`element
447447

448448
3. For each :ref:`table <syntax-table>` :math:`\table_i` in :math:`\module.\MTABLES`, do:
449449

450-
a. Let :math:`\tableaddr_i` be the :ref:`table address <syntax-tableaddr>` resulting from :ref:`allocating <alloc-table>` :math:`\table_i.\TTYPE`.
450+
a. Let :math:`\limits_i~t_i` be the :ref:`table type <syntax-tabletype>` :math:`\table_i.\TTYPE`.
451+
452+
b. Let :math:`\tableaddr_i` be the :ref:`table address <syntax-tableaddr>` resulting from :ref:`allocating <alloc-table>` :math:`\table_i.\TTYPE`
453+
with initialization value :math:`\REFNULL~t_i`.
451454

452455
4. For each :ref:`memory <syntax-mem>` :math:`\mem_i` in :math:`\module.\MMEMS`, do:
453456

@@ -526,8 +529,9 @@ where:
526529
\MIEXPORTS~\exportinst^\ast ~\}
527530
\end{array} \\[1ex]
528531
S_1, \funcaddr^\ast &=& \allocfunc^\ast(S, \module.\MFUNCS, \moduleinst) \\
529-
S_2, \tableaddr^\ast &=& \alloctable^\ast(S_1, (\table.\TTYPE)^\ast, \REFNULL)
530-
\qquad\qquad\qquad~ (\where \table^\ast = \module.\MTABLES) \\
532+
S_2, \tableaddr^\ast &=& \alloctable^\ast(S_1, (\table.\TTYPE)^\ast, \REFNULL~t)
533+
\qquad\qquad\qquad~ (\where \table^\ast = \module.\MTABLES \\ &&
534+
\qquad\qquad\qquad~~ \wedge (\table.\TTYPE)^\ast = (\limits~t)^\ast) \\
531535
S_3, \memaddr^\ast &=& \allocmem^\ast(S_2, (\mem.\MTYPE)^\ast)
532536
\qquad\qquad\qquad~ (\where \mem^\ast = \module.\MMEMS) \\
533537
S_4, \globaladdr^\ast &=& \allocglobal^\ast(S_3, (\global.\GTYPE)^\ast, \val^\ast)

0 commit comments

Comments
 (0)