diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 75d229b285..e5091e0296 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -2039,6 +2039,17 @@ public function getNativeType(Expr $expr): Type return $this->nativeExpressionTypes[$key]; } + if ($expr instanceof Expr\ArrayDimFetch && $expr->dim !== null) { + return $this->getNullsafeShortCircuitingType( + $expr->var, + $this->getTypeFromArrayDimFetch( + $expr, + $this->getNativeType($expr->dim), + $this->getNativeType($expr->var) + ) + ); + } + return $this->getType($expr); } diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index 5bdeac0fb3..e1133a8cda 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -10347,6 +10347,11 @@ public function dataIncDecInConditions(): array return $this->gatherAssertTypes(__DIR__ . '/data/inc-dec-in-conditions.php'); } + public function dataBug4099(): array + { + return $this->gatherAssertTypes(__DIR__ . '/data/bug-4099.php'); + } + /** * @param string $file * @return array @@ -10529,6 +10534,7 @@ private function gatherAssertTypes(string $file): array * @dataProvider dataComparisonOperators * @dataProvider dataBug3880 * @dataProvider dataIncDecInConditions + * @dataProvider dataBug4099 * @param string $assertType * @param string $file * @param mixed ...$args diff --git a/tests/PHPStan/Analyser/data/bug-4099.php b/tests/PHPStan/Analyser/data/bug-4099.php new file mode 100644 index 0000000000..aead9a8747 --- /dev/null +++ b/tests/PHPStan/Analyser/data/bug-4099.php @@ -0,0 +1,41 @@ + array(\'inner\' => mixed))', $arr); + assertNativeType('array', $arr); + + if (!array_key_exists('key', $arr)) { + assertType('*NEVER*', $arr); + assertNativeType('array', $arr); + throw new \Exception('no key "key" found.'); + } + assertType('array(\'key\' => array(\'inner\' => mixed))', $arr); + assertNativeType('array&hasOffset(\'key\')', $arr); + assertType('array(\'inner\' => mixed)', $arr['key']); + assertNativeType('mixed', $arr['key']); + + if (!array_key_exists('inner', $arr['key'])) { + assertType('array(\'key\' => *NEVER*)', $arr); + //assertNativeType('array(\'key\' => mixed)', $arr); + assertType('*NEVER*', $arr['key']); + //assertNativeType('mixed', $arr['key']); + throw new \Exception('need key.inner'); + } + + assertType('array(\'key\' => array(\'inner\' => mixed))', $arr); + assertNativeType('array(\'key\' => array(\'inner\' => mixed))', $arr); + } + +}