Require exact type in instanceof basicType, fixes #493

This commit is contained in:
dcode 2019-02-21 02:09:06 +01:00
parent 6b495f71d0
commit 8d2194f045
4 changed files with 330 additions and 61 deletions

View File

@ -6138,24 +6138,32 @@ export class Compiler extends DiagnosticEmitter {
// time of implementation, this seemed more useful because dynamic rhs expressions are not // time of implementation, this seemed more useful because dynamic rhs expressions are not
// possible in AS anyway. // possible in AS anyway.
var expr = this.compileExpressionRetainType(expression.expression, this.options.usizeType, WrapMode.NONE); var expr = this.compileExpressionRetainType(expression.expression, this.options.usizeType, WrapMode.NONE);
var type = this.currentType; var actualType = this.currentType;
var isType = this.resolver.resolveType( var expectedType = this.resolver.resolveType(
expression.isType, expression.isType,
this.currentFlow.actualFunction this.currentFlow.actualFunction
); );
this.currentType = Type.bool; this.currentType = Type.bool;
if (!isType) return module.createUnreachable(); if (!expectedType) return module.createUnreachable();
return type.is(TypeFlags.NULLABLE) && !isType.is(TypeFlags.NULLABLE)
? type.nonNullableType.isAssignableTo(isType) // instanceof <basicType> must be exact
? module.createBinary( // not precomputeable if (!expectedType.is(TypeFlags.REFERENCE)) {
type.is(TypeFlags.LONG) return module.createI32(actualType == expectedType ? 1 : 0);
}
// <nullable> instanceof <nonNullable> must be != 0
if (
actualType.is(TypeFlags.NULLABLE) && !expectedType.is(TypeFlags.NULLABLE) &&
actualType.nonNullableType.isAssignableTo(expectedType)
) {
return module.createBinary(
actualType.is(TypeFlags.LONG)
? BinaryOp.NeI64 ? BinaryOp.NeI64
: BinaryOp.NeI32, : BinaryOp.NeI32,
expr, expr,
type.toNativeZero(module) actualType.toNativeZero(module)
) );
: module.createI32(0) }
: module.createI32(type.isAssignableTo(isType, true) ? 1 : 0); return module.createI32(actualType.isAssignableTo(expectedType) ? 1 : 0);
} }
compileLiteralExpression( compileLiteralExpression(

View File

@ -15,7 +15,7 @@
if if
i32.const 0 i32.const 0
i32.const 8 i32.const 8
i32.const 43 i32.const 68
i32.const 0 i32.const 0
call $~lib/env/abort call $~lib/env/abort
unreachable unreachable
@ -27,7 +27,7 @@
if if
i32.const 0 i32.const 0
i32.const 8 i32.const 8
i32.const 46 i32.const 71
i32.const 0 i32.const 0
call $~lib/env/abort call $~lib/env/abort
unreachable unreachable

View File

@ -4,27 +4,51 @@ class B extends A {}
var a: A; var a: A;
var b: B; var b: B;
var i: i32; var i: i32;
var I: i64;
var f: f32; var f: f32;
var F: f64;
assert( a instanceof A ); assert( a instanceof A );
assert( b instanceof A ); assert( b instanceof A );
assert(!(i instanceof A)); assert(!(i instanceof A));
assert(!(I instanceof A));
assert(!(f instanceof A)); assert(!(f instanceof A));
assert(!(F instanceof A));
assert(!(a instanceof B)); assert(!(a instanceof B));
assert( b instanceof B ); assert( b instanceof B );
assert(!(i instanceof B)); assert(!(i instanceof B));
assert(!(I instanceof B));
assert(!(f instanceof B)); assert(!(f instanceof B));
assert(!(F instanceof B));
assert(!(a instanceof i32)); assert(!(a instanceof i32));
assert(!(b instanceof i32)); assert(!(b instanceof i32));
assert( i instanceof i32 ); assert( i instanceof i32 );
assert(!(I instanceof i32));
assert(!(f instanceof i32)); assert(!(f instanceof i32));
assert(!(F instanceof i32));
assert(!(a instanceof i64));
assert(!(b instanceof i64));
assert(!(i instanceof i64));
assert( I instanceof i64 );
assert(!(f instanceof i64));
assert(!(F instanceof i64));
assert(!(a instanceof f32)); assert(!(a instanceof f32));
assert(!(b instanceof f32)); assert(!(b instanceof f32));
assert(!(i instanceof f32)); assert(!(i instanceof f32));
assert(!(I instanceof f32));
assert( f instanceof f32 ); assert( f instanceof f32 );
assert(!(F instanceof f32));
assert(!(a instanceof f64));
assert(!(b instanceof f64));
assert(!(i instanceof f64));
assert(!(I instanceof f64));
assert(!(f instanceof f64));
assert( F instanceof f64 );
function isI32<T>(v: T): bool { function isI32<T>(v: T): bool {
// should eliminate non-applicable branches (see fixture) // should eliminate non-applicable branches (see fixture)
@ -38,13 +62,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 assert(!isI32(<u32>0)); // signedness is relevant
assert(!isI32(<u16>0)); // byte size is relevant
var an: A | null = null; var an: A | null = null;
assert(!(an instanceof A)); // TS: null is not an instance of A assert(!(an instanceof A)); // TS: ==null is not an instance of A
assert( an instanceof A | null); // AS: null is an instance of A | null assert( an instanceof A | null); // AS: ==null is an instance of A | null
an = changetype<A | null>(1); an = changetype<A | null>(1);
assert( an instanceof A); // TS: non-null is an instance of A assert( an instanceof A); // TS: !=null is an instance of A
assert( an instanceof A | null); // AS: non-null is an instance of A | null assert( an instanceof A | null); // AS: !=null is an instance of A | null
// TODO: keep track of nullability during flows, so this becomes precomputable: // TODO: keep track of nullability during flows, so this becomes precomputable:
// assert(an !== null && an instanceof A); // assert(an !== null && an instanceof A);

View File

@ -11,7 +11,9 @@
(global $instanceof/a (mut i32) (i32.const 0)) (global $instanceof/a (mut i32) (i32.const 0))
(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/I (mut i64) (i64.const 0))
(global $instanceof/f (mut f32) (f32.const 0)) (global $instanceof/f (mut f32) (f32.const 0))
(global $instanceof/F (mut f64) (f64.const 0))
(global $instanceof/an (mut i32) (i32.const 0)) (global $instanceof/an (mut i32) (i32.const 0))
(global $~lib/memory/HEAP_BASE i32 (i32.const 40)) (global $~lib/memory/HEAP_BASE i32 (i32.const 40))
(export "memory" (memory $0)) (export "memory" (memory $0))
@ -29,30 +31,13 @@
i32.const 0 i32.const 0
return return
) )
(func $start:instanceof (; 4 ;) (type $_) (func $instanceof/isI32<u16> (; 4 ;) (type $ii) (param $0 i32) (result i32)
i32.const 0
return
)
(func $start:instanceof (; 5 ;) (type $_)
i32.const 1 i32.const 1
i32.eqz i32.eqz
if
i32.const 0
i32.const 8
i32.const 9
i32.const 0
call $~lib/env/abort
unreachable
end
i32.const 1
i32.eqz
if
i32.const 0
i32.const 8
i32.const 10
i32.const 0
call $~lib/env/abort
unreachable
end
i32.const 0
i32.eqz
i32.eqz
if if
i32.const 0 i32.const 0
i32.const 8 i32.const 8
@ -61,8 +46,7 @@
call $~lib/env/abort call $~lib/env/abort
unreachable unreachable
end end
i32.const 0 i32.const 1
i32.eqz
i32.eqz i32.eqz
if if
i32.const 0 i32.const 0
@ -75,6 +59,17 @@
i32.const 0 i32.const 0
i32.eqz i32.eqz
i32.eqz i32.eqz
if
i32.const 0
i32.const 8
i32.const 13
i32.const 0
call $~lib/env/abort
unreachable
end
i32.const 0
i32.eqz
i32.eqz
if if
i32.const 0 i32.const 0
i32.const 8 i32.const 8
@ -83,7 +78,8 @@
call $~lib/env/abort call $~lib/env/abort
unreachable unreachable
end end
i32.const 1 i32.const 0
i32.eqz
i32.eqz i32.eqz
if if
i32.const 0 i32.const 0
@ -110,13 +106,12 @@
if if
i32.const 0 i32.const 0
i32.const 8 i32.const 8
i32.const 17 i32.const 18
i32.const 0 i32.const 0
call $~lib/env/abort call $~lib/env/abort
unreachable unreachable
end end
i32.const 0 i32.const 1
i32.eqz
i32.eqz i32.eqz
if if
i32.const 0 i32.const 0
@ -137,7 +132,8 @@
call $~lib/env/abort call $~lib/env/abort
unreachable unreachable
end end
i32.const 1 i32.const 0
i32.eqz
i32.eqz i32.eqz
if if
i32.const 0 i32.const 0
@ -164,7 +160,7 @@
if if
i32.const 0 i32.const 0
i32.const 8 i32.const 8
i32.const 24 i32.const 23
i32.const 0 i32.const 0
call $~lib/env/abort call $~lib/env/abort
unreachable unreachable
@ -202,18 +198,104 @@
unreachable unreachable
end end
i32.const 0 i32.const 0
call $instanceof/isI32<i32> i32.eqz
i32.eqz i32.eqz
if if
i32.const 0 i32.const 0
i32.const 8 i32.const 8
i32.const 38 i32.const 28
i32.const 0 i32.const 0
call $~lib/env/abort call $~lib/env/abort
unreachable unreachable
end end
f64.const 0 i32.const 0
call $instanceof/isI32<f64> i32.eqz
i32.eqz
if
i32.const 0
i32.const 8
i32.const 29
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 30
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 0
i32.eqz
i32.eqz
if
i32.const 0
i32.const 8
i32.const 33
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 34
i32.const 0
call $~lib/env/abort
unreachable
end
i32.const 1
i32.eqz
if
i32.const 0
i32.const 8
i32.const 35
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 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 0
i32.eqz i32.eqz
i32.eqz i32.eqz
if if
@ -225,7 +307,6 @@
unreachable unreachable
end end
i32.const 0 i32.const 0
call $instanceof/isI32<u32>
i32.eqz i32.eqz
i32.eqz i32.eqz
if if
@ -236,6 +317,161 @@
call $~lib/env/abort call $~lib/env/abort
unreachable unreachable
end end
i32.const 0
i32.eqz
i32.eqz
if
i32.const 0
i32.const 8
i32.const 41
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 42
i32.const 0
call $~lib/env/abort
unreachable
end
i32.const 1
i32.eqz
if
i32.const 0
i32.const 8
i32.const 43
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 44
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 46
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 47
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 48
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 49
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 50
i32.const 0
call $~lib/env/abort
unreachable
end
i32.const 1
i32.eqz
if
i32.const 0
i32.const 8
i32.const 51
i32.const 0
call $~lib/env/abort
unreachable
end
i32.const 0
call $instanceof/isI32<i32>
i32.eqz
if
i32.const 0
i32.const 8
i32.const 62
i32.const 0
call $~lib/env/abort
unreachable
end
f64.const 0
call $instanceof/isI32<f64>
i32.eqz
i32.eqz
if
i32.const 0
i32.const 8
i32.const 63
i32.const 0
call $~lib/env/abort
unreachable
end
i32.const 0
call $instanceof/isI32<u32>
i32.eqz
i32.eqz
if
i32.const 0
i32.const 8
i32.const 64
i32.const 0
call $~lib/env/abort
unreachable
end
i32.const 0
call $instanceof/isI32<u16>
i32.eqz
i32.eqz
if
i32.const 0
i32.const 8
i32.const 65
i32.const 0
call $~lib/env/abort
unreachable
end
global.get $instanceof/an global.get $instanceof/an
i32.const 0 i32.const 0
i32.ne i32.ne
@ -244,7 +480,7 @@
if if
i32.const 0 i32.const 0
i32.const 8 i32.const 8
i32.const 43 i32.const 68
i32.const 0 i32.const 0
call $~lib/env/abort call $~lib/env/abort
unreachable unreachable
@ -254,7 +490,7 @@
if if
i32.const 0 i32.const 0
i32.const 8 i32.const 8
i32.const 44 i32.const 69
i32.const 0 i32.const 0
call $~lib/env/abort call $~lib/env/abort
unreachable unreachable
@ -268,7 +504,7 @@
if if
i32.const 0 i32.const 0
i32.const 8 i32.const 8
i32.const 46 i32.const 71
i32.const 0 i32.const 0
call $~lib/env/abort call $~lib/env/abort
unreachable unreachable
@ -278,15 +514,15 @@
if if
i32.const 0 i32.const 0
i32.const 8 i32.const 8
i32.const 47 i32.const 72
i32.const 0 i32.const 0
call $~lib/env/abort call $~lib/env/abort
unreachable unreachable
end end
) )
(func $start (; 5 ;) (type $_) (func $start (; 6 ;) (type $_)
call $start:instanceof call $start:instanceof
) )
(func $null (; 6 ;) (type $_) (func $null (; 7 ;) (type $_)
) )
) )