Skip to content

@value T | null of a one-pointer T; rc conditional with nested @value literals - #763

Merged
ASDAlexander77 merged 2 commits into
mainfrom
value-one-field-niche
Oct 31, 2026
Merged

ASDAlexander77 merged 2 commits into
mainfrom
value-one-field-niche

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

Two fixes around @value types.

TSLANG_ISSUES 22: T | null of a @value type whose only field is a class
A T | null stored without a tag (MLIRTypeHelper::getValueNullNiche, #760) was given its largest member's LLVM type. A one-pointer T ({ptr}) is the same size as null's ptr, the first one won, and the union became a bare pointer: == null / if (v) crashed tslang (0xC0000005) and passing T to a T | null parameter failed with LLVM Translation failed for operation: builtin.unrealized_conversion_cast. The UnionType conversion now lays such a union out as T. This unblocks native_ts_graphics (one-handle @value wrappers taken as X | null).
Test: value/value_missing_niche_one_field.ts (gc, rc, none).

rc: a conditional whose branches build nested @value literals
c ? { one: { h: new H() } } : ... under -mm=rc: each branch released its new H before the retain after the conditional, so the program freed it and then used it (heap corruption 0xC0000374; pre-alpha112 too). consumeConditionalResults made the branch retain its literal only when the literal's own fields held a branch temporary; it now also looks into fields that hold another literal built in the same branch.
Test: tests/00conditional_nested_record_literal_temporary.ts (gc, and rc/none through the corpus); it fails on pre-alpha112 with assertion failed: sum.

Release ctest: 6572/6572.

🤖 Generated with Claude Code

ASDAlexander77 and others added 2 commits October 31, 2026 15:31
…pointer

A `T | null` kept without a tag (MLIRTypeHelper::getValueNullNiche) was laid out as its largest
member. When T's only field is a class, T's `{ptr}` is no larger than null's `ptr`, the first of
the two won, and the union became a bare pointer: comparing it with null extracted a field the
pointer does not have (a tslang crash), and casting T into it left an
unrealized_conversion_cast. Such a union is now laid out as T (TSLANG_ISSUES 22).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ral holds a branch temporary

`c ? { one: { h: new H() } } : ...` of a @value type holding a @value type: the branch gave its
new H back before the receiver after the conditional retained the literal, so H was freed under
it (heap corruption, 0xC0000374, pre-alpha112 too). consumeConditionalResults made the branch
retain the literal it yields only when the literal's own fields held a branch temporary; it now
looks into fields holding another literal the branch built.

Test: tests/00conditional_nested_record_literal_temporary.ts (gc, and rc/none through the corpus).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ASDAlexander77
ASDAlexander77 merged commit 522ae99 into main Oct 31, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the value-one-field-niche branch October 31, 2026 16:01
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.

1 participant