diff --git a/src/builtins.ts b/src/builtins.ts index 4a6e3d79..e65d37af 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -76,6 +76,8 @@ export namespace BuiltinSymbols { export const isReference = "~lib/builtins/isReference"; export const isString = "~lib/builtins/isString"; export const isArray = "~lib/builtins/isArray"; + export const isFunction = "~lib/builtins/isFunction"; + export const isNullable = "~lib/builtins/isNullable"; export const isDefined = "~lib/builtins/isDefined"; export const isConstant = "~lib/builtins/isConstant"; export const isManaged = "~lib/builtins/isManaged"; @@ -348,6 +350,18 @@ export function compileCall( : 0 ); } + case BuiltinSymbols.isFunction: { // isFunction / isFunction(value: T) -> bool + let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); + compiler.currentType = Type.bool; + if (!type) return module.createUnreachable(); + return module.createI32(type.signatureReference ? 1 : 0); + } + case BuiltinSymbols.isNullable: { // isNullable / isNullable(value: T) -> bool + let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); + compiler.currentType = Type.bool; + if (!type) return module.createUnreachable(); + return module.createI32(type.is(TypeFlags.NULLABLE) ? 1 : 0); + } case BuiltinSymbols.isDefined: { // isDefined(expression) -> bool compiler.currentType = Type.bool; if (typeArguments) { diff --git a/std/assembly/builtins.ts b/std/assembly/builtins.ts index 370047ad..af251761 100644 --- a/std/assembly/builtins.ts +++ b/std/assembly/builtins.ts @@ -9,6 +9,8 @@ @builtin export declare function isReference(value?: T): bool; @builtin export declare function isString(value?: T): bool; @builtin export declare function isArray(value?: T): bool; +@builtin export declare function isFunction(value?: T): bool; +@builtin export declare function isNullable(value?: T): bool; @builtin export declare function isDefined(expression: void): bool; @builtin export declare function isConstant(expression: void): bool; @builtin export declare function isManaged(value?: T): bool; diff --git a/std/assembly/index.d.ts b/std/assembly/index.d.ts index 7d0927d0..09af2088 100644 --- a/std/assembly/index.d.ts +++ b/std/assembly/index.d.ts @@ -128,6 +128,10 @@ declare function isReference(value?: any): value is object | string; declare function isString(value?: any): value is string | String; /** Tests if the specified type *or* expression can be used as an array. Compiles to a constant. */ declare function isArray(value?: any): value is Array; +/** Tests if the specified type *or* expression is of a function type. Compiles to a constant. */ +declare function isFunction(value?: any): value is Array; +/** Tests if the specified type *or* expression is of a nullable reference type. Compiles to a constant. */ +declare function isNullable(value?: any): value is Array; /** Tests if the specified expression resolves to a defined element. Compiles to a constant. */ declare function isDefined(expression: any): bool; /** Tests if the specified expression evaluates to a constant value. Compiles to a constant. */ diff --git a/tests/compiler/builtins.optimized.wat b/tests/compiler/builtins.optimized.wat index 8a61bc44..2257c7d2 100644 --- a/tests/compiler/builtins.optimized.wat +++ b/tests/compiler/builtins.optimized.wat @@ -43,7 +43,7 @@ if i32.const 0 i32.const 8 - i32.const 50 + i32.const 59 i32.const 19 call $~lib/env/abort unreachable @@ -56,7 +56,7 @@ if i32.const 0 i32.const 8 - i32.const 51 + i32.const 60 i32.const 20 call $~lib/env/abort unreachable @@ -69,7 +69,7 @@ if i32.const 0 i32.const 8 - i32.const 52 + i32.const 61 i32.const 20 call $~lib/env/abort unreachable @@ -92,7 +92,7 @@ if i32.const 0 i32.const 8 - i32.const 68 + i32.const 77 i32.const 19 call $~lib/env/abort unreachable @@ -105,7 +105,7 @@ if i32.const 0 i32.const 8 - i32.const 69 + i32.const 78 i32.const 20 call $~lib/env/abort unreachable @@ -118,7 +118,7 @@ if i32.const 0 i32.const 8 - i32.const 70 + i32.const 79 i32.const 20 call $~lib/env/abort unreachable diff --git a/tests/compiler/builtins.ts b/tests/compiler/builtins.ts index dea322d0..b81e57f4 100644 --- a/tests/compiler/builtins.ts +++ b/tests/compiler/builtins.ts @@ -1,4 +1,5 @@ var b: bool; +class C {} // type checks @@ -10,6 +11,10 @@ assert(isReference()); assert(!isReference()); assert(isArray()); assert(!isArray()); +assert(isFunction<() => void>()); +assert(!isFunction()); +assert(isNullable()); +assert(!isNullable()); assert(isInteger(1)); assert(!isInteger(1)); @@ -21,6 +26,10 @@ assert(isString("1")); assert(!isString(1)); assert(isArray(changetype(null))); assert(!isArray(changetype(null))); +assert(isFunction(changetype<() => void>(null))); +assert(!isFunction(changetype(null))); +assert(isNullable(changetype(null))); +assert(!isNullable(changetype(null))); // evaluation diff --git a/tests/compiler/builtins.untouched.wat b/tests/compiler/builtins.untouched.wat index ea5f4906..a5680091 100644 --- a/tests/compiler/builtins.untouched.wat +++ b/tests/compiler/builtins.untouched.wat @@ -68,7 +68,7 @@ if i32.const 0 i32.const 8 - i32.const 5 + i32.const 6 i32.const 0 call $~lib/env/abort unreachable @@ -76,16 +76,6 @@ i32.const 0 i32.eqz i32.eqz - if - i32.const 0 - i32.const 8 - i32.const 6 - i32.const 0 - call $~lib/env/abort - unreachable - end - i32.const 1 - i32.eqz if i32.const 0 i32.const 8 @@ -94,8 +84,7 @@ call $~lib/env/abort unreachable end - i32.const 0 - i32.eqz + i32.const 1 i32.eqz if i32.const 0 @@ -105,7 +94,8 @@ call $~lib/env/abort unreachable end - i32.const 1 + i32.const 0 + i32.eqz i32.eqz if i32.const 0 @@ -115,8 +105,7 @@ call $~lib/env/abort unreachable end - i32.const 0 - i32.eqz + i32.const 1 i32.eqz if i32.const 0 @@ -126,7 +115,8 @@ call $~lib/env/abort unreachable end - i32.const 1 + i32.const 0 + i32.eqz i32.eqz if i32.const 0 @@ -136,13 +126,23 @@ call $~lib/env/abort unreachable end + i32.const 1 + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 12 + i32.const 0 + call $~lib/env/abort + unreachable + end i32.const 0 i32.eqz i32.eqz if i32.const 0 i32.const 8 - i32.const 12 + i32.const 13 i32.const 0 call $~lib/env/abort unreachable @@ -194,7 +194,7 @@ if i32.const 0 i32.const 8 - i32.const 18 + i32.const 19 i32.const 0 call $~lib/env/abort unreachable @@ -202,16 +202,6 @@ i32.const 0 i32.eqz i32.eqz - if - i32.const 0 - i32.const 8 - i32.const 19 - i32.const 0 - call $~lib/env/abort - unreachable - end - i32.const 1 - i32.eqz if i32.const 0 i32.const 8 @@ -220,8 +210,7 @@ call $~lib/env/abort unreachable end - i32.const 0 - i32.eqz + i32.const 1 i32.eqz if i32.const 0 @@ -231,7 +220,8 @@ call $~lib/env/abort unreachable end - i32.const 1 + i32.const 0 + i32.eqz i32.eqz if i32.const 0 @@ -241,13 +231,44 @@ call $~lib/env/abort unreachable end + i32.const 1 + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 23 + i32.const 0 + call $~lib/env/abort + unreachable + end i32.const 0 i32.eqz i32.eqz if i32.const 0 i32.const 8 - i32.const 23 + i32.const 24 + i32.const 0 + call $~lib/env/abort + unreachable + end + i32.const 1 + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 25 + i32.const 0 + call $~lib/env/abort + unreachable + end + i32.const 0 + i32.eqz + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 26 i32.const 0 call $~lib/env/abort unreachable @@ -295,6 +316,69 @@ unreachable end i32.const 1 + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 31 + i32.const 0 + call $~lib/env/abort + unreachable + end + i32.const 0 + i32.eqz + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 32 + i32.const 0 + call $~lib/env/abort + unreachable + end + i32.const 1 + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 36 + i32.const 0 + call $~lib/env/abort + unreachable + end + i32.const 0 + i32.eqz + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 37 + i32.const 0 + call $~lib/env/abort + unreachable + end + i32.const 1 + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 38 + i32.const 0 + call $~lib/env/abort + unreachable + end + i32.const 0 + i32.eqz + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 39 + i32.const 0 + call $~lib/env/abort + unreachable + end + i32.const 1 i32.clz drop i32.const 1 @@ -373,7 +457,7 @@ if i32.const 0 i32.const 8 - i32.const 50 + i32.const 59 i32.const 19 call $~lib/env/abort unreachable @@ -394,7 +478,7 @@ if i32.const 0 i32.const 8 - i32.const 51 + i32.const 60 i32.const 20 call $~lib/env/abort unreachable @@ -415,7 +499,7 @@ if i32.const 0 i32.const 8 - i32.const 52 + i32.const 61 i32.const 20 call $~lib/env/abort unreachable @@ -481,7 +565,7 @@ if i32.const 0 i32.const 8 - i32.const 68 + i32.const 77 i32.const 19 call $~lib/env/abort unreachable @@ -502,7 +586,7 @@ if i32.const 0 i32.const 8 - i32.const 69 + i32.const 78 i32.const 20 call $~lib/env/abort unreachable @@ -523,7 +607,7 @@ if i32.const 0 i32.const 8 - i32.const 70 + i32.const 79 i32.const 20 call $~lib/env/abort unreachable @@ -577,7 +661,7 @@ if i32.const 0 i32.const 8 - i32.const 87 + i32.const 96 i32.const 0 call $~lib/env/abort unreachable @@ -597,7 +681,7 @@ if i32.const 0 i32.const 8 - i32.const 88 + i32.const 97 i32.const 0 call $~lib/env/abort unreachable @@ -619,7 +703,7 @@ if i32.const 0 i32.const 8 - i32.const 89 + i32.const 98 i32.const 0 call $~lib/env/abort unreachable @@ -641,7 +725,7 @@ if i32.const 0 i32.const 8 - i32.const 90 + i32.const 99 i32.const 0 call $~lib/env/abort unreachable @@ -664,7 +748,7 @@ if i32.const 0 i32.const 8 - i32.const 91 + i32.const 100 i32.const 0 call $~lib/env/abort unreachable @@ -686,7 +770,7 @@ if i32.const 0 i32.const 8 - i32.const 92 + i32.const 101 i32.const 0 call $~lib/env/abort unreachable @@ -800,7 +884,7 @@ if i32.const 0 i32.const 8 - i32.const 123 + i32.const 132 i32.const 0 call $~lib/env/abort unreachable @@ -820,7 +904,7 @@ if i32.const 0 i32.const 8 - i32.const 124 + i32.const 133 i32.const 0 call $~lib/env/abort unreachable @@ -842,7 +926,7 @@ if i32.const 0 i32.const 8 - i32.const 125 + i32.const 134 i32.const 0 call $~lib/env/abort unreachable @@ -864,7 +948,7 @@ if i32.const 0 i32.const 8 - i32.const 126 + i32.const 135 i32.const 0 call $~lib/env/abort unreachable @@ -887,7 +971,7 @@ if i32.const 0 i32.const 8 - i32.const 127 + i32.const 136 i32.const 0 call $~lib/env/abort unreachable @@ -909,7 +993,7 @@ if i32.const 0 i32.const 8 - i32.const 128 + i32.const 137 i32.const 0 call $~lib/env/abort unreachable @@ -1222,104 +1306,6 @@ i32.const 1 i32.eq i32.eqz - if - i32.const 0 - i32.const 8 - i32.const 247 - i32.const 0 - call $~lib/env/abort - unreachable - end - i32.const 2 - i32.const 2 - i32.eq - i32.eqz - if - i32.const 0 - i32.const 8 - i32.const 248 - i32.const 0 - call $~lib/env/abort - unreachable - end - i32.const 4 - i32.const 4 - i32.eq - i32.eqz - if - i32.const 0 - i32.const 8 - i32.const 249 - i32.const 0 - call $~lib/env/abort - unreachable - end - i32.const 8 - i32.const 8 - i32.eq - i32.eqz - if - i32.const 0 - i32.const 8 - i32.const 250 - i32.const 0 - call $~lib/env/abort - unreachable - end - i32.const 4 - drop - i32.const 1 - i32.const 1 - i32.eq - i32.eqz - if - i32.const 0 - i32.const 8 - i32.const 252 - i32.const 0 - call $~lib/env/abort - unreachable - end - i32.const 1 - i32.const 1 - i32.eq - i32.eqz - if - i32.const 0 - i32.const 8 - i32.const 253 - i32.const 0 - call $~lib/env/abort - unreachable - end - i32.const 2 - i32.const 2 - i32.eq - i32.eqz - if - i32.const 0 - i32.const 8 - i32.const 254 - i32.const 0 - call $~lib/env/abort - unreachable - end - i32.const 4 - i32.const 4 - i32.eq - i32.eqz - if - i32.const 0 - i32.const 8 - i32.const 255 - i32.const 0 - call $~lib/env/abort - unreachable - end - i32.const 8 - i32.const 8 - i32.eq - i32.eqz if i32.const 0 i32.const 8 @@ -1328,8 +1314,18 @@ call $~lib/env/abort unreachable end - i32.const 4 - drop + i32.const 2 + i32.const 2 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 257 + i32.const 0 + call $~lib/env/abort + unreachable + end i32.const 4 i32.const 4 i32.eq @@ -1354,8 +1350,22 @@ call $~lib/env/abort unreachable end - i32.const 0 - i32.const 0 + i32.const 4 + drop + i32.const 1 + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 261 + i32.const 0 + call $~lib/env/abort + unreachable + end + i32.const 1 + i32.const 1 i32.eq i32.eqz if @@ -1366,8 +1376,8 @@ call $~lib/env/abort unreachable end - i32.const 4 - i32.const 4 + i32.const 2 + i32.const 2 i32.eq i32.eqz if @@ -1378,8 +1388,8 @@ call $~lib/env/abort unreachable end - i32.const 0 - i32.const 0 + i32.const 4 + i32.const 4 i32.eq i32.eqz if @@ -1390,8 +1400,8 @@ call $~lib/env/abort unreachable end - i32.const 2 - i32.const 2 + i32.const 8 + i32.const 8 i32.eq i32.eqz if @@ -1402,8 +1412,10 @@ call $~lib/env/abort unreachable end - i32.const 0 - i32.const 0 + i32.const 4 + drop + i32.const 4 + i32.const 4 i32.eq i32.eqz if @@ -1426,6 +1438,78 @@ call $~lib/env/abort unreachable end + i32.const 0 + i32.const 0 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 271 + i32.const 0 + call $~lib/env/abort + unreachable + end + i32.const 4 + i32.const 4 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 272 + i32.const 0 + call $~lib/env/abort + unreachable + end + i32.const 0 + i32.const 0 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 273 + i32.const 0 + call $~lib/env/abort + unreachable + end + i32.const 2 + i32.const 2 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 274 + i32.const 0 + call $~lib/env/abort + unreachable + end + i32.const 0 + i32.const 0 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 276 + i32.const 0 + call $~lib/env/abort + unreachable + end + i32.const 8 + i32.const 8 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 277 + i32.const 0 + call $~lib/env/abort + unreachable + end f64.const nan:0x8000000000000 f64.const nan:0x8000000000000 f64.ne @@ -1433,7 +1517,7 @@ if i32.const 0 i32.const 8 - i32.const 270 + i32.const 279 i32.const 0 call $~lib/env/abort unreachable @@ -1451,7 +1535,7 @@ if i32.const 0 i32.const 8 - i32.const 271 + i32.const 280 i32.const 0 call $~lib/env/abort unreachable @@ -1469,7 +1553,7 @@ if i32.const 0 i32.const 8 - i32.const 272 + i32.const 281 i32.const 0 call $~lib/env/abort unreachable @@ -1490,7 +1574,7 @@ if i32.const 0 i32.const 8 - i32.const 273 + i32.const 282 i32.const 0 call $~lib/env/abort unreachable @@ -1511,7 +1595,7 @@ if i32.const 0 i32.const 8 - i32.const 274 + i32.const 283 i32.const 0 call $~lib/env/abort unreachable @@ -1532,7 +1616,7 @@ if i32.const 0 i32.const 8 - i32.const 275 + i32.const 284 i32.const 0 call $~lib/env/abort unreachable @@ -1553,7 +1637,7 @@ if i32.const 0 i32.const 8 - i32.const 276 + i32.const 285 i32.const 0 call $~lib/env/abort unreachable @@ -1573,7 +1657,7 @@ if i32.const 0 i32.const 8 - i32.const 277 + i32.const 286 i32.const 0 call $~lib/env/abort unreachable @@ -1593,7 +1677,7 @@ if i32.const 0 i32.const 8 - i32.const 278 + i32.const 287 i32.const 0 call $~lib/env/abort unreachable @@ -1609,7 +1693,7 @@ if i32.const 0 i32.const 8 - i32.const 291 + i32.const 300 i32.const 0 call $~lib/env/abort unreachable @@ -1621,7 +1705,7 @@ if i32.const 0 i32.const 8 - i32.const 292 + i32.const 301 i32.const 0 call $~lib/env/abort unreachable @@ -1637,7 +1721,7 @@ if i32.const 0 i32.const 8 - i32.const 293 + i32.const 302 i32.const 0 call $~lib/env/abort unreachable @@ -1649,7 +1733,7 @@ if i32.const 0 i32.const 8 - i32.const 294 + i32.const 303 i32.const 0 call $~lib/env/abort unreachable @@ -1661,7 +1745,7 @@ if i32.const 0 i32.const 8 - i32.const 295 + i32.const 304 i32.const 0 call $~lib/env/abort unreachable @@ -1673,7 +1757,7 @@ if i32.const 0 i32.const 8 - i32.const 296 + i32.const 305 i32.const 0 call $~lib/env/abort unreachable @@ -1685,7 +1769,7 @@ if i32.const 0 i32.const 8 - i32.const 297 + i32.const 306 i32.const 0 call $~lib/env/abort unreachable @@ -1697,7 +1781,7 @@ if i32.const 0 i32.const 8 - i32.const 298 + i32.const 307 i32.const 0 call $~lib/env/abort unreachable @@ -1709,7 +1793,7 @@ if i32.const 0 i32.const 8 - i32.const 300 + i32.const 309 i32.const 0 call $~lib/env/abort unreachable @@ -1721,7 +1805,7 @@ if i32.const 0 i32.const 8 - i32.const 301 + i32.const 310 i32.const 0 call $~lib/env/abort unreachable @@ -1733,7 +1817,7 @@ if i32.const 0 i32.const 8 - i32.const 302 + i32.const 311 i32.const 0 call $~lib/env/abort unreachable @@ -1745,7 +1829,7 @@ if i32.const 0 i32.const 8 - i32.const 303 + i32.const 312 i32.const 0 call $~lib/env/abort unreachable @@ -1757,7 +1841,7 @@ if i32.const 0 i32.const 8 - i32.const 304 + i32.const 313 i32.const 0 call $~lib/env/abort unreachable @@ -1769,7 +1853,7 @@ if i32.const 0 i32.const 8 - i32.const 305 + i32.const 314 i32.const 0 call $~lib/env/abort unreachable @@ -1781,7 +1865,7 @@ if i32.const 0 i32.const 8 - i32.const 306 + i32.const 315 i32.const 0 call $~lib/env/abort unreachable @@ -1793,7 +1877,7 @@ if i32.const 0 i32.const 8 - i32.const 307 + i32.const 316 i32.const 0 call $~lib/env/abort unreachable @@ -1805,7 +1889,7 @@ if i32.const 0 i32.const 8 - i32.const 308 + i32.const 317 i32.const 0 call $~lib/env/abort unreachable @@ -1817,7 +1901,7 @@ if i32.const 0 i32.const 8 - i32.const 308 + i32.const 317 i32.const 29 call $~lib/env/abort unreachable @@ -1829,7 +1913,7 @@ if i32.const 0 i32.const 8 - i32.const 309 + i32.const 318 i32.const 0 call $~lib/env/abort unreachable @@ -1841,7 +1925,7 @@ if i32.const 0 i32.const 8 - i32.const 309 + i32.const 318 i32.const 29 call $~lib/env/abort unreachable @@ -1853,7 +1937,7 @@ if i32.const 0 i32.const 8 - i32.const 311 + i32.const 320 i32.const 0 call $~lib/env/abort unreachable @@ -1865,7 +1949,7 @@ if i32.const 0 i32.const 8 - i32.const 312 + i32.const 321 i32.const 0 call $~lib/env/abort unreachable @@ -1877,7 +1961,7 @@ if i32.const 0 i32.const 8 - i32.const 313 + i32.const 322 i32.const 0 call $~lib/env/abort unreachable @@ -1889,7 +1973,7 @@ if i32.const 0 i32.const 8 - i32.const 314 + i32.const 323 i32.const 0 call $~lib/env/abort unreachable @@ -1901,7 +1985,7 @@ if i32.const 0 i32.const 8 - i32.const 315 + i32.const 324 i32.const 0 call $~lib/env/abort unreachable @@ -1913,7 +1997,7 @@ if i32.const 0 i32.const 8 - i32.const 316 + i32.const 325 i32.const 0 call $~lib/env/abort unreachable @@ -1925,7 +2009,7 @@ if i32.const 0 i32.const 8 - i32.const 318 + i32.const 327 i32.const 0 call $~lib/env/abort unreachable @@ -1937,7 +2021,7 @@ if i32.const 0 i32.const 8 - i32.const 319 + i32.const 328 i32.const 0 call $~lib/env/abort unreachable @@ -1949,7 +2033,7 @@ if i32.const 0 i32.const 8 - i32.const 320 + i32.const 329 i32.const 0 call $~lib/env/abort unreachable @@ -1961,7 +2045,7 @@ if i32.const 0 i32.const 8 - i32.const 321 + i32.const 330 i32.const 0 call $~lib/env/abort unreachable @@ -1973,7 +2057,7 @@ if i32.const 0 i32.const 8 - i32.const 322 + i32.const 331 i32.const 0 call $~lib/env/abort unreachable @@ -1985,7 +2069,7 @@ if i32.const 0 i32.const 8 - i32.const 323 + i32.const 332 i32.const 0 call $~lib/env/abort unreachable