A const array can grow: push/pop/splice on an annotated const - #387
Merged
Merged
Conversation
`const a: number[] = [1, 2]; a.push(3)` failed with "Can't get reference of the array, ensure const array is not used", and so did a const holding an array returned by a call. Only an unannotated array literal (!ts.const_array) was given storage; a const already typed !ts.array<T> stayed a bare SSA value, and push/pop/unshift/splice/length= change the array through a reference to it. A const of array type now gets storage like `let`. Two cases keep what they had: a ConstRef, which already aliases the storage it was read from, and a narrowed view (addSafeCastStatement), which is the narrowed variable seen through another type - giving it storage put a release at function scope for a value defined inside the branch. 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.
const a: number[] = [1, 2]; a.push(3)failed to compile:The same happened with a const holding an array returned by a call (
const c = make(); c.push(9)). Aconstbinding only forbids reassigning the name, not changing the array, so both should work.Cause: #344 gave storage only to an unannotated array literal (
!ts.const_array<T,N>). A const already typed!ts.array<T>stayed a bare SSA value, and push, pop, unshift, splice andlength =change the array through a reference to it.Fix: a const of array type now gets storage, the same as
let(processConstRef,MLIRGenImpl.h). Two cases are unchanged:ConstRef(an internal flag used by for-of) already aliases the storage it was read from.addSafeCastStatement, whose initializer is aSafeCastOp) is the narrowed variable seen through another type, not a new array. My first version gave it storage too, and that broketypeof u === "array"andif (results)narrowing: the release landed at function scope, outside the branch where the value is defined.Test:
00const_array_push.ts, registered for compile, jit and the corpus. It covers an annotated local, a call result, and a module-level const, using push, pop, unshift, splice andlength =. It fails on main with the error above.Results: the suite passes locally, 3017/3017. The new test also runs clean under
-mm=rc --verify-ownership.Not changed: arrays are value-typed here. After
let b = a; b.push(2),a.lengthis still the old length, and the same holds forconst items = holder.items. That was true before this change, and it's a separate issue.🤖 Generated with Claude Code