Skip to content

own: a record literal assigned to a class type is a borrow error ('this value' borrows a field) #492

Closed

Description

@ASDAlexander77

Under -mm=own, a record literal with a field made at run time cannot be assigned to a class type.

class P {
    x: number;
    items: number[];
}

function g(i: number) {
    const p: P = { x: i, items: [i] };
    return p.items.length;
}

function main() {
    print(g(7));
}
error: 'this value' borrows a field and cannot be stored, returned or captured

Expected: 1, as under gc, rc and none (since #487).

A record literal with a run-time field is built in a temporary slot of its own (a ts.Variable initialised by a ts.Constant, owning nothing), and the cast to a class reads each field back out of that slot (ts.PropertyRef + ts.Load) to store it into the new instance. The own pass sees each read as a borrow of the slot, and a borrow cannot be stored. The fresh values stored into the slot (ts.CreateArray, a fresh string, a call's result) should instead move into the instance: the slot is the literal's alone.

Taking the stored values directly in castTupleToClass is not enough: the literal's store into the slot already counts as a move, so own then reports "'this value' is used here after its value was moved". The pass needs to see the slot as a temporary that hands its fresh fields on, as it already does for a whole-record move into a local or a return (holdsConstantsOrMoves / recordRetainOf).

Since #487 a constant record assigned to a class is built the same way (the literal takes the class's field types, which fixed an rc leak), so const p: P = { x: 1, items: [1, 2] }, which compiled under own before #487 because the cast copied its arrays fresh, gives the same error.

Works under own: const o = { x: i, items: [i] } (a record-typed local) and a record assigned to a tuple type, which move the whole record.

Errors as expected (the value is shared): let r = { x: i, items: [i] }; const p: P = r;.

Found while fixing #487. Test: 00record_to_class.ts (passes under gc/rc/none, fails under own).

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions