Skip to content

-mm=own: an interface seen as another interface, or inside a union, is the block it shows - #671

Merged
ASDAlexander77 merged 1 commit into
mainfrom
own-iface-cast
Oct 23, 2026
Merged

ASDAlexander77 merged 1 commit into
mainfrom
own-iface-cast

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

Fixes the own limitation that #666, #669 and #670 each listed under "Not covered": -mm=own rejected every cast of an interface value to another interface type with "'this value' takes a second reference; -mm=own cannot prove a move or a borrow here yet". It wasn't only the casts #666 remaps. Even a cast to a base interface was rejected, and so was an interface given to its own | null:

const b: B = a;                     // A to B
const d: HasDist = mkHit();         // a call's fresh result
const base: A = derived;            // B extends A
function pick(): Hit | null { ...; return h; ... return null; }

Cause

own_facts::isView decides which casts are the same block as their operand. It took a cast between class, union and optional types, but not one from or to an interface. An ts.NewInterface (a class seen through an interface) was already a view.

Fix

InterfaceType joins that list (OwnershipFacts.h). The cast keeps this, and #666 interns the vtable laid out for the other interface, so no one owns it. own now moves and borrows through the cast as it does through the object. Only the own passes use isView; rc's and the lowering's are separate.

Tests

The following now also run under own, as JIT and compile tests:

  • 00interface_cast_unrelated;
  • 00interface_union_cast_unrelated;
  • 00nullable_interface_to_interface;
  • 00null_interface_to_interface.

Two cases in 00interface_cast_unrelated changed to fit own's existing rules, not this cast's:

  • the element case is [mkHit()] instead of [h], which moved h;
  • the loop no longer binds cond ? h : hc. own rejects a ternary of two outer locals inside a loop for a plain class too.

Tooth: on main, all four fail under own with "takes a second reference".

Probes (not in the suite):

  • A read of a after [a] moved it, through const b: B = a, is still "used here after its value was moved".
  • Also checked: a cast returned from a parameter (a borrow), passed as an argument, stored into a class field and into a global.
  • 30 million iterations of casts, unions and calls stay at a flat 4.2 MB under own, with the right sum.

Not covered

  • 00interface_type_tag_in_vtable stays rc/gc/none. It pushes a borrowed array element into another array, which own rejects by design.
  • A ternary of two outer locals in a loop is still rejected under own. That's general to own, and not about interfaces.

Verification

  • Windows: 5434/5434.
  • Linux: 5416/5416, plus 53 interface-cast and own-00 tests with MALLOC_PERTURB_=165 MALLOC_CHECK_=3.

🤖 Generated with Claude Code

…s the block it shows

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>
@ASDAlexander77
ASDAlexander77 merged commit 2b5b501 into main Oct 23, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the own-iface-cast branch October 23, 2026 15:59
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