Repository navigation
Test: an interface-or-null given to another interface-or-null (field read first) - #670
Merged
Merged
Conversation
…ace-to-interface cast `J | null` given to `I | null`, where `J` does not extend `I`, was a plain cast: the value kept `J`'s vtable, and a field read through `I` took a method slot of it for the field's offset (0xC0000005 under every model). Both are stored as their one member, so this is now the interface-to-interface cast of `J` to `I` (#666), as `C | null` to `I | null` is the class-to-interface cast (#665). A null value stays null: its vtable, the null vtable of `J`, is remapped as any other, and its methods throw. Test 00nullable_interface_to_interface.ts (compile + jit, rc/none corpus) reads a field before any method call; not under -mm=own, which refuses the program's interface-returning calls with or without the fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#669 made `J | null` given to `I | null` (and to `I`) the cast of J to I, the change this branch made to castToNullableUnionType and more. Main's MLIRGenCast.cpp is taken as it is; this branch now adds only the test 00nullable_interface_to_interface.ts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ASDAlexander77
added a commit
that referenced
this pull request
Oct 23, 2026
…s the block it shows (#671) own_facts::isView took a cast between class, union and optional types as the same block, but not one from or to an interface. So `const b: B = a` (A to B), `const d: HasDist = mkHit()`, `return h` into `Hit | null`, and even a cast to a base interface (B extends A, A of B) were each a second reference own could not prove a move or a borrow of. Every interface-to-interface cast (#666, #669, #670) was rejected under own. The cast keeps `this`; the vtable laid out for the other interface is interned, nobody's block. So it is a view like the others, and own moves and borrows through it as it does the object: a read after `[a]` moved it is still an error. 00interface_cast_unrelated, 00interface_union_cast_unrelated, 00nullable_interface_to_interface and 00null_interface_to_interface now run under own too. 00interface_cast_unrelated's element and loop cases no longer move or merge `h` (own's rules, not this cast's). Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.
Problem
Giving an
I | nullvalue to aJ | nullvariable, whereIdoes not extendJ, compiled to a plain cast. The value keptI's vtable, andJread it by its own slot numbers. A field read throughJtook one ofI's method slots as the field's offset, so the program crashed (0xC0000005) under gc, rc and none:Fix
castToNullableUnionType(MLIRGenCast.cpp): both unions are stored as their one member, soI | null→J | nullis now the interface-to-interface cast ofItoJ(castInterfaceToInterface, with the #666 vtable remap). This is how #665 already handlesC | null→I | null. A null value stays null. Its vtable,I's null vtable, is remapped like any other, so its methods still throw.00null_interface_to_interface.ts(#665) settled the same rule forI→J.I | null→I | null(the same interface) is left as it was.Tests
tests/00nullable_interface_to_interface.ts, registered as compile + jit and in TSLANG_CORPUS (rc, none). It reads a field before any method call or allocation, so a regression fails at a few MB instead of running into random code. It covers assignment, a declaration, a value returned from a call, an interface whose members come in another order, and null (stays null, its method throws).-mm=own: own refuses this program's interface-returning calls ("'this value' takes a second reference") with or without the fix.ctest -C Release: 5420/5420 passed (2 disabled/skipped as on main).Based on main after #668 (type tag in the vtable): the only overlap was adjacent lines in tslang/test/tester/CMakeLists.txt.
🤖 Generated with Claude Code