Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions tslang/lib/TypeScript/MLIRGenCast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1294,8 +1294,10 @@ namespace mlirgen
}
else if (auto classType = dyn_cast<mlir_ts::ClassType>(type))
{
emitError(location, "invalid cast from ") << to_print(valueType) << " to " << to_print(type);
return mlir::failure();
// a record with a run-time field (`const p: P = { x: 1, items: [i, 2] }`) makes the
// instance from its fields, as a constant record does (#487)
fields = mlir::cast<mlir_ts::ClassStorageType>(classType.getStorageType()).getFields();
return castTupleToClass(location, value, srcTupleType, fields, classType, genContext);
}
else if (auto funcType = dyn_cast<mlir_ts::FunctionType>(type))
{
Expand Down
14 changes: 14 additions & 0 deletions tslang/lib/TypeScript/MLIRGenImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -9875,6 +9875,20 @@ class MLIRGenImpl
}
}

// a record literal made into a class instance (`const p: P = { x: 1, items: [i, 2] }`) is
// built with the class's field types, as for a tuple: `[i, 2]` is the field's `number[]`
// itself, not an `s32[]` copied into one and left with no count under rc, and `[]` is no
// `any[]` the field cannot take (#487)
if (auto classType = dyn_cast<mlir_ts::ClassType>(receiverType))
{
auto classStorageType = mlir::cast<mlir_ts::ClassStorageType>(classType.getStorageType());
auto index = classStorageType.getIndex(fieldName);
if (index >= 0 && index < (int)classStorageType.size())
{
return classStorageType.getType(index);
}
}

if (auto interfaceType = dyn_cast<mlir_ts::InterfaceType>(receiverType))
{
auto interfaceInfo = getInterfaceInfoByFullName(interfaceType.getName().getValue());
Expand Down
3 changes: 3 additions & 0 deletions tslang/test/tester/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ tslang_add_test(NAME test-compile-00-arrays6 COMMAND test-runner "${PROJECT_SOUR
tslang_add_test(NAME test-compile-00-array-static-nested COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00array_static_nested.ts")
tslang_add_test(NAME test-compile-00-array-literal-copy COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00array_literal_copy.ts")
tslang_add_test(NAME test-compile-00-tuple-runtime-arrays COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00tuple_runtime_arrays.ts")
tslang_add_test(NAME test-compile-00-record-to-class COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00record_to_class.ts")
tslang_add_test(NAME test-compile-00-const-record-owned-fields COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00const_record_owned_fields.ts")
tslang_add_test(NAME test-compile-00-array-length-valid COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00array_length_valid.ts")
tslang_add_test(NAME test-compile-00-string-view-copy COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00string_view_copy.ts")
Expand Down Expand Up @@ -855,6 +856,7 @@ tslang_add_test(NAME test-jit-00-arrays6 COMMAND test-runner -jit "${PROJECT_SOU
tslang_add_test(NAME test-jit-00-array-static-nested COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00array_static_nested.ts")
tslang_add_test(NAME test-jit-00-array-literal-copy COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00array_literal_copy.ts")
tslang_add_test(NAME test-jit-00-tuple-runtime-arrays COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00tuple_runtime_arrays.ts")
tslang_add_test(NAME test-jit-00-record-to-class COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00record_to_class.ts")
tslang_add_test(NAME test-jit-00-const-record-owned-fields COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00const_record_owned_fields.ts")
tslang_add_test(NAME test-jit-00-array-length-valid COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00array_length_valid.ts")
tslang_add_test(NAME test-jit-00-string-view-copy COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00string_view_copy.ts")
Expand Down Expand Up @@ -1690,6 +1692,7 @@ set(TSLANG_CORPUS
00array_static_nested.ts
00array_literal_copy.ts
00tuple_runtime_arrays.ts
00record_to_class.ts
00const_record_owned_fields.ts
00array_length_valid.ts
00string_view_copy.ts
Expand Down
51 changes: 51 additions & 0 deletions tslang/test/tester/tests/00record_to_class.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// A record literal with a run-time field can be assigned to a class type (#487): the instance is
// made from the record's fields, as it is from a constant record's, where the cast used to be an
// "invalid cast" error. A literal assigned to a class is built with the class's field types, so
// `[i, 2]` is the field's `number[]` itself (an `s32[]` copied into one was never freed under rc)
// and `[]` is no `any[]` the field cannot take.
class P {
x: number;
items: number[];
name: string;
}

function take(p: P) {
return p.items.length + p.name.length;
}

function make(i: number): P {
return { x: i, items: [i, i + 1, i + 2], name: "n" + i };
}

function main() {
let i = 7;
const p: P = { x: 1, items: [i, 2], name: "a" };
assert(p.items.length == 2 && p.items[0] == 7 && p.x == 1, "const of a run-time record");
p.items.push(3);
assert(p.items.length == 3, "its array can be changed");

const c: P = { x: 2, items: [1, 2], name: "c" };
assert(c.items.length == 2 && c.items[1] == 2, "a constant record");
const e: P = { x: i, items: [], name: "e" };
e.items.push(i);
assert(e.items.length == 1 && e.items[0] == 7, "an empty array");

let n: number = 5;
let r = { x: n, items: [n, 2], name: "b" + n };
const q: P = r;
q.items.push(9);
assert(r.items.length == 3 && q.name == "b5", "a record variable, sharing its array");

assert(take({ x: 2, items: [i], name: "cc" + i }) == 4, "to a class parameter");
const m = make(i);
assert(m.x == 7 && m.items.length == 3 && m.name == "n7", "returned as a class");

let total = 0;
for (let k = 0; k < 1000; k++) {
const z: P = { x: k, items: [k, k], name: "z" + k };
total += z.items.length + z.name.length;
}
assert(total == 5890, "a fresh instance each pass");

print("done.");
}
Loading