Skip to content

Preserve array type through dependent offset assignment with template keys#5625

Open
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-dw7utkc
Open

Preserve array type through dependent offset assignment with template keys#5625
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-dw7utkc

Conversation

@phpstan-bot
Copy link
Copy Markdown
Collaborator

Summary

Fixes false positives when assigning to an array with a dependent template key and value type, such as $attr[$key] = $val where $key: K of key-of<Attrs> and $val: Attrs[K].

Previously, PHPStan eagerly resolved Attrs[K] (an OffsetAccessType) into the union of all possible value types (string|5|6|7|bool), then widened each key's value type with this union, producing non-empty-array<'bar'|'baz'|'foo'|K, 5|6|7|bool|string> instead of preserving the original array{foo?: string, bar?: 5|6|7, baz?: bool}. This caused a false positive on the subsequent $this->setAttributes($attr) call.

Changes

  • src/Analyser/ExprHandler/AssignHandler.php: Before calling produceArrayDimFetchAssignValueToWrite(), detect when the assignment follows a dependent offset access pattern by inspecting the raw (unresolved) expression type from the scope. When the raw value type is an OffsetAccessType whose offset matches the dim's template parameter and whose accessed type is a supertype of the target array, skip the widening and preserve the original array type. Uses template identity comparison (name + scope) rather than strict equals() to handle cases where the same template K appears as TemplateKeyOfType vs TemplateStringType.

  • src/Type/OffsetAccessType.php: Added getAccessedType() and getAccessedOffset() public getters to enable inspecting the components of an OffsetAccessType.

  • tests/PHPStan/Analyser/nsrt/bug-7380.php: New regression test covering both the concrete type alias case (@phpstan-type Attrs) and the generic class case (@template T).

  • tests/PHPStan/Analyser/AnalyserIntegrationTest.php: Updated testBug7094() to remove the false positive assertion at line 29 (previously expected 6 errors, now correctly expects 5).

Closes phpstan/phpstan#7380

… keys

When assigning `$arr[$key] = $val` where `$key` is a template key-of<T>
and `$val` is T[$key] (an OffsetAccessType), the assignment is type-
preserving by definition. Previously PHPStan would eagerly resolve the
OffsetAccessType, losing the dependent relationship between key and value,
then widen all value types to the union of all possible values.

Detect this pattern in AssignHandler by examining the raw (unresolved)
expression type: if the assigned value's raw type is an OffsetAccessType
whose offset matches the dim's template parameter and whose accessed type
is a supertype of the array being assigned to, skip the widening step and
preserve the original array type.

Also compare template parameters by identity (name + scope) rather than
strict equals, since the same template K may appear as TemplateKeyOfType
in the OffsetAccessType but as TemplateStringType in the resolved dim.

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