Skip to content

Preserve surviving offsets when popping or shifting a list - #6274

Merged
ondrejmirtes merged 1 commit into
2.2.xfrom
list-pop-shift-offsets
Aug 26, 2026
Merged

ondrejmirtes merged 1 commit into
2.2.xfrom
list-pop-shift-offsets

Conversation

@ondrejmirtes

Copy link
Copy Markdown
Member

Extracted from resolve-type-rewrite-2 (first of the tier-1/tier-2 extraction series).

When popping or shifting a list carrying hasOffsetValue(n, T) / hasOffset(n) accessory types, the surviving offsets were dropped entirely, so a subsequent array_pop()/array_shift() degraded to T|null even though the list provably still had elements:

  • pop removes the highest index, so offsets up to n − 1 survive as hasOffset (their values are unknown — the value known at n may have been the popped one).
  • shift reindexes, so index n's entry moves to n − 1, preserving hasOffsetValue.

Verified red before the fix: without the IntersectionType change, the new nsrt fixture fails with string|null where string is expected after array_pop() on a count-narrowed explode() result.

Gates: full suite 21155 tests / 96002 assertions green, make phpstan clean, make cs clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_01R7pqAkCx4xP6WYxBo2nMJE

$members[] = $type;
continue;
}
if ($type instanceof HasOffsetValueType || $type instanceof HasOffsetType) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need a nsrt test for a list which contains a mix of string and int offset-types

hasOffsetValue(n, T) on a list proves indices 0..n exist, so popping the
highest index keeps hasOffset(0..n-1) - previously the accessory answered
with no opinion and the whole intersection degraded to a possibly-empty
list, so a second array_pop() in the same statement typed as nullable.
Shifting reindexes, so the value known at n moves to n - 1 intact.
TemplateType members pass through unchanged, as in
intersectTypesPreserveTemplateType().
@ondrejmirtes
ondrejmirtes force-pushed the list-pop-shift-offsets branch from b6633b0 to 5ee6f45 Compare August 26, 2026 11:49
@ondrejmirtes
ondrejmirtes merged commit 24cde24 into 2.2.x Aug 26, 2026
408 of 413 checks passed
@ondrejmirtes
ondrejmirtes deleted the list-pop-shift-offsets branch August 26, 2026 11:50
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.

2 participants