diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 12672c9d53..ecf824a240 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -5480,8 +5480,7 @@ private function processAssignVar( } if ($originalVar->dim instanceof Variable || $originalVar->dim instanceof Node\Scalar) { - $currentVarType = $scope->getType($originalVar); - if (!$originalValueToWrite->isSuperTypeOf($currentVarType)->yes()) { + if (!$scope->hasExpressionType($originalVar)->yes()) { $scope = $scope->assignExpression( $originalVar, $originalValueToWrite, diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index 7f3d9638b2..9dd8161487 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -208,6 +208,7 @@ private static function findTestFiles(): iterable yield __DIR__ . '/../Rules/Classes/data/bug-11591-property-tag.php'; yield __DIR__ . '/../Rules/Classes/data/mixin-trait-use.php'; + yield __DIR__ . '/../Rules/Arrays/data/bug-11679.php'; yield __DIR__ . '/../Rules/Methods/data/bug-4801.php'; } diff --git a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php index 78e8d86ccf..6557f97ed3 100644 --- a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php @@ -849,6 +849,20 @@ public function testArrayDimFetchOnArrayKeyFirsOrLastOrCount(): void ]); } + public function testBug12406(): void + { + $this->reportPossiblyNonexistentGeneralArrayOffset = true; + + $this->analyse([__DIR__ . '/data/bug-12406.php'], []); + } + + public function testBug11679(): void + { + $this->reportPossiblyNonexistentGeneralArrayOffset = true; + + $this->analyse([__DIR__ . '/data/bug-11679.php'], []); + } + public function testBug8649(): void { $this->reportPossiblyNonexistentGeneralArrayOffset = true; diff --git a/tests/PHPStan/Rules/Arrays/data/bug-11679.php b/tests/PHPStan/Rules/Arrays/data/bug-11679.php new file mode 100644 index 0000000000..463362516a --- /dev/null +++ b/tests/PHPStan/Rules/Arrays/data/bug-11679.php @@ -0,0 +1,39 @@ +arr); + if (!isset($this->arr['foo'])) { + $this->arr['foo'] = true; + assertType('array{foo: true}', $this->arr); + } + assertType('array{foo: bool}', $this->arr); + return $this->arr['foo']; // PHPStan realizes optional 'foo' is set + } +} + +class NonworkingExample +{ + /** @var array */ + private array $arr = []; + + public function sayHello(int $index): bool + { + assertType('array', $this->arr); + if (!isset($this->arr[$index]['foo'])) { + $this->arr[$index]['foo'] = true; + assertType('non-empty-array', $this->arr); + } + assertType('array', $this->arr); + return $this->arr[$index]['foo']; // PHPStan does not realize 'foo' is set + } +} diff --git a/tests/PHPStan/Rules/Arrays/data/bug-12406.php b/tests/PHPStan/Rules/Arrays/data/bug-12406.php new file mode 100644 index 0000000000..5d967399c1 --- /dev/null +++ b/tests/PHPStan/Rules/Arrays/data/bug-12406.php @@ -0,0 +1,15 @@ + */ + protected array $words = []; + + public function sayHello(string $word, int $count): void + { + $this->words[$word] ??= 0; + $this->words[$word] += $count; + } +}