Skip to content

Narrow parent constant array type when type-checking an array offset#5590

Closed
phpstan-bot wants to merge 2 commits intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-ekcy66x
Closed

Narrow parent constant array type when type-checking an array offset#5590
phpstan-bot wants to merge 2 commits intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-ekcy66x

Conversation

@phpstan-bot
Copy link
Copy Markdown
Collaborator

Summary

  • When is_string($arr['key']) (or similar type-check functions) narrows an array offset's type, also propagate a sureNotType on the parent array variable. This removes constant array members whose offset value is fully covered by the narrowing, preventing false positives when BooleanAnd's intersectWith drops entries for different expression keys.
  • Extend the coalesce simplification in createForExpr's false context so that is_string($x ?? null) in the falsey branch simplifies to narrowing $x (since string is non-null, the ?? null fallback is irrelevant).
  • Also fixes the same false positive in bug-9004.

Test plan

  • tests/PHPStan/Rules/Arrays/OffsetAccessAssignmentRuleTest::testBug14566 — regression test with both isset && is_string and is_string($x ?? null) patterns
  • tests/PHPStan/Rules/Arrays/OffsetAccessAssignmentRuleTest::testBug9004 — existing test updated (was asserting buggy behavior)
  • Full test suite passes (11,981 tests, 79,553 assertions)
  • PHPStan self-analysis passes (make phpstan)
  • Coding standards pass (make cs-fix)

Closes phpstan/phpstan#14566

When is_string($arr['key']) narrows the offset type, also propagate a
sureNotType on the parent array variable to remove constant array members
whose offset value is fully covered by the narrowing. This prevents false
positives when BooleanAnd's intersectWith drops entries for different
expression keys.

Also extend the coalesce simplification in createForExpr's false context
to handle non-null type checks (e.g. is_string($x ?? null) in the falsey
branch can be simplified to just narrowing $x).

Closes phpstan/phpstan#14566
@VincentLanglet VincentLanglet force-pushed the create-pull-request/patch-ekcy66x branch from c4a74c8 to 39ed27d Compare May 3, 2026 10:45
Copy link
Copy Markdown
Contributor

@VincentLanglet VincentLanglet left a comment

Choose a reason for hiding this comment

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

Explains why

/**
 * @param array{}|array{hi: 'hello'}|array{hi: array{0: 42, 1?: 42}} $test
 */
function foo(array $test): void {
	if (!isset($test['hi'])) {
		return;
	}
	if (\is_string($test['hi'])) {
		return;
	}
	$test['hi'][] = 42;
}

/**
 * @param array{}|array{hi: 'hello'}|array{hi: array{0: 42, 1?: 42}} $test
 */
function foo2(array $test): void {
	if (!\is_array($test['hi'] ?? null)) {
		return;
	}
	$test['hi'][] = 42;
}

already works fine

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@phpstan-bot
Copy link
Copy Markdown
Collaborator Author

Done. Added the two equivalent patterns from VincentLanglet's review as additional test cases (foo3 with split if statements, foo4 with is_array + ?? null) to document that these already worked before the fix. All tests (11,986) and make phpstan pass. Pushed to the branch.

@VincentLanglet VincentLanglet deleted the create-pull-request/patch-ekcy66x branch May 3, 2026 10:56
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