fix(ir,codegen): autovivify missing parents in nested array writes#570
Open
mirchaemanuel wants to merge 1 commit into
Open
fix(ir,codegen): autovivify missing parents in nested array writes#570mirchaemanuel wants to merge 1 commit into
mirchaemanuel wants to merge 1 commit into
Conversation
This was referenced Jul 20, 2026
Open
…llegalstudio#555) A nested assignment through a missing intermediate element ($a[7][1] = 'patched' when $a[7] does not exist) lowered the parent chain as a plain READ: the miss produced a detached Mixed(null) box plus an "Undefined array key" warning, __rt_mixed_array_set hit its incompatible-target drop path, and the write was silently lost. PHP autovivifies the missing element as an array and emits no warning. Lower the parent chain with fetch-for-write semantics instead: - New runtime helper __rt_mixed_array_get_for_write mirrors the plain reader but installs an empty-array cell into missing indexed slots (growing and zero-filling gaps), null gap slots, boxed-null slots, and missing hash keys, and returns the STORED cell retained so the three-operand set writes through the parent storage. Indexed payloads are normalized through __rt_array_to_mixed first, which also fixes write-through for concrete intermediates of 3+ level chains (the residual limitation documented in the issue illegalstudio#529 fix). Non-container receivers tail-call the plain reader unchanged. - New wrapper __rt_array_ensure_elem_for_write applies the same logic to concrete array<mixed>/assoc locals through a transient stack cell and returns the possibly promoted or reallocated container for the local storeback (prepare/store_prepared bracketing, so boxed Mixed-storage slot owners are released exactly once). - New helper __rt_mixed_cell_promote_to_hash converts an indexed cell payload to hash storage (array_to_hash + hash_to_mixed, COW-safe); __rt_mixed_array_set now uses it for string keys on indexed payloads instead of dropping the write, matching PHP array-key semantics. A literal string key on an indexed local promotes the local through Op::ArrayToHash before the ensure call. - The write-context parent read emits no undefined-key warning, and the post-ensure re-read is in bounds, so legal autovivifying writes are silent like PHP. Both AArch64 and x86_64 emitters are implemented symmetrically. Incompatible scalar intermediates are intentionally not converted (the leaf set still drops the write; PHP raises an Error there). Claude-Session: https://claude.ai/code/session_01QyzntRke1Cgxgq1ueuz4X9
mirchaemanuel
force-pushed
the
fix/555-autovivify-missing-parent
branch
from
July 20, 2026 10:18
3ac326a to
074c195
Compare
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.
fix(ir,codegen): autovivify missing parents in nested array writes
Fixes #555.
Symptom
Root cause
The parent chain of a nested assignment was lowered as a plain read. A missing element produced a detached
Mixed(null)box (with an undefined-key warning), and__rt_mixed_array_setreleased the value in its incompatible-target path. Nothing installed a container into the missing slot: there were no write-context lookup semantics for intermediate elements. Additionally, a string key on an indexed payload branched to the same drop path, losing legal writes like$a[0]['new'] = 'v'.Fix
The parent chain now lowers with fetch-for-write semantics:
__rt_mixed_array_get_for_writeautovivifies missing indexed elements (grow, zero-fill, length update), null gap slots, boxed-null slots, and missing hash keys, installing an empty-array cell into the parent storage and returning the STORED cell (retained) so the three-operand set writes through the parent. Indexed payloads are first normalized via__rt_array_to_mixed(COW split + boxed slots, republished into the cell) — which also lands writes through concrete intermediates of 3+ level chains, the residual limitation documented in fix(ir): write nested array assignments through the parent cell (#529) #553.array<mixed>/assoc locals go through a new__rt_array_ensure_elem_for_writewrapper plus a local storeback; a literal string key on an indexed local promotes it viaOp::ArrayToHash.__rt_mixed_array_setnow promotes indexed payloads to hash storage for string keys (new__rt_mixed_cell_promote_to_hash) instead of dropping the write, matching PHP array-key semantics.Tests
tests/codegen/arrays/nested_autovivify.rs(14 tests): the exact issue repro, append position, null gap and boxed-null parents, assoc missing key, multi-level int and string chains from[], Mixed indexed/assoc receivers, string-key child promotion, existing-parent and shared-array COW controls, and function-return visibility; all assert no warning and heap-debug cleanliness. (The json_decode variant asserts stdout/warnings only — Mixed builtin results stored into locals leak one owner reference on currentmainindependently of nested writes, reproducible with a bare read.) 13/13 of the original tests failed before the fix.Limitations (documented)
Error: Cannot use a scalar value as an array— no error machinery added here).count()can differ from PHP's sparse arrays (pre-existing).QA
patched, zero warnings,leak summary: clean, under--ir-opt=onand=off.main(post-fix(ir): write nested array assignments through the parent cell (#529) #553, including its extendednested_mixed_writesuite):nested_autovivify14,nested_mixed_write8,arrays::366,mixed262 — all green. Pre-rebase full slices:nested155,json445,cargo test --lib930 (one pre-existing environment-dependent DNS test failure unrelated to this change, fails identically on pristine main). No new clippy warnings.https://claude.ai/code/session_01QyzntRke1Cgxgq1ueuz4X9