{{ message }}
Conversation
A sequence of List operations could corrupt a stored `undefined` into `null`, breaking `get`, `toArray`, `equals` and `hashCode`. When a List's only element lives entirely in its tail (`_origin 31`, `_capacity 32`, `_root null`, so `getTailOffset(32) === 0`), a later grow pushes `_capacity` across the next 32-boundary and `getTailOffset` jumps `0 -> 32`. Raw index 31 (logical 0) now routes to `_root` instead of the tail, but `setListBounds`'s "Merge Tail into tree" step skipped grafting the tail whenever `oldTail.array.length` was falsy. The element was never migrated, `_root` stayed `null`, and `listNodeFor` returned `null`; in `List.get` the expression `node && node.array[index & MASK]` then yielded `null` instead of the stored `undefined`. Allow the merge step to run for an empty tail too when the origin will sit below the new tail offset, so those raw indices route through a real (possibly empty) root subtree and read back as `undefined`.
Member
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.

Bug
A sequence of
Listoperations silently corrupts a storedundefinedintonull, breakingget,toArray,equalsandhashCode.This violates the documented
get(index): T | undefinedcontract and thesetSize"fills withundefined" semantics: an authentic storedundefinedmust never read back asnull.Root cause
At the corrupting step the List has reached an intermediate state where its single logical element lives entirely in the tail:
_origin 31,_capacity 32,_root null. BecausegetTailOffset(32) === 0, every in-bounds raw index correctly routes to the tail.A later grow pushes
_capacityacross the next 32-element boundary, sogetTailOffsetjumps0 -> 32. Raw index 31 (logical 0) must now route through_rootinstead of the tail. InsetListBoundsthe "Merge Tail into tree" step is responsible for grafting the old tail into a freshly created root subtree, but its guard requiredoldTail.array.lengthto be truthy. At this point the tail array is empty (the element is a virtualundefined, not physically present), so the merge was skipped and no root was created._rootstayednullwhilegetTailOffset(_capacity) > _origin.listNodeForthen returnsnullfor that index, and inList.getthe expressionnode && node.array[index & MASK]evaluates tonullinstead of the storedundefined. The samenullthen surfaces throughtoArray, iteration,equalsandhashCode.Fix
Allow the "Merge Tail into tree" step to run for an empty tail as well, when the origin will sit below the new tail offset (
newOrigin < newTailOffset) and therefore genuinely needs a root to route those raw indices. The (possibly empty) tail node is grafted into a real root subtree, so reads returnundefinedrather thannull. The empty-tail skip remains an optimization in every other case.Tests
Added a
Listtest that runs the 8-operation repro and assertsget(0)isundefined,toArray()is[undefined, undefined, undefined], and thatequals/hashCodematchList([undefined, undefined, undefined]).get(0)returnsnull,toArray()yields[null, ...],equalsisfalse.Listfast-check property tests). Flow type-check, ESLint and Prettier all clean.