diff --git a/src/compiler.ts b/src/compiler.ts index 79b5bd5144..0123c30bea 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -3521,10 +3521,10 @@ export class Compiler extends DiagnosticEmitter { if (currentType != contextualType.nonNullableType) { // allow assigning non-nullable to nullable if (constraints & Constraints.CONV_EXPLICIT) { expr = this.convertExpression(expr, currentType, contextualType, true, expression); - this.currentType = contextualType; + this.currentType = currentType = contextualType; } else if (constraints & Constraints.CONV_IMPLICIT) { expr = this.convertExpression(expr, currentType, contextualType, false, expression); - this.currentType = contextualType; + this.currentType = currentType = contextualType; } } if (wrap) expr = this.ensureSmallIntegerWrap(expr, currentType); diff --git a/src/flow.ts b/src/flow.ts index 998e9e191d..91e64789df 100644 --- a/src/flow.ts +++ b/src/flow.ts @@ -1351,6 +1351,13 @@ export class Flow { case UnaryOp.ClzI32: case UnaryOp.CtzI32: case UnaryOp.PopcntI32: return type.size < 7; + + // sign extensions overflow if result can have high garbage bits in the target type + case UnaryOp.Extend8I32: return type.size < (type.isUnsignedIntegerValue ? 32 : 8); + case UnaryOp.Extend8I64: return type.size < (type.isUnsignedIntegerValue ? 64 : 8); + case UnaryOp.Extend16I32: return type.size < (type.isUnsignedIntegerValue ? 32 : 16); + case UnaryOp.Extend16I64: return type.size < (type.isUnsignedIntegerValue ? 64 : 16); + case UnaryOp.Extend32I64: return type.size < (type.isUnsignedIntegerValue ? 64 : 32); } break; } diff --git a/tests/compiler/abi.untouched.wat b/tests/compiler/abi.untouched.wat index 06e2ca21e8..dd4b94e38b 100644 --- a/tests/compiler/abi.untouched.wat +++ b/tests/compiler/abi.untouched.wat @@ -88,7 +88,6 @@ local.set $0 end local.get $0 - i32.extend8_s i32.eqz i32.eqz if @@ -176,7 +175,6 @@ ) (func $abi/exportedExported (result i32) call $abi/exported - i32.extend8_s ) (func $abi/exportedInternal (result i32) call $abi/internal diff --git a/tests/compiler/cast.json b/tests/compiler/cast.json new file mode 100644 index 0000000000..1bdd02b1be --- /dev/null +++ b/tests/compiler/cast.json @@ -0,0 +1,4 @@ +{ + "asc_flags": [ + ] +} diff --git a/tests/compiler/cast.optimized.wat b/tests/compiler/cast.optimized.wat new file mode 100644 index 0000000000..23da3862e2 --- /dev/null +++ b/tests/compiler/cast.optimized.wat @@ -0,0 +1,4 @@ +(module + (memory $0 0) + (export "memory" (memory $0)) +) diff --git a/tests/compiler/cast.ts b/tests/compiler/cast.ts new file mode 100644 index 0000000000..cd81a6dac2 --- /dev/null +++ b/tests/compiler/cast.ts @@ -0,0 +1,96 @@ +function test(x: T): U { + // @ts-ignore + var y = x as U; + // @ts-ignore + return y; +} + +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); + +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); + +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); + +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); + +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); + +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); + +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); + +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); + +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); +test(0); diff --git a/tests/compiler/cast.untouched.wat b/tests/compiler/cast.untouched.wat new file mode 100644 index 0000000000..62ab3dba02 --- /dev/null +++ b/tests/compiler/cast.untouched.wat @@ -0,0 +1,825 @@ +(module + (type $i32_=>_i32 (func (param i32) (result i32))) + (type $i32_=>_i64 (func (param i32) (result i64))) + (type $i64_=>_i32 (func (param i64) (result i32))) + (type $i64_=>_i64 (func (param i64) (result i64))) + (type $none_=>_none (func)) + (global $~lib/memory/__data_end i32 (i32.const 8)) + (global $~lib/memory/__stack_pointer (mut i32) (i32.const 16392)) + (global $~lib/memory/__heap_base i32 (i32.const 16392)) + (memory $0 0) + (table $0 1 funcref) + (elem $0 (i32.const 1)) + (export "memory" (memory $0)) + (start $~start) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + i32.extend8_s + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + i32.extend8_s + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + i32.extend8_s + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + i32.extend8_s + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i64) + (local $1 i64) + local.get $0 + i32.extend8_s + i64.extend_i32_s + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i64) + (local $1 i64) + local.get $0 + i32.extend8_s + i64.extend_i32_s + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + i32.const 255 + i32.and + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + i32.const 255 + i32.and + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + i32.const 255 + i32.and + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + i32.const 255 + i32.and + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i64) + (local $1 i64) + local.get $0 + i32.const 255 + i32.and + i64.extend_i32_u + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i64) + (local $1 i64) + local.get $0 + i32.const 255 + i32.and + i64.extend_i32_u + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + i32.extend16_s + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + i32.extend16_s + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i64) + (local $1 i64) + local.get $0 + i32.extend16_s + i64.extend_i32_s + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i64) + (local $1 i64) + local.get $0 + i32.extend16_s + i64.extend_i32_s + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + i32.const 65535 + i32.and + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + i32.const 65535 + i32.and + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i64) + (local $1 i64) + local.get $0 + i32.const 65535 + i32.and + i64.extend_i32_u + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i64) + (local $1 i64) + local.get $0 + i32.const 65535 + i32.and + i64.extend_i32_u + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i64) + (local $1 i64) + local.get $0 + i64.extend_i32_s + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i64) + (local $1 i64) + local.get $0 + i64.extend_i32_s + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i64) + (local $1 i64) + local.get $0 + i64.extend_i32_u + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i64) + (local $1 i64) + local.get $0 + i64.extend_i32_u + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i64) (result i32) + (local $1 i32) + local.get $0 + i32.wrap_i64 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i64) (result i32) + (local $1 i32) + local.get $0 + i32.wrap_i64 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i64) (result i32) + (local $1 i32) + local.get $0 + i32.wrap_i64 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i64) (result i32) + (local $1 i32) + local.get $0 + i32.wrap_i64 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i64) (result i32) + (local $1 i32) + local.get $0 + i32.wrap_i64 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i64) (result i32) + (local $1 i32) + local.get $0 + i32.wrap_i64 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i64) (result i64) + (local $1 i64) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i64) (result i64) + (local $1 i64) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i64) (result i32) + (local $1 i32) + local.get $0 + i64.const 0 + i64.ne + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i64) (result i32) + (local $1 i32) + local.get $0 + i32.wrap_i64 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i64) (result i32) + (local $1 i32) + local.get $0 + i32.wrap_i64 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i64) (result i32) + (local $1 i32) + local.get $0 + i32.wrap_i64 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i64) (result i32) + (local $1 i32) + local.get $0 + i32.wrap_i64 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i64) (result i32) + (local $1 i32) + local.get $0 + i32.wrap_i64 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i64) (result i32) + (local $1 i32) + local.get $0 + i32.wrap_i64 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i64) (result i64) + (local $1 i64) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i64) (result i64) + (local $1 i64) + local.get $0 + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i64) (result i32) + (local $1 i32) + local.get $0 + i64.const 0 + i64.ne + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + i32.const 0 + i32.ne + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + i32.const 0 + i32.ne + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + i32.const 0 + i32.ne + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + i32.const 0 + i32.ne + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + i32.const 0 + i32.ne + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + i32.const 0 + i32.ne + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i64) + (local $1 i64) + local.get $0 + i32.const 0 + i32.ne + i64.extend_i32_u + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i64) + (local $1 i64) + local.get $0 + i32.const 0 + i32.ne + i64.extend_i32_u + local.set $1 + local.get $1 + ) + (func $cast/test (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + local.set $1 + local.get $1 + ) + (func $start:cast + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i64.const 0 + call $cast/test + drop + i64.const 0 + call $cast/test + drop + i64.const 0 + call $cast/test + drop + i64.const 0 + call $cast/test + drop + i64.const 0 + call $cast/test + drop + i64.const 0 + call $cast/test + drop + i64.const 0 + call $cast/test + drop + i64.const 0 + call $cast/test + drop + i64.const 0 + call $cast/test + drop + i64.const 0 + call $cast/test + drop + i64.const 0 + call $cast/test + drop + i64.const 0 + call $cast/test + drop + i64.const 0 + call $cast/test + drop + i64.const 0 + call $cast/test + drop + i64.const 0 + call $cast/test + drop + i64.const 0 + call $cast/test + drop + i64.const 0 + call $cast/test + drop + i64.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + i32.const 0 + call $cast/test + drop + ) + (func $~start + call $start:cast + ) +) diff --git a/tests/compiler/many-locals.untouched.wat b/tests/compiler/many-locals.untouched.wat index 8a263436ce..4b5c0c39ff 100644 --- a/tests/compiler/many-locals.untouched.wat +++ b/tests/compiler/many-locals.untouched.wat @@ -805,7 +805,6 @@ end i32.const 42 call $many-locals/testI8 - i32.extend8_s i32.const 42 i32.eq i32.eqz diff --git a/tests/compiler/std/typedarray.optimized.wat b/tests/compiler/std/typedarray.optimized.wat index 2ed4585d84..4c5b236587 100644 --- a/tests/compiler/std/typedarray.optimized.wat +++ b/tests/compiler/std/typedarray.optimized.wat @@ -5713,9 +5713,7 @@ (func $std/typedarray/testArrayEvery<~lib/typedarray/Int8Array,i8>~anonymous|0 (param $0 i32) (param $1 i32) (param $2 i32) (result i32) local.get $0 i32.extend8_s - i32.const 2 - i32.rem_s - i32.const 255 + i32.const 1 i32.and i32.eqz ) @@ -5728,9 +5726,7 @@ (func $std/typedarray/testArrayEvery<~lib/typedarray/Int16Array,i16>~anonymous|0 (param $0 i32) (param $1 i32) (param $2 i32) (result i32) local.get $0 i32.extend16_s - i32.const 2 - i32.rem_s - i32.const 65535 + i32.const 1 i32.and i32.eqz ) diff --git a/tests/compiler/std/typedarray.untouched.wat b/tests/compiler/std/typedarray.untouched.wat index e137c9bc55..89a3c2a52f 100644 --- a/tests/compiler/std/typedarray.untouched.wat +++ b/tests/compiler/std/typedarray.untouched.wat @@ -10222,7 +10222,6 @@ i32.extend8_s i32.const 2 i32.rem_s - i32.extend8_s i32.const 0 i32.eq ) @@ -10440,7 +10439,6 @@ i32.extend16_s i32.const 2 i32.rem_s - i32.extend16_s i32.const 0 i32.eq )