diff --git a/src/compiler.ts b/src/compiler.ts index 7a6a435a72..9a60c12214 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -9941,7 +9941,10 @@ export class Compiler extends DiagnosticEmitter { case TypeKind.EQREF: case TypeKind.DATAREF: case TypeKind.I31REF: { - return module.ref_is(RefIsOp.RefIsNull, expr); + // Needs to be true (i.e. not zero) when the ref is _not_ null, + // which means `ref.is_null` returns false (i.e. zero). + return module.unary(UnaryOp.EqzI32, module.ref_is(RefIsOp.RefIsNull, expr)); + } default: { assert(false); diff --git a/tests/compiler/features/reference-types.js b/tests/compiler/features/reference-types.js index 50aeab08ba..078c91423f 100644 --- a/tests/compiler/features/reference-types.js +++ b/tests/compiler/features/reference-types.js @@ -9,6 +9,12 @@ exports.preInstantiate = function(imports, exports) { external: function(a) { return a; }, + somethingReal() { + return {}; + }, + somethingNull() { + return null; + }, someObject: { theKey: "Hello world!" }, diff --git a/tests/compiler/features/reference-types.ts b/tests/compiler/features/reference-types.ts index d0b3e8d208..982c885c29 100644 --- a/tests/compiler/features/reference-types.ts +++ b/tests/compiler/features/reference-types.ts @@ -1,6 +1,8 @@ // can use externref as a parameter or return type export declare function external(a: externref): externref; +export declare function somethingReal(): externref; +export declare function somethingNull(): externref; export function internal(a: externref): externref { const b = external(a); @@ -26,6 +28,44 @@ console.log(someObject); console.log(someKey); console.log(Reflect.get(someObject, someKey)); +// Truthiness conversion +if(!somethingReal()) { + assert(false); +} +if(!somethingNull()) { + // nop +} else { + assert(false); +} +if(somethingReal()) { + // nop +} else { + assert(false); +} +if(somethingNull()) { + assert(false); +} + +// Explicit null checks (don’t work yet) +/* +if(somethingReal() !== null) { + // nop +} else { + assert(false); +} +if(somethingReal() === null) { + assert(false); +} +if(somethingNull() === null) { + // nop +} else { + assert(false); +} +if(somethingNull() !== null) { + assert(false); +} +*/ + // can represent and recognize 'null' var funcGlobal: funcref; diff --git a/tests/compiler/features/reference-types.untouched.wat b/tests/compiler/features/reference-types.untouched.wat index b4212781f2..d11e0d6bcb 100644 --- a/tests/compiler/features/reference-types.untouched.wat +++ b/tests/compiler/features/reference-types.untouched.wat @@ -1,5 +1,6 @@ (module (type $none_=>_none (func)) + (type $none_=>_externref (func (result externref))) (type $externref_=>_externref (func (param externref) (result externref))) (type $externref_=>_none (func (param externref))) (type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32))) @@ -11,6 +12,8 @@ (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) (import "console" "log" (func $~lib/bindings/console/log (param externref))) (import "Reflect" "get" (func $~lib/bindings/Reflect/get (param externref externref) (result externref))) + (import "reference-types" "somethingReal" (func $features/reference-types/somethingReal (result externref))) + (import "reference-types" "somethingNull" (func $features/reference-types/somethingNull (result externref))) (import "reference-types" "external" (func $features/reference-types/external (param externref) (result externref))) (memory $0 1) (data (i32.const 12) "L\00\00\00\00\00\00\00\00\00\00\00\01\00\00\006\00\00\00f\00e\00a\00t\00u\00r\00e\00s\00/\00r\00e\00f\00e\00r\00e\00n\00c\00e\00-\00t\00y\00p\00e\00s\00.\00t\00s\00\00\00\00\00\00\00") @@ -26,6 +29,8 @@ (global $~lib/memory/__stack_pointer (mut i32) (i32.const 16476)) (global $~lib/memory/__heap_base i32 (i32.const 16476)) (export "external" (func $features/reference-types/external)) + (export "somethingReal" (func $features/reference-types/somethingReal)) + (export "somethingNull" (func $features/reference-types/somethingNull)) (export "internal" (func $features/reference-types/internal)) (export "memory" (memory $0)) (start $~start) @@ -36,10 +41,11 @@ ref.is_null i32.eqz i32.eqz + i32.eqz if i32.const 0 i32.const 32 - i32.const 54 + i32.const 94 i32.const 3 call $~lib/builtins/abort unreachable @@ -50,10 +56,11 @@ ref.is_null i32.eqz i32.eqz + i32.eqz if i32.const 0 i32.const 32 - i32.const 56 + i32.const 96 i32.const 3 call $~lib/builtins/abort unreachable @@ -64,10 +71,11 @@ ref.is_null i32.eqz i32.eqz + i32.eqz if i32.const 0 i32.const 32 - i32.const 58 + i32.const 98 i32.const 3 call $~lib/builtins/abort unreachable @@ -80,10 +88,11 @@ ref.is_null i32.eqz i32.eqz + i32.eqz if i32.const 0 i32.const 32 - i32.const 54 + i32.const 94 i32.const 3 call $~lib/builtins/abort unreachable @@ -94,10 +103,11 @@ ref.is_null i32.eqz i32.eqz + i32.eqz if i32.const 0 i32.const 32 - i32.const 56 + i32.const 96 i32.const 3 call $~lib/builtins/abort unreachable @@ -108,10 +118,11 @@ ref.is_null i32.eqz i32.eqz + i32.eqz if i32.const 0 i32.const 32 - i32.const 58 + i32.const 98 i32.const 3 call $~lib/builtins/abort unreachable @@ -124,10 +135,11 @@ ref.is_null i32.eqz i32.eqz + i32.eqz if i32.const 0 i32.const 32 - i32.const 54 + i32.const 94 i32.const 3 call $~lib/builtins/abort unreachable @@ -138,10 +150,11 @@ ref.is_null i32.eqz i32.eqz + i32.eqz if i32.const 0 i32.const 32 - i32.const 56 + i32.const 96 i32.const 3 call $~lib/builtins/abort unreachable @@ -152,10 +165,11 @@ ref.is_null i32.eqz i32.eqz + i32.eqz if i32.const 0 i32.const 32 - i32.const 58 + i32.const 98 i32.const 3 call $~lib/builtins/abort unreachable @@ -175,7 +189,7 @@ if i32.const 0 i32.const 32 - i32.const 19 + i32.const 21 i32.const 1 call $~lib/builtins/abort unreachable @@ -188,14 +202,81 @@ global.get $features/reference-types/someKey call $~lib/bindings/Reflect/get call $~lib/bindings/console/log + call $features/reference-types/somethingReal + ref.is_null + i32.eqz + i32.eqz + if + i32.const 0 + i32.eqz + if + i32.const 0 + i32.const 32 + i32.const 33 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + end + call $features/reference-types/somethingNull + ref.is_null + i32.eqz + i32.eqz + if + nop + else + i32.const 0 + i32.eqz + if + i32.const 0 + i32.const 32 + i32.const 38 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + end + call $features/reference-types/somethingReal + ref.is_null + i32.eqz + if + nop + else + i32.const 0 + i32.eqz + if + i32.const 0 + i32.const 32 + i32.const 43 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + end + call $features/reference-types/somethingNull + ref.is_null + i32.eqz + if + i32.const 0 + i32.eqz + if + i32.const 0 + i32.const 32 + i32.const 46 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + end global.get $features/reference-types/funcGlobal ref.is_null i32.eqz i32.eqz + i32.eqz if i32.const 0 i32.const 32 - i32.const 32 + i32.const 72 i32.const 1 call $~lib/builtins/abort unreachable @@ -206,10 +287,11 @@ ref.is_null i32.eqz i32.eqz + i32.eqz if i32.const 0 i32.const 32 - i32.const 34 + i32.const 74 i32.const 1 call $~lib/builtins/abort unreachable @@ -220,10 +302,11 @@ ref.is_null i32.eqz i32.eqz + i32.eqz if i32.const 0 i32.const 32 - i32.const 36 + i32.const 76 i32.const 1 call $~lib/builtins/abort unreachable @@ -232,10 +315,11 @@ ref.is_null i32.eqz i32.eqz + i32.eqz if i32.const 0 i32.const 32 - i32.const 39 + i32.const 79 i32.const 1 call $~lib/builtins/abort unreachable @@ -246,10 +330,11 @@ ref.is_null i32.eqz i32.eqz + i32.eqz if i32.const 0 i32.const 32 - i32.const 41 + i32.const 81 i32.const 1 call $~lib/builtins/abort unreachable @@ -260,10 +345,11 @@ ref.is_null i32.eqz i32.eqz + i32.eqz if i32.const 0 i32.const 32 - i32.const 43 + i32.const 83 i32.const 1 call $~lib/builtins/abort unreachable @@ -272,10 +358,11 @@ ref.is_null i32.eqz i32.eqz + i32.eqz if i32.const 0 i32.const 32 - i32.const 46 + i32.const 86 i32.const 1 call $~lib/builtins/abort unreachable @@ -286,10 +373,11 @@ ref.is_null i32.eqz i32.eqz + i32.eqz if i32.const 0 i32.const 32 - i32.const 48 + i32.const 88 i32.const 1 call $~lib/builtins/abort unreachable @@ -300,10 +388,11 @@ ref.is_null i32.eqz i32.eqz + i32.eqz if i32.const 0 i32.const 32 - i32.const 50 + i32.const 90 i32.const 1 call $~lib/builtins/abort unreachable @@ -318,7 +407,7 @@ if i32.const 0 i32.const 32 - i32.const 68 + i32.const 108 i32.const 1 call $~lib/builtins/abort unreachable @@ -330,7 +419,7 @@ if i32.const 0 i32.const 32 - i32.const 70 + i32.const 110 i32.const 1 call $~lib/builtins/abort unreachable @@ -342,7 +431,7 @@ if i32.const 0 i32.const 32 - i32.const 73 + i32.const 113 i32.const 3 call $~lib/builtins/abort unreachable