diff --git a/tslang/include/TypeScript/MLIRLogic/MLIRCodeLogic.h b/tslang/include/TypeScript/MLIRLogic/MLIRCodeLogic.h index 296661d43..9362dfaac 100644 --- a/tslang/include/TypeScript/MLIRLogic/MLIRCodeLogic.h +++ b/tslang/include/TypeScript/MLIRLogic/MLIRCodeLogic.h @@ -1325,7 +1325,13 @@ class MLIRPropertyAccessCodeLogic { name = strAttr.getValue(); } - } + } + + // the object is accessed as another value of it - a union as its base type + void setExpression(mlir::Value newExpression) + { + expression = newExpression; + } mlir::Value Enum(mlir_ts::EnumType enumType) { diff --git a/tslang/lib/TypeScript/MLIRGenAccessCall.cpp b/tslang/lib/TypeScript/MLIRGenAccessCall.cpp index 5bbf0edac..e6c9f9ac1 100644 --- a/tslang/lib/TypeScript/MLIRGenAccessCall.cpp +++ b/tslang/lib/TypeScript/MLIRGenAccessCall.cpp @@ -169,8 +169,14 @@ namespace mlirgen { LLVM_DEBUG(llvm::dbgs() << "\n!! mlirGenPropertyAccessExpressionBaseLogic: union type " << baseType << "\n";); actualType = baseType; + // The value is the base type as well: a union of object types sharing one layout + // (`{ kind: "a", r: number } | { kind: "b", r: number }`) is stored as it. Left a + // union, the field was read through the union's reference - a PropertyRef the + // verifier rejects. + objectValue = builder.create(location, baseType, objectValue); + cl.setExpression(objectValue); } - } + } // class member access auto classAccessWithObject = [&](mlir_ts::ClassType classType, mlir::Value objectValue) { diff --git a/tslang/test/tester/CMakeLists.txt b/tslang/test/tester/CMakeLists.txt index f5087e746..ea7eee333 100644 --- a/tslang/test/tester/CMakeLists.txt +++ b/tslang/test/tester/CMakeLists.txt @@ -532,6 +532,7 @@ tslang_add_test(NAME test-compile-00-safe-cast-while COMMAND test-runner "${PROJ tslang_add_test(NAME test-compile-01-safe-cast-while COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/01safe_cast_while.ts") tslang_add_test(NAME test-compile-00-safe-cast-field-access COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00safe_cast_field_access.ts") tslang_add_test(NAME test-compile-00-safe-cast-early-exit COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00safe_cast_early_exit.ts") +tslang_add_test(NAME test-compile-00-union-object-types-access COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00union_object_types_access.ts") tslang_add_test(NAME test-compile-00-safe-cast-null-field COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00safe_cast_null_field.ts") tslang_add_test(NAME test-compile-00-safe-cast-else-scope COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00safe_cast_else_scope.ts") tslang_add_test(NAME test-compile-00-safe-cast-bug COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00safe_cast_bug.ts") @@ -979,6 +980,7 @@ tslang_add_test(NAME test-jit-00-safe-cast-while COMMAND test-runner -jit "${PRO tslang_add_test(NAME test-jit-01-safe-cast-while COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/01safe_cast_while.ts") tslang_add_test(NAME test-jit-00-safe-cast-field-access COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00safe_cast_field_access.ts") tslang_add_test(NAME test-jit-00-safe-cast-early-exit COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00safe_cast_early_exit.ts") +tslang_add_test(NAME test-jit-00-union-object-types-access COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00union_object_types_access.ts") tslang_add_test(NAME test-jit-00-safe-cast-null-field COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00safe_cast_null_field.ts") tslang_add_test(NAME test-jit-00-safe-cast-else-scope COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00safe_cast_else_scope.ts") tslang_add_test(NAME test-jit-00-safe-cast-bug COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00safe_cast_bug.ts") @@ -1767,6 +1769,7 @@ set(TSLANG_CORPUS 00safe_cast_bug.ts 00safe_cast_field_access.ts 00safe_cast_early_exit.ts + 00union_object_types_access.ts 00safe_cast_null_field.ts 00safe_cast_else_scope.ts 00safe_cast_typeof.ts diff --git a/tslang/test/tester/tests/00union_object_types_access.ts b/tslang/test/tester/tests/00union_object_types_access.ts new file mode 100644 index 000000000..9695f7f90 --- /dev/null +++ b/tslang/test/tester/tests/00union_object_types_access.ts @@ -0,0 +1,41 @@ +// A field of a union of object types that share one layout. The union is stored as its base type, +// but the field was read through the union's reference - a 'ts.PropertyRef' the verifier rejected +// (#231). + +type Shape = { kind: "circle", r: number } | { kind: "square", r: number }; + +function kind(s: Shape) { + if (s.kind === "circle") { + return 1; + } + + return 2; +} + +function size(s: Shape) { + return s.r; +} + +type Sized = { kind: "circle", r: number | null } | { kind: "square", r: number | null }; + +function hasSize(s: Sized) { + if (s.r !== null) { + return true; + } + + return false; +} + +function main() { + const c: Shape = { kind: "circle", r: 1 }; + const q: Shape = { kind: "square", r: 2 }; + assert(kind(c) == 1 && kind(q) == 2); + assert(size(c) == 1 && size(q) == 2); + + const c2: Sized = { kind: "circle", r: 3 }; + const q2: Sized = { kind: "square", r: null }; + assert(hasSize(c2)); + assert(!hasSize(q2)); + + print("done."); +}