diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 2bedcd238e..075b4c99bd 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -4367,7 +4367,7 @@ public function specifyExpressionType(Expr $expr, Type $type, Type $nativeType, && !$expr->dim instanceof Expr\PostInc ) { $dimType = $scope->getType($expr->dim)->toArrayKey(); - if ($dimType->isInteger()->yes() || $dimType->isString()->yes()) { + if ($dimType instanceof ConstantIntegerType || $dimType instanceof ConstantStringType) { $exprVarType = $scope->getType($expr->var); if (!$exprVarType instanceof MixedType && !$exprVarType->isArray()->no()) { $types = [ @@ -4375,21 +4375,16 @@ public function specifyExpressionType(Expr $expr, Type $type, Type $nativeType, new ObjectType(ArrayAccess::class), new NullType(), ]; - if ($dimType->isInteger()->yes()) { + if ($dimType instanceof ConstantIntegerType) { $types[] = new StringType(); } - $offsetValueType = TypeCombinator::intersect($exprVarType, TypeCombinator::union(...$types)); - - if ($dimType instanceof ConstantIntegerType || $dimType instanceof ConstantStringType) { - $offsetValueType = TypeCombinator::intersect( - $offsetValueType, - new HasOffsetValueType($dimType, $type), - ); - } $scope = $scope->specifyExpressionType( $expr->var, - $offsetValueType, + TypeCombinator::intersect( + TypeCombinator::intersect($exprVarType, TypeCombinator::union(...$types)), + new HasOffsetValueType($dimType, $type), + ), $scope->getNativeType($expr->var), $certainty, ); diff --git a/tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php b/tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php index 96b89cf070..cbd0e45c27 100644 --- a/tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php +++ b/tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php @@ -1169,4 +1169,14 @@ public function testBug8719(): void $this->analyse([__DIR__ . '/data/bug-8719.php'], []); } + public function testBug13694(): void + { + $this->cliArgumentsVariablesRegistered = true; + $this->polluteScopeWithLoopInitialAssignments = true; + $this->checkMaybeUndefinedVariables = true; + $this->polluteScopeWithAlwaysIterableForeach = true; + + $this->analyse([__DIR__ . '/data/bug-13694.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Variables/data/bug-13694.php b/tests/PHPStan/Rules/Variables/data/bug-13694.php new file mode 100644 index 0000000000..8d71a3a89c --- /dev/null +++ b/tests/PHPStan/Rules/Variables/data/bug-13694.php @@ -0,0 +1,19 @@ + $things + */ +function evaluateThings(array $keys, array $things): void +{ + foreach ($keys as $key) { + if (array_key_exists($key, $things) && $things[$key] === null) { + echo "Value for key $key is null\n"; + continue; + } + + if (isset($things[$key])) { + echo "Key $key is set\n"; + } + } +}