Skip to content

A global initialised with a constant string concatenation runs as a constructor (#469) - #473

Merged
ASDAlexander77 merged 1 commit into
mainfrom
fix-global-const-concat
Oct 3, 2026
Merged

ASDAlexander77 merged 1 commit into
mainfrom
fix-global-const-concat

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

Fixes #469.

let S = "text" + 4; at module level, read by a function, failed to compile in every model with "ops with side effects not allowed in global initializers".

GlobalOpLowering decides where each global's initializer goes:

  • one that looks constant goes into the llvm.mlir.global's own region;
  • anything that runs code goes into a per-global constructor.

Its list of code-running ops included ts.StringConcat, but two ops were missing:

  • at that point the concatenation is still a ts.ArithmeticBinary with a string result;
  • the number's conversion (ts.Cast si32 → string, a sprintf into a new block) was not on the list either.

So both landed in the region, where allocating is not allowed. With a variable or a call among the operands the global was already a constructor, and a global that nothing reads was dropped before it mattered.

Now a string-typed ts.ArithmeticBinary, or a cast to string from anything that is not already a string, makes the global a constructor. A plain string constant stays in place.

Tests

  • New test: 00global_constant_concat.ts, registered as compile and JIT tests and in the rc/none corpus. It failed to compile before the change. It covers:
    • globals read in main: "text" + 4, "text" + "four", a string | null, and "" + 6.5;
    • a plain string constant;
    • a reassignment.
  • Own corpus: unchanged.
  • Full Release ctest: 3666/3667. The one failure is test-compile-gc-defaultlib-collector, the known local LNK2005 against the stale installed default library, which fails on main the same way.

🤖 Generated with Claude Code

…onstructor (#469)

`let S = "text" + 4;` at module level, read by a function, failed to compile in every model:
"ops with side effects not allowed in global initializers". GlobalOpLowering puts an initializer
that looks constant into the llvm.mlir.global's own region and anything that runs code into a
per-global constructor. Its list knew ts.StringConcat, but at that point the concatenation is
still a ts.ArithmeticBinary with a string result, and the number's conversion (`ts.Cast` si32 ->
string, a sprintf into a new block) was not on the list either, so both landed in the region,
where allocating is not allowed. With a variable or a call among the operands it was already a
constructor, and a global nothing reads was dropped before it mattered.

Now a string-typed ts.ArithmeticBinary, and a cast to string from anything that is not already a
string, make the global a constructor. A plain string constant stays in place.

Test: 00global_constant_concat (compile and JIT, and in the rc/none corpus): `"text" + 4`,
`"text" + "four"`, a `string | null` and `"" + 6.5` globals read in main, a plain string constant,
and a reassignment. It failed to compile before the change.

Fixes #469.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ASDAlexander77
ASDAlexander77 merged commit ee08124 into main Oct 3, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the fix-global-const-concat branch October 3, 2026 20:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A global initialised with a constant string concatenation: 'ops with side effects not allowed in global initializers'

1 participant