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
33 changes: 33 additions & 0 deletions tslang/lib/TypeScript/MLIRGenExpressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,39 @@ namespace mlirgen
EXIT_IF_FAILED_OR_NO_VALUE(result)
auto value = V(result);

// `const m: Map<string, number[]> = new Map()`: a generic class written without type
// arguments takes them from the type it is given to, when that is the same class. Its
// type parameter defaults (`Map<K = any, V = any>`) made Map<any, any> otherwise, a
// different layout, and the cast to the declared type crashed at run time.
if (newExpression->typeArguments.size() == 0 && genContext.receiverType)
{
if (auto classType = dyn_cast<mlir_ts::ClassType>(value.getType()))
{
// the generic itself, or its specialization by the defaults
auto genericClassType = mlir_ts::ClassType();
if (getGenericClassInfoByFullName(classType.getName().getValue()))
{
genericClassType = classType;
}
else if (auto classInfo = getClassInfoByFullName(classType.getName().getValue()))
{
genericClassType = classInfo->originClassType;
}

auto receiverClassType = dyn_cast<mlir_ts::ClassType>(mth.stripOptionalType(genContext.receiverType));
if (genericClassType && receiverClassType && receiverClassType != classType)
{
auto receiverClassInfo = getClassInfoByFullName(receiverClassType.getName().getValue());
if (receiverClassInfo && receiverClassInfo->originClassType == genericClassType)
{
value = builder.create<mlir_ts::ClassRefOp>(
location, receiverClassType,
mlir::FlatSymbolRefAttr::get(builder.getContext(), receiverClassType.getName().getValue()));
}
}
}
}

if (auto arrayType = dyn_cast<mlir_ts::ArrayType>(value.getType()))
{
return NewArray(location, arrayType, newExpression->arguments, genContext);
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 @@ -385,6 +385,7 @@ tslang_add_test(NAME test-compile-00-sizeof COMMAND test-runner "${PROJECT_SOURC
tslang_add_test(NAME test-compile-01-sizeof COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/01sizeof.ts")
tslang_add_test(NAME test-compile-02-sizeof COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/02sizeof.ts")
tslang_add_test(NAME test-compile-00-new-delete COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00new_delete.ts")
tslang_add_test(NAME test-compile-00-new-generic-from-receiver COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00new_generic_from_receiver.ts")
tslang_add_test(NAME test-compile-00-owned-locals COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00owned_locals.ts")
# The JIT variants are the ones that matter here: this shape was a JIT-only miscompile until
# the catchable-type size was fixed (see the file header). Kept in all three models, since the
Expand Down Expand Up @@ -832,6 +833,7 @@ tslang_add_test(NAME test-jit-00-sizeof COMMAND test-runner -jit "${PROJECT_SOUR
tslang_add_test(NAME test-jit-01-sizeof COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/01sizeof.ts")
tslang_add_test(NAME test-jit-02-sizeof COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/02sizeof.ts")
tslang_add_test(NAME test-jit-00-new-delete COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00new_delete.ts")
tslang_add_test(NAME test-jit-00-new-generic-from-receiver COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00new_generic_from_receiver.ts")
tslang_add_test(NAME test-jit-00-owned-locals COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00owned_locals.ts")
tslang_add_test(NAME test-jit-00-throw-in-catch COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00throw_in_catch.ts")
tslang_add_test(NAME test-jit-00-throw-inlined COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00throw_inlined.ts")
Expand Down Expand Up @@ -1702,6 +1704,7 @@ set(TSLANG_CORPUS
00try_mismatch_in_catch_clause.ts
00try_mismatch_in_catch_clause_using.ts
00new_delete.ts
00new_generic_from_receiver.ts
00ns_bug.ts
00ns.ts
00ns2.ts
Expand Down
66 changes: 66 additions & 0 deletions tslang/test/tester/tests/00new_generic_from_receiver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// `new C()` of a generic class takes its type arguments from the type it is given to, as in
// `const m: Map<string, number[]> = new Map()`. Without them a plain generic was an error ("missing
// type arguments"), and one with defaults (`Map<K = any, V = any>`) became C<any, any>, whose cast
// to the declared type crashed at run time (#231).

class Box<T> {
items: T[] = [];

add(v: T) {
this.items.push(v);
}

get(i: number): T {
return this.items[i];
}
}

class Pair<K = any, V = any> {
keys: K[] = [];
values: V[] = [];

set(k: K, v: V) {
this.keys.push(k);
this.values.push(v);
}
}

class Holder {
private readonly boxes: Box<string> = new Box();
pairs: Pair<string, number[]>;

constructor() {
this.pairs = new Pair();
}

fill() {
this.boxes.add("x");
this.pairs.set("a", [1, 2, 3]);
return this.boxes.get(0) + this.pairs.values[0][2];
}
}

function main() {
const b: Box<number> = new Box();
b.add(5);
assert(b.get(0) == 5);

const p: Pair<string, number> = new Pair();
p.set("k", 7);
assert(p.keys[0] == "k" && p.values[0] == 7);

let q = new Pair<number, string>();
q.set(0, "zero");
q = new Pair();
q.set(1, "one");
assert(q.values[0] == "one");

// explicit type arguments still win
const e: Box<number> = new Box<number>();
e.add(1);
assert(e.get(0) == 1);

assert(new Holder().fill() == "x3");

print("done.");
}
Loading