Skip to content

fix(types): list destructuring accepts a union/assoc RHS carrying an array member#522

Merged
nahime0 merged 5 commits into
illegalstudio:mainfrom
chadmandoo:upstream-pr/list-unpack-union-rhs
Jul 22, 2026
Merged

fix(types): list destructuring accepts a union/assoc RHS carrying an array member#522
nahime0 merged 5 commits into
illegalstudio:mainfrom
chadmandoo:upstream-pr/list-unpack-union-rhs

Conversation

@chadmandoo

Copy link
Copy Markdown
Contributor

What

list() / [$a, $b] = ... destructuring only accepted a plain Array(T) right-hand side and errored otherwise. A common pattern was rejected:

private function mk(int $n): ?array { /* ... */ }

$entry = $this->mk($n);
if ($entry === null) { continue; }
[$key, $value] = $entry;   // $entry types as Union[Array, Void] here

How

In check_list_unpack, accept an AssocArray RHS and a Union that carries an array-like member (Array / AssocArray / Mixed) — both are arrays at runtime in well-typed code. Their elements bind as Mixed (adaptive access), the trust posture PHP applies at runtime.

Test

test_list_unpack_null_narrowed_array_return — destructuring a null-narrowed ?array return in a loop, byte-parity vs PHP 8.5.

🤖 Generated with Claude Code

…array member

`list()` / `[$a, $b] = ...` destructuring only accepted a plain `Array(T)` RHS
and errored on everything else. A `?array` method return narrowed by `=== null`
still types as `Union[Array, Void]` at the destructure (and an associative-array
or Mixed union is an array at runtime in well-typed code). Accept an
`AssocArray` RHS and a union that carries an array-like member; their elements
bind as Mixed (adaptive access), the trust posture PHP applies at runtime.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@chadmandoo
chadmandoo force-pushed the upstream-pr/list-unpack-union-rhs branch from 4a3375d to 23ab06d Compare July 11, 2026 14:18
@github-actions github-actions Bot added area:types Touches type checking, inference, or compatibility. size:xs Very small pull request. type:fix Corrects broken or incompatible behavior. labels Jul 13, 2026

nahime0 commented Jul 22, 2026

Copy link
Copy Markdown
Member

Maintainer follow-up:

The original Union(...).any(array-like) workaround has been replaced locally with a fix at the narrowing boundary.

Changes prepared on the maintainer worktree:

  • merged the current main into the PR branch (7dc840c89);
  • changed post-guard analysis so direct continue and break bodies are treated as non-fallthrough, preserving the complement after if ($entry === null) { ... };
  • removed the permissive union branch from check_list_unpack, so an unguarded ?array is rejected again instead of being accepted because one union member is array-like;
  • kept AssocArray as an independently valid list-unpack RHS, with conservative Mixed element typing;
  • added focused regressions for continue, break, associative storage, and rejection of nullable arrays without a guard.

Local validation is green:

  • cargo build
  • focused list-unpack error tests: 2 passed
  • focused list-unpack codegen tests: 3 passed
  • existing throw-guard narrowing regression: passed
  • cargo fmt --check
  • git diff --check

The broader pre-existing limitation in the block fallthrough analysis is intentionally kept out of this PR and tracked separately in #590.

@github-actions github-actions Bot added size:s Small pull request. and removed size:xs Very small pull request. labels Jul 22, 2026
@nahime0
nahime0 merged commit b2086eb into illegalstudio:main Jul 22, 2026
113 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:types Touches type checking, inference, or compatibility. size:s Small pull request. type:fix Corrects broken or incompatible behavior.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants