Skip to content

Commit 8d2194f

Browse files
committed
Require exact type in instanceof basicType, fixes AssemblyScript#493
1 parent 6b495f7 commit 8d2194f

File tree

4 files changed

+315
-46
lines changed

4 files changed

+315
-46
lines changed

src/compiler.ts

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6138,24 +6138,32 @@ export class Compiler extends DiagnosticEmitter {
61386138
// time of implementation, this seemed more useful because dynamic rhs expressions are not
61396139
// possible in AS anyway.
61406140
var expr = this.compileExpressionRetainType(expression.expression, this.options.usizeType, WrapMode.NONE);
6141-
var type = this.currentType;
6142-
var isType = this.resolver.resolveType(
6141+
var actualType = this.currentType;
6142+
var expectedType = this.resolver.resolveType(
61436143
expression.isType,
61446144
this.currentFlow.actualFunction
61456145
);
61466146
this.currentType = Type.bool;
6147-
if (!isType) return module.createUnreachable();
6148-
return type.is(TypeFlags.NULLABLE) && !isType.is(TypeFlags.NULLABLE)
6149-
? type.nonNullableType.isAssignableTo(isType)
6150-
? module.createBinary( // not precomputeable
6151-
type.is(TypeFlags.LONG)
6152-
? BinaryOp.NeI64
6153-
: BinaryOp.NeI32,
6154-
expr,
6155-
type.toNativeZero(module)
6156-
)
6157-
: module.createI32(0)
6158-
: module.createI32(type.isAssignableTo(isType, true) ? 1 : 0);
6147+
if (!expectedType) return module.createUnreachable();
6148+
6149+
// instanceof <basicType> must be exact
6150+
if (!expectedType.is(TypeFlags.REFERENCE)) {
6151+
return module.createI32(actualType == expectedType ? 1 : 0);
6152+
}
6153+
// <nullable> instanceof <nonNullable> must be != 0
6154+
if (
6155+
actualType.is(TypeFlags.NULLABLE) && !expectedType.is(TypeFlags.NULLABLE) &&
6156+
actualType.nonNullableType.isAssignableTo(expectedType)
6157+
) {
6158+
return module.createBinary(
6159+
actualType.is(TypeFlags.LONG)
6160+
? BinaryOp.NeI64
6161+
: BinaryOp.NeI32,
6162+
expr,
6163+
actualType.toNativeZero(module)
6164+
);
6165+
}
6166+
return module.createI32(actualType.isAssignableTo(expectedType) ? 1 : 0);
61596167
}
61606168

61616169
compileLiteralExpression(

tests/compiler/instanceof.optimized.wat

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
if
1616
i32.const 0
1717
i32.const 8
18-
i32.const 43
18+
i32.const 68
1919
i32.const 0
2020
call $~lib/env/abort
2121
unreachable
@@ -27,7 +27,7 @@
2727
if
2828
i32.const 0
2929
i32.const 8
30-
i32.const 46
30+
i32.const 71
3131
i32.const 0
3232
call $~lib/env/abort
3333
unreachable

tests/compiler/instanceof.ts

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,51 @@ class B extends A {}
44
var a: A;
55
var b: B;
66
var i: i32;
7+
var I: i64;
78
var f: f32;
9+
var F: f64;
810

911
assert( a instanceof A );
1012
assert( b instanceof A );
1113
assert(!(i instanceof A));
14+
assert(!(I instanceof A));
1215
assert(!(f instanceof A));
16+
assert(!(F instanceof A));
1317

1418
assert(!(a instanceof B));
1519
assert( b instanceof B );
1620
assert(!(i instanceof B));
21+
assert(!(I instanceof B));
1722
assert(!(f instanceof B));
23+
assert(!(F instanceof B));
1824

1925
assert(!(a instanceof i32));
2026
assert(!(b instanceof i32));
2127
assert( i instanceof i32 );
28+
assert(!(I instanceof i32));
2229
assert(!(f instanceof i32));
30+
assert(!(F instanceof i32));
31+
32+
assert(!(a instanceof i64));
33+
assert(!(b instanceof i64));
34+
assert(!(i instanceof i64));
35+
assert( I instanceof i64 );
36+
assert(!(f instanceof i64));
37+
assert(!(F instanceof i64));
2338

2439
assert(!(a instanceof f32));
2540
assert(!(b instanceof f32));
2641
assert(!(i instanceof f32));
42+
assert(!(I instanceof f32));
2743
assert( f instanceof f32 );
44+
assert(!(F instanceof f32));
45+
46+
assert(!(a instanceof f64));
47+
assert(!(b instanceof f64));
48+
assert(!(i instanceof f64));
49+
assert(!(I instanceof f64));
50+
assert(!(f instanceof f64));
51+
assert( F instanceof f64 );
2852

2953
function isI32<T>(v: T): bool {
3054
// should eliminate non-applicable branches (see fixture)
@@ -38,13 +62,14 @@ function isI32<T>(v: T): bool {
3862
assert( isI32(0));
3963
assert(!isI32(0.0));
4064
assert(!isI32(<u32>0)); // signedness is relevant
65+
assert(!isI32(<u16>0)); // byte size is relevant
4166

4267
var an: A | null = null;
43-
assert(!(an instanceof A)); // TS: null is not an instance of A
44-
assert( an instanceof A | null); // AS: null is an instance of A | null
68+
assert(!(an instanceof A)); // TS: ==null is not an instance of A
69+
assert( an instanceof A | null); // AS: ==null is an instance of A | null
4570
an = changetype<A | null>(1);
46-
assert( an instanceof A); // TS: non-null is an instance of A
47-
assert( an instanceof A | null); // AS: non-null is an instance of A | null
71+
assert( an instanceof A); // TS: !=null is an instance of A
72+
assert( an instanceof A | null); // AS: !=null is an instance of A | null
4873

4974
// TODO: keep track of nullability during flows, so this becomes precomputable:
5075
// assert(an !== null && an instanceof A);

0 commit comments

Comments
 (0)