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
15 changes: 15 additions & 0 deletions tslang/lib/TypeScript/MLIRGenFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2013,6 +2013,21 @@ namespace mlirgen

// review capturing by ref. it should match storage type
auto refValue = mcl.GetReferenceFromValue(location, varValue);

// A copy is taken through the reference only when that reference is the variable's own
// storage. A `const` folded into a read (`const v = n.v`, `const v = G`) has none: the
// reference is where it was read from, and dereferenced now it gave the closure what the
// place holds by the time the closure is made - `n.v = d` in between, and `v` in the
// closure was `d`. The value itself is what the const names.
auto isOwnStorage = refValue && (refValue.getDefiningOp<mlir_ts::VariableOp>() ||
refValue.getDefiningOp<mlir_ts::ParamOp>() ||
refValue.getDefiningOp<mlir_ts::ParamOptionalOp>() ||
isCapturedCellSlot(refValue));
if (refValue && !capturedByRef && !isOwnStorage)
{
refValue = mlir::Value();
}

if (refValue && !capturedByRef)
{
// the box holds a copy, exactly as it does for a value with no reference at all
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 @@ -406,6 +406,7 @@ tslang_add_test(NAME test-compile-00-const-element-read COMMAND test-runner "${P
tslang_add_test(NAME test-compile-00-const-global-read COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00const_global_read.ts")
tslang_add_test(NAME test-compile-00-global-argument-reassigned COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00global_argument_reassigned.ts")
tslang_add_test(NAME test-compile-00-global-argument-view COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00global_argument_view.ts")
tslang_add_test(NAME test-compile-00-closure-const-read COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00closure_const_read.ts")
tslang_add_test(NAME test-compile-00-element-store-after-value COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00element_store_after_value.ts")
tslang_add_test(NAME test-compile-00-const-interface-field-read COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00const_interface_field_read.ts")
tslang_add_test(NAME test-compile-00-argument-place-overwritten COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00argument_place_overwritten.ts")
Expand Down Expand Up @@ -992,6 +993,7 @@ tslang_add_test(NAME test-jit-00-const-element-read COMMAND test-runner -jit "${
tslang_add_test(NAME test-jit-00-const-global-read COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00const_global_read.ts")
tslang_add_test(NAME test-jit-00-global-argument-reassigned COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00global_argument_reassigned.ts")
tslang_add_test(NAME test-jit-00-global-argument-view COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00global_argument_view.ts")
tslang_add_test(NAME test-jit-00-closure-const-read COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00closure_const_read.ts")
tslang_add_test(NAME test-jit-00-element-store-after-value COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00element_store_after_value.ts")
tslang_add_test(NAME test-jit-00-const-interface-field-read COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00const_interface_field_read.ts")
tslang_add_test(NAME test-jit-00-argument-place-overwritten COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00argument_place_overwritten.ts")
Expand Down Expand Up @@ -1968,6 +1970,7 @@ set(TSLANG_CORPUS
00const_global_read.ts
00global_argument_reassigned.ts
00global_argument_view.ts
00closure_const_read.ts
00element_store_after_value.ts
00const_interface_field_read.ts
00argument_place_overwritten.ts
Expand Down
45 changes: 45 additions & 0 deletions tslang/test/tester/tests/00closure_const_read.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// A closure over a `const` read out of a field, an element or a global sees
// the value the const was given, not what the place holds by the time the closure is made. Folded
// into the read, the const had no storage of its own, and the capture was taken through the
// place it was read from: `const v = n.v; n.v = d; const c = () => v.x;` gave `d.x` under gc and
// none (rc gives such a const storage, and was right).
class V {
constructor(public x: number) {}
}

class N {
v = new V(3);
items: V[] = [new V(4)];
}

let G = new V(5);

function field() {
const n = new N();
const v = n.v;
n.v = new V(2);
const c = (): number => v.x;
return c();
}

function element() {
const n = new N();
const v = n.items[0];
n.items[0] = new V(2);
const c = (): number => v.x;
return c();
}

function global() {
const v = G;
G = new V(2);
const c = (): number => v.x;
return c();
}

function main() {
assert(field() == 3, "a closure over a const read out of a field");
assert(element() == 4, "a closure over a const read out of an element");
assert(global() == 5, "a closure over a const read out of a global");
print("done.");
}
Loading