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
13 changes: 12 additions & 1 deletion tslang/lib/TypeScript/MLIRGenCast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2044,7 +2044,7 @@ namespace mlirgen
}
}

mlir::LogicalResult MLIRGenImpl::verifyFunctionCastRules(mlir::Location location, mlir::Type type, mlir::Value value, mlir::Type valueType, const GenContext &genContext)
mlir::LogicalResult MLIRGenImpl::verifyFunctionCastRules(mlir::Location location, mlir::Type type, mlir::Value &value, mlir::Type &valueType, const GenContext &genContext)
{
if (mth.isAnyFunctionType(valueType) && mth.isAnyFunctionType(type)) {

Expand All @@ -2053,6 +2053,17 @@ namespace mlirgen
// need to instantiate generic method
auto result = instantiateSpecializedFunction(location, value, type, genContext);
EXIT_IF_FAILED(result);

// An arrow that captures comes back as a new value, the closure bound over its
// captured variables; the old reference is the bare function and calling it reads
// the captures through a null pointer (`new W((v) => { seen += 1; })`). Without
// captures the reference was retyped in place.
if (auto resultValue = V(result))
{
value = resultValue;
}

valueType = value.getType();
}

// A C variadic function is called with C's variadic convention and a TypeScript
Expand Down
2 changes: 1 addition & 1 deletion tslang/lib/TypeScript/MLIRGenImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -14253,7 +14253,7 @@ class MLIRGenImpl
// union or optional or any or opaque source type
std::optional<ValueOrLogicalResult> castFromSourceSpecialCases(mlir::Location location, mlir::Type type, mlir::Value value, mlir::Type valueType, const GenContext &genContext);

mlir::LogicalResult verifyFunctionCastRules(mlir::Location location, mlir::Type type, mlir::Value value, mlir::Type valueType, const GenContext &genContext);
mlir::LogicalResult verifyFunctionCastRules(mlir::Location location, mlir::Type type, mlir::Value &value, mlir::Type &valueType, const GenContext &genContext);

// cast ext method to bound method
std::optional<ValueOrLogicalResult> castExtensionFunctionType(mlir::Location location, mlir::Type type, mlir::Value value, mlir::Type valueType);
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 @@ -597,6 +597,7 @@ tslang_add_test(NAME test-compile-00-try-cleanup-then-catch COMMAND test-runner
tslang_add_test(NAME test-compile-00-try-empty-catch COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00try_empty_catch.ts")
tslang_add_test(NAME test-compile-00-global-union-from-call COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00global_union_from_call.ts")
tslang_add_test(NAME test-compile-00-capture-in-new-arguments COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00capture_in_new_arguments.ts")
tslang_add_test(NAME test-compile-00-capture-in-new-untyped-arrow COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00capture_in_new_untyped_arrow.ts")
tslang_add_test(NAME test-compile-01-class-new COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/01class_new.ts")
tslang_add_test(NAME test-compile-00-class-stack COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_stack.ts")
tslang_add_test(NAME test-compile-00-class-static COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_static.ts")
Expand Down Expand Up @@ -1202,6 +1203,7 @@ tslang_add_test(NAME test-jit-00-try-cleanup-then-catch COMMAND test-runner -jit
tslang_add_test(NAME test-jit-00-try-empty-catch COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00try_empty_catch.ts")
tslang_add_test(NAME test-jit-00-global-union-from-call COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00global_union_from_call.ts")
tslang_add_test(NAME test-jit-00-capture-in-new-arguments COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00capture_in_new_arguments.ts")
tslang_add_test(NAME test-jit-00-capture-in-new-untyped-arrow COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00capture_in_new_untyped_arrow.ts")
tslang_add_test(NAME test-jit-01-class-new COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/01class_new.ts")
tslang_add_test(NAME test-jit-00-class-stack COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_stack.ts")
tslang_add_test(NAME test-jit-00-class-static COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_static.ts")
Expand Down Expand Up @@ -2146,6 +2148,7 @@ set(TSLANG_CORPUS
00try_scope_exit_through_finally.ts
00try_jump_from_catch.ts
00capture_in_new_arguments.ts
00capture_in_new_untyped_arrow.ts
00cast_to_f32.ts
00catch_untyped_value.ts
00catch_value.ts
Expand Down
66 changes: 66 additions & 0 deletions tslang/test/tester/tests/00capture_in_new_untyped_arrow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// An arrow without parameter types, `(v) => ...`, is generic until something gives it a type. As a
// `new` argument it gets one when it is cast to the constructor parameter's type, and the cast
// instantiated it there - but when the arrow captured a local, the instantiation built the closure
// over the captured variables and the cast went on with the bare function instead. The constructor
// stored a function whose captures were a null pointer, and the first call crashed - under every
// memory model, so it is a front-end bug. A non-capturing arrow, or one with typed parameters,
// never went that way.

class ParamProperty {
constructor(private f: (v: number) => void) {}

run(v: number) {
this.f(v);
}
}

class StoredField {
f: (v: number) => void;

constructor(f: (v: number) => void) {
this.f = f;
}

run(v: number) {
this.f(v);
}
}

class Mapper {
constructor(private f: (v: number) => number) {}

apply(v: number) {
return this.f(v);
}
}

let globalSeen: number = 0;

function main() {
let seen: number = 0;
const p = new ParamProperty((v) => {
seen += v;
});
p.run(1);
p.run(2);
assert(seen == 3, "a capturing untyped arrow in a parameter property");

let total: number = 0;
const s = new StoredField((v) => {
total += v;
});
s.run(5);
assert(total == 5, "a capturing untyped arrow stored in a field");

const k = 10;
const m = new Mapper((v) => v * k);
assert(m.apply(4) == 40, "a capturing untyped arrow returning a value");

const g = new ParamProperty((v) => {
globalSeen += v;
});
g.run(7);
assert(globalSeen == 7, "a non-capturing untyped arrow");

print("done.");
}
Loading