Skip to content

own: narrowed and kept locals, stable private fields, constant function aliases, pushes and moves on some paths (TSLANG 71-79, 81) - #856

Merged
ASDAlexander77 merged 21 commits into
mainfrom
fix-own-items-71
Nov 14, 2026
Merged

ASDAlexander77 merged 21 commits into
mainfrom
fix-own-items-71

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

More -mm=own gaps from compiling native_ts_graphics (TSLANG 71-81, written up in TSLANG_ISSUES.md).

Fixed

  • 71: a value narrowed from T | null and kept by a constructor can be used after it.
  • 72: a local kept by a constructor or pushed, then read. This includes a local declared in the loop, or filled in place before the move.
  • 73: a private field that only the constructor writes is not overwritten by a later call, callbacks included.
  • 74: cond ? null : f(), with f from another module, pushed where not null, then used.
  • 75: a call through a global no store writes, initialized with a function (const f = Math.fround), is a call of that function.
  • 76: a constructor that gives this to a call (this.reset()) still keeps a parameter, in a private field only it writes.
  • 77: an array kept by a constructor, then filled through the local, fills the object's array.
  • 78: a value pushed on, or stored into, a field of a local object made by new, then used, reads that field.
  • 79: let x = ...; if (x) this.xs.push(x); return x; reads the element where the paths join, or null.
  • 81: a value moved on some paths only is released on the edges that did not move it. A read after the paths join is still refused, a copyable value's read included.

Not fixed

  • 80 is open. A first fix copied an owned parameter at a field store; it leaked (3M calls grew to 2.7 GB) and is backed out in this branch. own_err_string_kept_param_known says why.

Tests

  • Every model: 00tslang_issue_71, 00tslang_issue_73, and 00tslang_issue_75 to 00tslang_issue_79, plus 00tslang_issue_81.
  • New own error tests:
    • own_err_kept_local_array_popped
    • own_err_private_field_written_callback
    • own_err_const_alias_drops
    • own_err_kept_field_rebound
    • own_err_kept_array_filled_after_pop
    • own_err_local_object_field_popped
    • own_err_pushed_let_popped
    • own_err_moved_on_some_paths_used
  • TSLANG 74's case is in own-facts-objects.cmake.
  • Existing own error tests:
    • Five are still refused, at the same position, as a field borrow, and their expected text says so.
    • Three are now accepted (a value moved on some ways, an aliased store); they became cases in the 78 and 81 tests.
    • own_err_declared_drops now lends a public field, because the private one is a field 73 keeps.

Validation

  • ctest: 7400 of 7400 passed.
  • DefaultLib tests.ps1: all four models passed. Results are in a comment.
  • 73 and 81 change releases, so I ran leak probes too: memory stays flat over 20M+ iterations.
  • ntg sweep: 615 errors in 115 failing sources before this branch, 129 in 39 after. The ntg-side changes are on ntg branch own-sweep-fixes.

🤖 Generated with Claude Code

ASDAlexander77 and others added 21 commits November 14, 2026 20:06
…uctor or pushed, then read (TSLANG 71, 72)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…written by a call (TSLANG 73)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hen used (TSLANG 74)

readFieldsForLocals runs before the signature pass marks imported calls'
results fresh, so a merge of null and such a call was not taken as the
function's own, though the call's result alone is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… initializer, is a call of that function (TSLANG 75)

`const f = Math.fround` in clustered_geometry made every f(...) a call
that may destroy anything.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… private field only it writes (TSLANG 76)

`constructor(private sample: NriSample) { this.reset(); }`: no call can
overwrite such a field, so the parameter used after `new` is read back from it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ills the object's array (TSLANG 77)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… used, reads that field (TSLANG 78)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ithout the default lib)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lement or null (TSLANG 79)

`let pipeline = ...; if (pipeline) this.pipelines.push(pipeline); return
pipeline;`: the reads after the paths join take the merge, and the local is
released on the edge that did not push it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… a value moved on some paths is released on the others (TSLANG 80, 81)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…uses a value read after the ways join; 78 takes only an object new made

- 80 copied an owned parameter stored into a field when it was read again,
  but nothing released the caller's reference: 3M calls grew to 2.7 GB.
  own_err_string_kept_param_known says why; it is refused again.
- 81 released a value on the edges that did not move it even where a read
  of a copyable value followed the join (own_string_copy_branch: a print
  after the release).
- 78 followed field stores into closure capture records too.
- Error tests now refused as a field borrow say so; three now accepted (a
  value moved on some ways, an aliased store) moved into the 78/81 tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ASDAlexander77

Copy link
Copy Markdown
Owner Author

DefaultLib tests.ps1 (Windows, release + debug, compile + jit), built with the branch head's tree (565f8d8b):

== gc
Finished release, compile : 224/225 passed, 1 skipped
Finished release, jit : 224/225 passed, 1 skipped
Finished debug, compile : 224/225 passed, 1 skipped
Finished debug, jit : 224/225 passed, 1 skipped
Done. All tests passed.
== none
Finished release, compile : 221/225 passed, 4 skipped
Finished release, jit : 221/225 passed, 4 skipped
Finished debug, compile : 221/225 passed, 4 skipped
Finished debug, jit : 221/225 passed, 4 skipped
Done. All tests passed.
== rc
Finished release, compile : 221/225 passed, 4 skipped
Finished release, jit : 221/225 passed, 4 skipped
Finished debug, compile : 221/225 passed, 4 skipped
Finished debug, jit : 221/225 passed, 4 skipped
Done. All tests passed.
== own
Finished release, compile : 219/225 passed, 6 skipped
Finished release, jit : 219/225 passed, 6 skipped
Finished debug, compile : 219/225 passed, 6 skipped
Finished debug, jit : 219/225 passed, 6 skipped
Done. All tests passed.

ctest: 100% tests passed, 0 tests failed out of 7400

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