An assert message can be known only at run time; output before a failing assert is kept - #393
Merged
Merged
Conversation
`assert(ok, what + ": failed")` failed to compile with "operation's operand is unlinked": mlirGenAssert erased the op behind every message argument, as if each were a constant string, while other ops still used it. A constant string is still kept as the op's text; anything else is now a string operand of ts.Assert, shown by _assert/__assert_fail when the assertion fails (a null string shows the constant text). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
_assert and __assert_fail abort, which flushes no stream, and the JIT's _assert handler ends with _exit: whenever stdout was not a console - a pipe, a file, the test runner - everything the program printed before the failure was lost. The lowered assert now calls fflush(NULL) first, the JIT handler flushes stdout, and the JIT binds fflush to its own CRT like puts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Run on its own, tslang --emit=jit finds the GC only through the
GC_LIB_PATH/TSLANG_LIB_PATH environment, which CI does not set, so the
test failed with "Symbols not found: GC_init, GC_malloc". It now passes
--shared-libs=TypeScriptRuntime, as the other direct JIT tests do.
It is Windows only, like the uncaught-exception JIT tests: on Linux the
message and the earlier output are printed, but abort() then reaches
LLVM's crash handler ("Stack dump"), and ctest fails the signal.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ASDAlexander77
force-pushed
the
assert-runtime-message
branch
from
September 28, 2026 15:06
ed52d0f to
4b75613
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
An
assertwhose message is known only at run time failed to compile:Cause:
mlirGenAsserterased the op behind every message argument, as if each were a constant string, while other ops still used it.Fix:
ts.Assert(message). A message that isn't a string is cast to one.AssertLogicpasses that operand to_assert(Windows) or__assert_fail(Unix) when the assertion fails. A null message shows the constant text instead.Tests:
00assert_message.ts, registered for compile, jit and the corpus: passing asserts with a concatenated message, a template literal, a null string and a number. It is clean under-mm=rc --verify-ownership.test-jit-assert-message-failing: a failing assert must printassertion failed: n is 7.Second commit: output printed before a failing assert was lost.
_assertand__assert_failabort, which flushes no stream, and the JIT's_asserthandler ends with_exit. So whenever stdout wasn't a console (a pipe, a file, the test runner), everything printed before the failure was lost:Fix:
fflush(NULL)before_assert/__assert_fail.fflushto its own CRT, as it already doesputs.test-jit-assert-message-failingnow requires the output printed before the failure, then the message.Third commit (CI): the failing-assert test. It failed on both CI platforms with
Symbols not found: GC_init, GC_malloc. Run directly,tslang --emit=jitfinds the GC only through theGC_LIB_PATH/TSLANG_LIB_PATHenvironment, which CI doesn't set. Locally the environment hid this. The test now passes--shared-libs=$<TARGET_FILE:TypeScriptRuntime>, as the other direct JIT tests do. I reproduced the failure and the fix with those variables unset.The test is now Windows only, like the uncaught-exception JIT tests. On Linux the output and the message are both printed:
But
abort()then reaches LLVM's crash handler (Stack dump), and ctest fails the test on the signal. Catching an abort in a Linux JIT run is a separate gap.Results (after rebasing onto main, with #389/#391/#392):
🤖 Generated with Claude Code