From dbd232455a0b5a0e188c3f521d0da7918002f6e8 Mon Sep 17 00:00:00 2001 From: ASDAlexander77 Date: Sun, 4 Oct 2026 22:36:23 +0100 Subject: [PATCH] await of a void async function waits for it (#440) `await f()` on an async function that returns nothing never ran `f` before going on, under every memory model, AOT and JIT: the await of the example printed `ran 0`, and `f` did not run at all if the program ended first. mlirGen(AwaitExpression) wraps the awaited expression in an async.execute and checked its result with EXIT_IF_FAILED_OR_NO_VALUE; a call to a void function succeeds with no value, so it left there, before the async.await on the execute's token. It now leaves on a failure only, and a void await awaits its token and gives no value, as it already did with no result slot. Any await of a void call was affected: a function, a method, an arrow function, in a loop or in sequence. 00await_void.ts runs them in order under every model. Closes #440 Co-Authored-By: Claude Opus 5.5 --- tslang/lib/TypeScript/MLIRGenExpressions.cpp | 5 +++- tslang/test/tester/CMakeLists.txt | 3 +++ tslang/test/tester/tests/00await_void.ts | 26 ++++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 tslang/test/tester/tests/00await_void.ts diff --git a/tslang/lib/TypeScript/MLIRGenExpressions.cpp b/tslang/lib/TypeScript/MLIRGenExpressions.cpp index 3753a8c12..1694d0c8e 100644 --- a/tslang/lib/TypeScript/MLIRGenExpressions.cpp +++ b/tslang/lib/TypeScript/MLIRGenExpressions.cpp @@ -492,7 +492,10 @@ namespace mlirgen builder.create(location, mlir::ValueRange{}); } }); - EXIT_IF_FAILED_OR_NO_VALUE(result) + // a call to a void function succeeds with no value, and is awaited all the same: leaving + // here dropped the token, so nothing waited for the task and `await f()` went straight + // on (#440) + EXIT_IF_FAILED(result) // Registered only now, and only if the store above actually happened: an owned slot is // released at scope exit whatever is in it, and a slot nothing wrote holds whatever the diff --git a/tslang/test/tester/CMakeLists.txt b/tslang/test/tester/CMakeLists.txt index aff8c36e8..30583de1b 100644 --- a/tslang/test/tester/CMakeLists.txt +++ b/tslang/test/tester/CMakeLists.txt @@ -351,6 +351,7 @@ tslang_add_test(NAME test-compile-00-array-literal-copy COMMAND test-runner "${P 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-array-insert-functions COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00array_insert_functions.ts") +tslang_add_test(NAME test-compile-00-await-void COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00await_void.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") @@ -859,6 +860,7 @@ tslang_add_test(NAME test-jit-00-array-literal-copy COMMAND test-runner -jit "${ 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-array-insert-functions COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00array_insert_functions.ts") +tslang_add_test(NAME test-jit-00-await-void COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00await_void.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") @@ -1696,6 +1698,7 @@ set(TSLANG_CORPUS 00tuple_runtime_arrays.ts 00record_to_class.ts 00array_insert_functions.ts + 00await_void.ts 00const_record_owned_fields.ts 00array_length_valid.ts 00string_view_copy.ts diff --git a/tslang/test/tester/tests/00await_void.ts b/tslang/test/tester/tests/00await_void.ts new file mode 100644 index 000000000..c71da5d78 --- /dev/null +++ b/tslang/test/tester/tests/00await_void.ts @@ -0,0 +1,26 @@ +// `await` of an async function that returns nothing runs it, and in order (#440): the await +// left before its `async.await`, so nothing waited for the task and the awaiting function went +// straight on. +let log = ""; +async function step(s: string) { log += s; } +async function twice() { + await step("b"); + await step("c"); +} +class C { + async run() { log += "m"; } +} +async function main() { + await step("a"); + await twice(); + for (let i = 0; i < 3; i++) { + await step("" + i); + } + const c = new C(); + await c.run(); + const g = async () => { log += "g"; }; + await g(); + print(log); + assert(log == "abc012mg", "in order"); + print("done."); +}