diff --git a/tslang/lib/TypeScript/MLIRGenCast.cpp b/tslang/lib/TypeScript/MLIRGenCast.cpp index 2c6713628..0ae05704b 100644 --- a/tslang/lib/TypeScript/MLIRGenCast.cpp +++ b/tslang/lib/TypeScript/MLIRGenCast.cpp @@ -1603,6 +1603,18 @@ namespace mlirgen { return castNullableToString(location, type, value, baseType, genContext); } + + // A union of literals, as `c ? 1 : 0` is (`0 | 1`), is stored as its literals' type: cast + // it to that type first. Cast straight to another type (`index`, a tuple field's type), + // it reached the lowering as a union, which sign-extended the union itself. + if (!toAny) + { + if (auto literalBaseType = getLiteralUnionBaseType(location, valueType); literalBaseType && literalBaseType != type) + { + CAST_A(baseValue, location, literalBaseType, value, genContext); + return cast(location, type, baseValue, genContext); + } + } } // TODO: issue is with casting to Boolean type from union type for example, you need to cast optional type to boolean to check value diff --git a/tslang/test/tester/CMakeLists.txt b/tslang/test/tester/CMakeLists.txt index 891d8b56e..ddafdf95d 100644 --- a/tslang/test/tester/CMakeLists.txt +++ b/tslang/test/tester/CMakeLists.txt @@ -273,6 +273,7 @@ tslang_add_test(NAME test-compile-00-equals COMMAND test-runner "${PROJECT_SOURC tslang_add_test(NAME test-compile-00-bool-arith-ops COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00bool_arith_ops.ts") tslang_add_test(NAME test-compile-00-int64-shift-bitwise COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00int64_shift_bitwise.ts") tslang_add_test(NAME test-compile-00-literal-union-arith COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00literal_union_arith.ts") +tslang_add_test(NAME test-compile-00-literal-union-cast COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00literal_union_cast.ts") tslang_add_test(NAME test-compile-00-bool-const-array COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00bool_const_array.ts") tslang_add_test(NAME test-compile-00-mixed-type-ops COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00mixed_type_ops.ts") tslang_add_test(NAME test-compile-00-generator-manual-next COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00generator_manual_next.ts") @@ -808,6 +809,7 @@ tslang_add_test(NAME test-jit-00-equals COMMAND test-runner -jit "${PROJECT_SOUR tslang_add_test(NAME test-jit-00-bool-arith-ops COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00bool_arith_ops.ts") tslang_add_test(NAME test-jit-00-int64-shift-bitwise COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00int64_shift_bitwise.ts") tslang_add_test(NAME test-jit-00-literal-union-arith COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00literal_union_arith.ts") +tslang_add_test(NAME test-jit-00-literal-union-cast COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00literal_union_cast.ts") tslang_add_test(NAME test-jit-00-bool-const-array COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00bool_const_array.ts") tslang_add_test(NAME test-jit-00-mixed-type-ops COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00mixed_type_ops.ts") tslang_add_test(NAME test-jit-00-generator-manual-next COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00generator_manual_next.ts") @@ -1799,6 +1801,7 @@ set(TSLANG_CORPUS 00bool_arith_ops.ts 00int64_shift_bitwise.ts 00literal_union_arith.ts + 00literal_union_cast.ts 00bool_const_array.ts 00break_continue_scope_exit.ts 00break_continue.ts diff --git a/tslang/test/tester/tests/00literal_union_cast.ts b/tslang/test/tester/tests/00literal_union_cast.ts new file mode 100644 index 000000000..93d4ea59c --- /dev/null +++ b/tslang/test/tester/tests/00literal_union_cast.ts @@ -0,0 +1,39 @@ +// regression test: a union of literals, as a ternary of two literals is, converts to another +// numeric type through its literals' type. +// +// bug found and fixed: `c ? 1 : 0` is the union `0 | 1`; cast straight to `index` (a variable, a +// parameter, a tuple field) it reached the lowering as a union, and `llvm.sext` of the union failed +// with no source location. + +type Vec = [items: [_0: Opaque | null], count: index]; + +function make(item: Opaque | null): Vec { + return [[item], item ? 1 : 0]; +} + +function takeIndex(n: index): index { + return n; +} + +function main() { + let c = true; + let off = false; + + let x: index = c ? 1 : 0; + assert(x == 1); + + let y: index = off ? 1 : 0; + assert(y == 0); + + assert(takeIndex(c ? 7 : 3) == 7); + + let n: number = c ? 1 : 0; + assert(n == 1); + + let w: s64 = off ? 2 : 5; + assert(w == 5); + + assert(make(null).count == 0); + + print("done."); +}