Skip to content

Fix #14124: Reassigning to array<string, list<T>> out parameter does not see the list<T> property during assignment#4999

Open
phpstan-bot wants to merge 1 commit into2.1.xfrom
create-pull-request/patch-kundrtk
Open

Fix #14124: Reassigning to array<string, list<T>> out parameter does not see the list<T> property during assignment#4999
phpstan-bot wants to merge 1 commit into2.1.xfrom
create-pull-request/patch-kundrtk

Conversation

@phpstan-bot
Copy link
Collaborator

Summary

When a function has a @param-out array<string, list<string>> parameter and reassigns values via nested array dimension assignment ($convert[$outerKey][$key] = strtoupper($val)), PHPStan incorrectly reported a paramOut.type error because it saw the type as non-empty-array<string, array<int<0, max>, string>> instead of preserving the list<string> inner type.

Changes

  • Changed VariableAssignNode callback in the ArrayDimFetch assignment handling of src/Analyser/NodeScopeResolver.php (lines 6300, 6317) to pass new TypeExpr($valueToWrite) instead of $assignedPropertyExpr
  • Added regression test in tests/PHPStan/Rules/Variables/data/bug-14124.php and test method in tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php

Root cause

When processing nested array dim assignments like $convert[$outerKey][$key] = expr, two separate type computations occur:

  1. produceArrayDimFetchAssignValueToWrite — correctly uses cross-paired dim fetch expressions to determine when to call setExistingOffsetValueType vs setOffsetValueType, preserving list types
  2. $assignedPropertyExpr expression tree (built in the while loop) — only uses SetExistingOffsetValueTypeExpr for the outermost dim fetch ($var === $originalVar), falling back to SetOffsetValueTypeExpr for inner dims

The ParameterOutAssignedTypeRule evaluates the $assignedPropertyExpr tree via $scope->getType($node->getAssignedExpr()), which calls setOffsetValueType on the inner list<string> with an int<0, max> key. This destroys the AccessoryArrayListType (since setOffsetValueType returns ErrorType for non-zero/non-null offsets).

The fix passes the already-computed $valueToWrite (from produceArrayDimFetchAssignValueToWrite) directly as a TypeExpr to the VariableAssignNode, ensuring the rule sees the same correct type that gets assigned to the variable in scope.

Test

Added a regression test with two functions: one using by-reference foreach (already working) and one using indexed assignment ($convert[$outerKey][$key] = strtoupper($val)) which was the failing case. Both should analyze without errors.

Fixes phpstan/phpstan#14124

- Pass correctly computed valueToWrite type to VariableAssignNode instead of
  the assignedPropertyExpr expression tree which loses list types on nested
  array dimension assignments
- The assignedPropertyExpr uses setOffsetValueType for non-outermost dims,
  losing AccessoryArrayListType, while produceArrayDimFetchAssignValueToWrite
  correctly uses setExistingOffsetValueType via cross-paired dim fetch checks
- New regression test in tests/PHPStan/Rules/Variables/data/bug-14124.php

Closes phpstan/phpstan#14124
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

Comments