Source code

Revision control

Copy as Markdown

Other Tools

function simpleTypeSection(types) {
return types.map((x, i) => `(type \$${i} ${x})`).join('\n');
}
function assertSubtype(superType, subType, types) {
types = types || [];
wasmEvalText(`(module
${types}
(func
unreachable
(block (param ${subType})
(block (param ${superType})
drop
)
)
)
)`);
}
function assertNotSubtype(superType, subType, types) {
assertErrorMessage(() => {
assertSubtype(superType, subType, types);
}, WebAssembly.CompileError, /type mismatch/);
}
// Primitive trivial subtyping
assertSubtype('i32', 'i32');
assertSubtype('i64', 'i64');
assertSubtype('f32', 'f32');
assertSubtype('f64', 'f64');
assertSubtype('eqref', 'eqref');
assertSubtype('i31ref', 'i31ref');
assertSubtype('funcref', 'funcref');
// No subtyping relation between funcref, anyref, externref. These are our top
// types.
assertNotSubtype('funcref', 'anyref');
assertNotSubtype('anyref', 'funcref');
assertNotSubtype('funcref', 'externref');
assertNotSubtype('externref', 'funcref');
assertNotSubtype('externref', 'anyref');
assertNotSubtype('anyref', 'externref');
// eqref is a subtype of anyref
assertSubtype('anyref', 'eqref');
// i31ref is a subtype of eqref
assertSubtype('anyref', 'i31ref');
assertSubtype('eqref', 'i31ref');
// structref is a subtype of eqref and anyref
assertSubtype('anyref', 'structref');
assertSubtype('eqref', 'structref');
// arrayref is a subtype of eqref and anyref
assertSubtype('anyref', 'arrayref');
assertSubtype('eqref', 'arrayref');
// Structs are subtypes of anyref, eqref, and structref
assertSubtype(
'anyref',
'(ref 0)',
simpleTypeSection(['(struct)']));
assertSubtype(
'eqref',
'(ref 0)',
simpleTypeSection(['(struct)']));
assertSubtype(
'structref',
'(ref 0)',
simpleTypeSection(['(struct)']));
// Struct identity
assertSubtype(
'(ref 0)',
'(ref 1)',
simpleTypeSection(['(struct)', '(struct)']));
assertSubtype(
'(ref 1)',
'(ref 0)',
simpleTypeSection(['(struct)', '(struct)']));
// Self referential struct
assertSubtype(
'(ref 1)',
'(ref 0)',
simpleTypeSection(['(struct (field (ref 0)))', '(struct (field (ref 1)))']));
// Mutually referential structs
assertSubtype(
'(ref 2)',
'(ref 0)',
`(rec
(type (struct (field (ref 1))))
(type (struct (field (ref 0))))
)
(rec
(type (struct (field (ref 3))))
(type (struct (field (ref 2))))
)`);
// Struct subtypes can have extra fields
assertSubtype(
'(ref 0)',
'(ref 1)',
`(type (sub (struct)))
(type (sub 0 (struct (field i32))))`);
assertSubtype(
'(ref 0)',
'(ref 1)',
`(type (sub (struct)))
(type (sub 0 (struct (field i32) (field i32))))`);
// Struct supertypes cannot have extra fields
assertNotSubtype(
'(ref 0)',
'(ref 1)',
simpleTypeSection([
'(struct (field i32))',
'(struct)']));
// Struct field mutability must match
assertSubtype(
'(ref 0)',
'(ref 1)',
simpleTypeSection([
'(struct (field (mut i32)))',
'(struct (field (mut i32)))']));
assertSubtype(
'(ref 0)',
'(ref 1)',
simpleTypeSection([
'(struct (field i32))',
'(struct (field i32))']));
assertNotSubtype(
'(ref 0)',
'(ref 1)',
simpleTypeSection([
'(struct (field (mut i32)))',
'(struct (field i32))']));
assertNotSubtype(
'(ref 0)',
'(ref 1)',
simpleTypeSection([
'(struct (field i32))',
'(struct (field (mut i32)))']));
// Struct fields are invariant when mutable
assertSubtype(
'(ref 2)',
'(ref 3)',
simpleTypeSection([
'(struct)',
'(struct)',
'(struct (field (mut (ref 0))))',
'(struct (field (mut (ref 1))))']));
assertNotSubtype(
'(ref 2)',
'(ref 3)',
simpleTypeSection([
'(struct)',
'(struct (field i32))',
'(struct (field (mut (ref 0))))',
'(struct (field (mut (ref 1))))']));
// Struct fields are covariant when immutable
assertSubtype(
'(ref 2)',
'(ref 3)',
`(type (sub (struct)))
(type (sub 0 (struct (field i32))))
(type (sub (struct (field (ref 0)))))
(type (sub 2 (struct (field (ref 1)))))`);
// Arrays are subtypes of anyref, eqref, and arrayref
assertSubtype(
'anyref',
'(ref 0)',
simpleTypeSection(['(array i32)']));
assertSubtype(
'eqref',
'(ref 0)',
simpleTypeSection(['(array i32)']));
assertSubtype(
'arrayref',
'(ref 0)',
simpleTypeSection(['(array i32)']));
// Array identity
assertSubtype(
'(ref 0)',
'(ref 1)',
simpleTypeSection(['(array i32)', '(array i32)']));
assertSubtype(
'(ref 1)',
'(ref 0)',
simpleTypeSection(['(array i32)', '(array i32)']));
// Self referential array
assertSubtype(
'(ref 1)',
'(ref 0)',
simpleTypeSection(['(array (ref 0))', '(array (ref 1))']));
// Mutually referential arrays
assertSubtype(
'(ref 2)',
'(ref 0)',
`(rec
(type (array (ref 1)))
(type (array (ref 0)))
)
(rec
(type (array (ref 3)))
(type (array (ref 2)))
)`);
// Array mutability must match
assertSubtype(
'(ref 0)',
'(ref 1)',
simpleTypeSection([
'(array (mut i32))',
'(array (mut i32))']));
assertSubtype(
'(ref 0)',
'(ref 1)',
simpleTypeSection([
'(array i32)',
'(array i32)']));
assertNotSubtype(
'(ref 0)',
'(ref 1)',
simpleTypeSection([
'(array (mut i32))',
'(array i32)']));
assertNotSubtype(
'(ref 0)',
'(ref 1)',
simpleTypeSection([
'(array i32)',
'(array (mut i32))']));
// Array elements are invariant when mutable
assertSubtype(
'(ref 2)',
'(ref 3)',
simpleTypeSection([
'(struct)',
'(struct)',
'(array (mut (ref 0)))',
'(array (mut (ref 1)))']));
assertNotSubtype(
'(ref 2)',
'(ref 3)',
simpleTypeSection([
'(struct)',
'(struct (field i32))',
'(array (mut (ref 0)))',
'(array (mut (ref 1)))']));
// Array elements are covariant when immutable
assertSubtype(
'(ref 2)',
'(ref 3)',
simpleTypeSection([
'(sub (struct))',
'(sub 0 (struct (field i32)))',
'(sub (array (ref 0)))',
'(sub 2 (array (ref 1)))']));
// nullref is a subtype of everything in anyref hierarchy
assertSubtype('anyref', 'nullref');
assertSubtype('eqref', 'nullref');
assertSubtype('structref', 'nullref');
assertSubtype('arrayref', 'nullref');
assertSubtype('(ref null 0)', 'nullref', simpleTypeSection(['(struct)']));
assertSubtype('(ref null 0)', 'nullref', simpleTypeSection(['(array i32)']));
// nullref is not a subtype of any other hierarchy
assertNotSubtype('funcref', 'nullref');
assertNotSubtype('(ref null 0)', 'nullref', simpleTypeSection(['(func)']));
assertNotSubtype('externref', 'nullref');
// nullfuncref is a subtype of everything in funcref hierarchy
assertSubtype('funcref', 'nullfuncref');
assertSubtype('(ref null 0)', 'nullfuncref', simpleTypeSection(['(func)']));
// nullfuncref is not a subtype of any other hierarchy
assertNotSubtype('anyref', 'nullfuncref');
assertNotSubtype('eqref', 'nullfuncref');
assertNotSubtype('structref', 'nullfuncref');
assertNotSubtype('arrayref', 'nullfuncref');
assertNotSubtype('externref', 'nullfuncref');
assertNotSubtype('(ref null 0)', 'nullfuncref', simpleTypeSection(['(struct)']));
assertNotSubtype('(ref null 0)', 'nullfuncref', simpleTypeSection(['(array i32)']));
// nullexternref is a subtype of everything in externref hierarchy
assertSubtype('externref', 'nullexternref');
// nullexternref is not a subtype of any other hierarchy
assertNotSubtype('anyref', 'nullexternref');
assertNotSubtype('eqref', 'nullexternref');
assertNotSubtype('structref', 'nullexternref');
assertNotSubtype('arrayref', 'nullexternref');
assertNotSubtype('funcref', 'nullexternref');
assertNotSubtype('(ref null 0)', 'nullexternref', simpleTypeSection(['(struct)']));
assertNotSubtype('(ref null 0)', 'nullexternref', simpleTypeSection(['(array i32)']));
assertNotSubtype('(ref null 0)', 'nullexternref', simpleTypeSection(['(func)']));