mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 23:12:19 +00:00
Make 'instanceof' behave like TS if the lhs is nullable
This commit is contained in:
parent
7478c8a0d3
commit
47f2e0950a
2
dist/assemblyscript.js
vendored
2
dist/assemblyscript.js
vendored
File diff suppressed because one or more lines are too long
2
dist/assemblyscript.js.map
vendored
2
dist/assemblyscript.js.map
vendored
File diff suppressed because one or more lines are too long
@ -2377,18 +2377,17 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// any to void
|
// any to void
|
||||||
if (toType.kind == TypeKind.VOID) {
|
if (toType.kind == TypeKind.VOID) return module.createDrop(expr);
|
||||||
return module.createDrop(expr);
|
|
||||||
|
if (!fromType.isAssignableTo(toType)) {
|
||||||
|
if (conversionKind == ConversionKind.IMPLICIT) {
|
||||||
|
this.error(
|
||||||
|
DiagnosticCode.Conversion_from_type_0_to_1_requires_an_explicit_cast,
|
||||||
|
reportNode.range, fromType.toString(), toType.toString()
|
||||||
|
); // recoverable
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conversionKind == ConversionKind.IMPLICIT && !fromType.isAssignableTo(toType)) {
|
|
||||||
this.error(
|
|
||||||
DiagnosticCode.Conversion_from_type_0_to_1_requires_an_explicit_cast,
|
|
||||||
reportNode.range, fromType.toString(), toType.toString()
|
|
||||||
); // recoverable
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: make this a proper switch?
|
|
||||||
if (fromType.is(TypeFlags.FLOAT)) {
|
if (fromType.is(TypeFlags.FLOAT)) {
|
||||||
|
|
||||||
// float to float
|
// float to float
|
||||||
@ -4502,7 +4501,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
if (!target) return this.module.createUnreachable();
|
if (!target) return this.module.createUnreachable();
|
||||||
|
|
||||||
// to compile just the value, we need to know the target's type
|
// to compile just the value, we need to know the target's type
|
||||||
var elementType: Type;
|
var targetType: Type;
|
||||||
switch (target.kind) {
|
switch (target.kind) {
|
||||||
case ElementKind.GLOBAL: {
|
case ElementKind.GLOBAL: {
|
||||||
if (!this.compileGlobal(<Global>target)) { // reports; not yet compiled if a static field compiled as a global
|
if (!this.compileGlobal(<Global>target)) { // reports; not yet compiled if a static field compiled as a global
|
||||||
@ -4513,7 +4512,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
case ElementKind.LOCAL:
|
case ElementKind.LOCAL:
|
||||||
case ElementKind.FIELD: {
|
case ElementKind.FIELD: {
|
||||||
elementType = (<VariableLikeElement>target).type;
|
targetType = (<VariableLikeElement>target).type;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ElementKind.PROPERTY: {
|
case ElementKind.PROPERTY: {
|
||||||
@ -4522,7 +4521,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
let instance = prototype.resolve(); // reports
|
let instance = prototype.resolve(); // reports
|
||||||
if (!instance) return this.module.createUnreachable();
|
if (!instance) return this.module.createUnreachable();
|
||||||
assert(instance.signature.parameterTypes.length == 1); // parser must guarantee this
|
assert(instance.signature.parameterTypes.length == 1); // parser must guarantee this
|
||||||
elementType = instance.signature.parameterTypes[0];
|
targetType = instance.signature.parameterTypes[0];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
this.error(
|
this.error(
|
||||||
@ -4551,7 +4550,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
return this.module.createUnreachable();
|
return this.module.createUnreachable();
|
||||||
}
|
}
|
||||||
assert(indexedSet.signature.parameterTypes.length == 2); // parser must guarantee this
|
assert(indexedSet.signature.parameterTypes.length == 2); // parser must guarantee this
|
||||||
elementType = indexedSet.signature.parameterTypes[1]; // 2nd parameter is the element
|
targetType = indexedSet.signature.parameterTypes[1]; // 2nd parameter is the element
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// fall-through
|
// fall-through
|
||||||
@ -4566,7 +4565,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// compile the value and do the assignment
|
// compile the value and do the assignment
|
||||||
var valueExpr = this.compileExpression(valueExpression, elementType, ConversionKind.IMPLICIT, WrapMode.NONE);
|
var valueExpr = this.compileExpression(valueExpression, targetType, ConversionKind.IMPLICIT, WrapMode.NONE);
|
||||||
return this.compileAssignmentWithValue(
|
return this.compileAssignmentWithValue(
|
||||||
expression,
|
expression,
|
||||||
valueExpr,
|
valueExpr,
|
||||||
@ -5882,12 +5881,26 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
expression: InstanceOfExpression,
|
expression: InstanceOfExpression,
|
||||||
contextualType: Type
|
contextualType: Type
|
||||||
): ExpressionRef {
|
): ExpressionRef {
|
||||||
this.compileExpressionRetainType(expression.expression, this.options.usizeType, WrapMode.NONE);
|
var module = this.module;
|
||||||
|
// NOTE that this differs from TypeScript in that the rhs is a type, not an expression. at the
|
||||||
|
// time of implementation, this seemed more useful because dynamic rhs expressions are not
|
||||||
|
// possible in AS anyway.
|
||||||
|
var expr = this.compileExpressionRetainType(expression.expression, this.options.usizeType, WrapMode.NONE);
|
||||||
var type = this.currentType;
|
var type = this.currentType;
|
||||||
var isType = this.program.resolveType(expression.isType);
|
var isType = this.program.resolveType(expression.isType);
|
||||||
this.currentType = Type.bool;
|
this.currentType = Type.bool;
|
||||||
if (!isType) return this.module.createUnreachable();
|
if (!isType) return module.createUnreachable();
|
||||||
return this.module.createI32(type.isAssignableTo(isType, false) ? 1 : 0);
|
return type.is(TypeFlags.NULLABLE) && !isType.is(TypeFlags.NULLABLE)
|
||||||
|
? type.nonNullableType.isAssignableTo(isType)
|
||||||
|
? module.createBinary( // not precomputeable
|
||||||
|
type.is(TypeFlags.LONG)
|
||||||
|
? BinaryOp.NeI64
|
||||||
|
: BinaryOp.NeI32,
|
||||||
|
expr,
|
||||||
|
type.toNativeZero(module)
|
||||||
|
)
|
||||||
|
: module.createI32(0)
|
||||||
|
: module.createI32(type.isAssignableTo(isType, true) ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
compileLiteralExpression(
|
compileLiteralExpression(
|
||||||
|
@ -1847,7 +1847,9 @@ export class Program extends DiagnosticEmitter {
|
|||||||
if (node.kind == NodeKind.SIGNATURE) {
|
if (node.kind == NodeKind.SIGNATURE) {
|
||||||
let signature = this.resolveSignature(<SignatureNode>node, contextualTypeArguments, reportNotFound);
|
let signature = this.resolveSignature(<SignatureNode>node, contextualTypeArguments, reportNotFound);
|
||||||
if (!signature) return null;
|
if (!signature) return null;
|
||||||
return Type.u32.asFunction(signature);
|
return node.isNullable
|
||||||
|
? signature.type.asNullable()
|
||||||
|
: signature.type;
|
||||||
}
|
}
|
||||||
var typeNode = <TypeNode>node;
|
var typeNode = <TypeNode>node;
|
||||||
var simpleName = typeNode.name.text;
|
var simpleName = typeNode.name.text;
|
||||||
@ -1867,7 +1869,10 @@ export class Program extends DiagnosticEmitter {
|
|||||||
contextualTypeArguments,
|
contextualTypeArguments,
|
||||||
null
|
null
|
||||||
); // reports
|
); // reports
|
||||||
return instance ? instance.type : null;
|
if (!instance) return null;
|
||||||
|
return node.isNullable
|
||||||
|
? instance.type.asNullable()
|
||||||
|
: instance.type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
51
src/types.ts
51
src/types.ts
@ -170,6 +170,7 @@ export class Type {
|
|||||||
if (!this.cachedNullableType) {
|
if (!this.cachedNullableType) {
|
||||||
assert(!this.is(TypeFlags.NULLABLE));
|
assert(!this.is(TypeFlags.NULLABLE));
|
||||||
this.cachedNullableType = new Type(this.kind, this.flags | TypeFlags.NULLABLE, this.size);
|
this.cachedNullableType = new Type(this.kind, this.flags | TypeFlags.NULLABLE, this.size);
|
||||||
|
this.cachedNullableType.nonNullableType = this;
|
||||||
this.cachedNullableType.classReference = this.classReference; // either a class reference
|
this.cachedNullableType.classReference = this.classReference; // either a class reference
|
||||||
this.cachedNullableType.signatureReference = this.signatureReference; // or a function reference
|
this.cachedNullableType.signatureReference = this.signatureReference; // or a function reference
|
||||||
}
|
}
|
||||||
@ -177,27 +178,29 @@ export class Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Tests if a value of this type is assignable to a target of the specified type. */
|
/** Tests if a value of this type is assignable to a target of the specified type. */
|
||||||
isAssignableTo(target: Type, signednessIsImportant: bool = false): bool {
|
isAssignableTo(target: Type, signednessIsRelevant: bool = false): bool {
|
||||||
var currentClass: Class | null;
|
var currentClass: Class | null;
|
||||||
var targetClass: Class | null;
|
var targetClass: Class | null;
|
||||||
var currentFunction: Signature | null;
|
var currentFunction: Signature | null;
|
||||||
var targetFunction: Signature | null;
|
var targetFunction: Signature | null;
|
||||||
if (this.is(TypeFlags.REFERENCE)) {
|
if (this.is(TypeFlags.REFERENCE)) {
|
||||||
if (target.is(TypeFlags.REFERENCE)) {
|
if (target.is(TypeFlags.REFERENCE)) {
|
||||||
if (currentClass = this.classReference) {
|
if (!this.is(TypeFlags.NULLABLE) || target.is(TypeFlags.NULLABLE)) {
|
||||||
if (targetClass = target.classReference) {
|
if (currentClass = this.classReference) {
|
||||||
return currentClass.isAssignableTo(targetClass);
|
if (targetClass = target.classReference) {
|
||||||
}
|
return currentClass.isAssignableTo(targetClass);
|
||||||
} else if (currentFunction = this.signatureReference) {
|
}
|
||||||
if (targetFunction = target.signatureReference) {
|
} else if (currentFunction = this.signatureReference) {
|
||||||
return currentFunction.isAssignableTo(targetFunction);
|
if (targetFunction = target.signatureReference) {
|
||||||
|
return currentFunction.isAssignableTo(targetFunction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!target.is(TypeFlags.REFERENCE)) {
|
} else if (!target.is(TypeFlags.REFERENCE)) {
|
||||||
if (this.is(TypeFlags.INTEGER)) {
|
if (this.is(TypeFlags.INTEGER)) {
|
||||||
if (target.is(TypeFlags.INTEGER)) {
|
if (target.is(TypeFlags.INTEGER)) {
|
||||||
if (!signednessIsImportant || this.is(TypeFlags.SIGNED) == target.is(TypeFlags.SIGNED)) {
|
if (!signednessIsRelevant || this.is(TypeFlags.SIGNED) == target.is(TypeFlags.SIGNED)) {
|
||||||
return this.size <= target.size;
|
return this.size <= target.size;
|
||||||
}
|
}
|
||||||
} else if (target.kind == TypeKind.F32) {
|
} else if (target.kind == TypeKind.F32) {
|
||||||
@ -223,6 +226,21 @@ export class Type {
|
|||||||
|
|
||||||
/** Converts this type to its TypeScript representation. */
|
/** Converts this type to its TypeScript representation. */
|
||||||
toString(kindOnly: bool = false): string {
|
toString(kindOnly: bool = false): string {
|
||||||
|
if (!kindOnly && this.is(TypeFlags.REFERENCE)) {
|
||||||
|
let classReference = this.classReference;
|
||||||
|
if (classReference) {
|
||||||
|
return this.is(TypeFlags.NULLABLE)
|
||||||
|
? classReference.toString() + " | null"
|
||||||
|
: classReference.toString();
|
||||||
|
}
|
||||||
|
let signatureReference = this.signatureReference;
|
||||||
|
if (signatureReference) {
|
||||||
|
return this.is(TypeFlags.NULLABLE)
|
||||||
|
? "(" + signatureReference.toString(true) + ") | null"
|
||||||
|
: signatureReference.toString(true);
|
||||||
|
}
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
switch (this.kind) {
|
switch (this.kind) {
|
||||||
case TypeKind.I8: return "i8";
|
case TypeKind.I8: return "i8";
|
||||||
case TypeKind.I16: return "i16";
|
case TypeKind.I16: return "i16";
|
||||||
@ -231,23 +249,14 @@ export class Type {
|
|||||||
case TypeKind.ISIZE: return "isize";
|
case TypeKind.ISIZE: return "isize";
|
||||||
case TypeKind.U8: return "u8";
|
case TypeKind.U8: return "u8";
|
||||||
case TypeKind.U16: return "u16";
|
case TypeKind.U16: return "u16";
|
||||||
case TypeKind.U32: {
|
case TypeKind.U32: return "u32";
|
||||||
let functionType = this.signatureReference;
|
|
||||||
return kindOnly || !functionType ? "u32" : functionType.toString(true);
|
|
||||||
}
|
|
||||||
case TypeKind.U64: return "u64";
|
case TypeKind.U64: return "u64";
|
||||||
case TypeKind.USIZE: {
|
case TypeKind.USIZE: return "usize";
|
||||||
let classType = this.classReference;
|
|
||||||
return kindOnly || !classType ? "usize" : classType.toString();
|
|
||||||
}
|
|
||||||
case TypeKind.BOOL: return "bool";
|
case TypeKind.BOOL: return "bool";
|
||||||
case TypeKind.F32: return "f32";
|
case TypeKind.F32: return "f32";
|
||||||
case TypeKind.F64: return "f64";
|
case TypeKind.F64: return "f64";
|
||||||
|
default: assert(false);
|
||||||
case TypeKind.VOID: return "void";
|
case TypeKind.VOID: return "void";
|
||||||
default: {
|
|
||||||
assert(false);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
(type $Fi (func (param f64) (result i32)))
|
(type $Fi (func (param f64) (result i32)))
|
||||||
(type $v (func))
|
(type $v (func))
|
||||||
(import "env" "abort" (func $~lib/env/abort (param i32 i32 i32 i32)))
|
(import "env" "abort" (func $~lib/env/abort (param i32 i32 i32 i32)))
|
||||||
|
(global $instanceof/an (mut i32) (i32.const 0))
|
||||||
(memory $0 1)
|
(memory $0 1)
|
||||||
(data (i32.const 8) "\0d\00\00\00i\00n\00s\00t\00a\00n\00c\00e\00o\00f\00.\00t\00s")
|
(data (i32.const 8) "\0d\00\00\00i\00n\00s\00t\00a\00n\00c\00e\00o\00f\00.\00t\00s")
|
||||||
(export "memory" (memory $0))
|
(export "memory" (memory $0))
|
||||||
@ -14,7 +15,10 @@
|
|||||||
(func $instanceof/isI32<f64> (; 2 ;) (type $Fi) (param $0 f64) (result i32)
|
(func $instanceof/isI32<f64> (; 2 ;) (type $Fi) (param $0 f64) (result i32)
|
||||||
(i32.const 0)
|
(i32.const 0)
|
||||||
)
|
)
|
||||||
(func $start (; 3 ;) (type $v)
|
(func $instanceof/isI32<u32> (; 3 ;) (type $ii) (param $0 i32) (result i32)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(func $start (; 4 ;) (type $v)
|
||||||
(if
|
(if
|
||||||
(i32.eqz
|
(i32.eqz
|
||||||
(call $instanceof/isI32<i32>
|
(call $instanceof/isI32<i32>
|
||||||
@ -45,5 +49,48 @@
|
|||||||
(unreachable)
|
(unreachable)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
(if
|
||||||
|
(call $instanceof/isI32<u32>
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(call $~lib/env/abort
|
||||||
|
(i32.const 0)
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 40)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(get_global $instanceof/an)
|
||||||
|
(block
|
||||||
|
(call $~lib/env/abort
|
||||||
|
(i32.const 0)
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 43)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $instanceof/an
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(get_global $instanceof/an)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(call $~lib/env/abort
|
||||||
|
(i32.const 0)
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 46)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -37,13 +37,14 @@ function isI32<T>(v: T): bool {
|
|||||||
|
|
||||||
assert( isI32(0));
|
assert( isI32(0));
|
||||||
assert(!isI32(0.0));
|
assert(!isI32(0.0));
|
||||||
|
assert(!isI32(<u32>0)); // signedness is relevant
|
||||||
|
|
||||||
// TODO: what about nullables?
|
var an: A | null = null;
|
||||||
// var an: A | null;
|
assert(!(an instanceof A)); // TS: null is not an instance of A
|
||||||
// var bn: B | null;
|
assert( an instanceof A | null); // AS: null is an instance of A | null
|
||||||
//
|
an = changetype<A | null>(1);
|
||||||
// assert(an instanceof A);
|
assert( an instanceof A); // TS: non-null is an instance of A
|
||||||
// assert(bn instanceof A);
|
assert( an instanceof A | null); // AS: non-null is an instance of A | null
|
||||||
//
|
|
||||||
// assert(!(an instanceof B));
|
// TODO: keep track of nullability during flows, so this becomes precomputable:
|
||||||
// assert(bn instanceof B);
|
// assert(an !== null && an instanceof A);
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
(global $instanceof/b (mut i32) (i32.const 0))
|
(global $instanceof/b (mut i32) (i32.const 0))
|
||||||
(global $instanceof/i (mut i32) (i32.const 0))
|
(global $instanceof/i (mut i32) (i32.const 0))
|
||||||
(global $instanceof/f (mut f32) (f32.const 0))
|
(global $instanceof/f (mut f32) (f32.const 0))
|
||||||
|
(global $instanceof/an (mut i32) (i32.const 0))
|
||||||
(global $HEAP_BASE i32 (i32.const 40))
|
(global $HEAP_BASE i32 (i32.const 40))
|
||||||
(memory $0 1)
|
(memory $0 1)
|
||||||
(data (i32.const 8) "\0d\00\00\00i\00n\00s\00t\00a\00n\00c\00e\00o\00f\00.\00t\00s\00")
|
(data (i32.const 8) "\0d\00\00\00i\00n\00s\00t\00a\00n\00c\00e\00o\00f\00.\00t\00s\00")
|
||||||
@ -23,7 +24,12 @@
|
|||||||
(i32.const 0)
|
(i32.const 0)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
(func $start (; 3 ;) (type $v)
|
(func $instanceof/isI32<u32> (; 3 ;) (type $ii) (param $0 i32) (result i32)
|
||||||
|
(return
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $start (; 4 ;) (type $v)
|
||||||
(if
|
(if
|
||||||
(i32.eqz
|
(i32.eqz
|
||||||
(i32.const 1)
|
(i32.const 1)
|
||||||
@ -304,5 +310,90 @@
|
|||||||
(unreachable)
|
(unreachable)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i32.eqz
|
||||||
|
(call $instanceof/isI32<u32>
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(call $~lib/env/abort
|
||||||
|
(i32.const 0)
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 40)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i32.eqz
|
||||||
|
(i32.ne
|
||||||
|
(get_global $instanceof/an)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(call $~lib/env/abort
|
||||||
|
(i32.const 0)
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 43)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(call $~lib/env/abort
|
||||||
|
(i32.const 0)
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 44)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $instanceof/an
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i32.ne
|
||||||
|
(get_global $instanceof/an)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(call $~lib/env/abort
|
||||||
|
(i32.const 0)
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 46)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(call $~lib/env/abort
|
||||||
|
(i32.const 0)
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 47)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user