diff --git a/src/Rules/Arrays/InvalidKeyInArrayDimFetchRule.php b/src/Rules/Arrays/InvalidKeyInArrayDimFetchRule.php index 30f7febe49..e90c9bfe9e 100644 --- a/src/Rules/Arrays/InvalidKeyInArrayDimFetchRule.php +++ b/src/Rules/Arrays/InvalidKeyInArrayDimFetchRule.php @@ -10,7 +10,6 @@ use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Rules\RuleLevelHelper; use PHPStan\Type\ErrorType; -use PHPStan\Type\MixedType; use PHPStan\Type\Type; use PHPStan\Type\VerbosityLevel; use function sprintf; @@ -41,22 +40,27 @@ public function processNode(Node $node, Scope $scope): array return []; } - $dimensionType = $scope->getType($node->dim); - if ($dimensionType instanceof MixedType) { - return []; - } - $varType = $this->ruleLevelHelper->findTypeToCheck( $scope, $node->var, '', - static fn (Type $varType): bool => $varType->isArray()->no() || AllowedArrayKeysTypes::getType()->isSuperTypeOf($dimensionType)->yes(), + static fn (Type $varType): bool => $varType->isArray()->no(), )->getType(); if ($varType instanceof ErrorType || $varType->isArray()->no()) { return []; } + $dimensionType = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $node->dim, + '', + static fn (Type $dimType): bool => AllowedArrayKeysTypes::getType()->isSuperTypeOf($dimType)->yes(), + )->getType(); + if ($dimensionType instanceof ErrorType) { + return []; + } + $isSuperType = AllowedArrayKeysTypes::getType()->isSuperTypeOf($dimensionType); if ($isSuperType->yes() || ($isSuperType->maybe() && !$this->reportMaybes)) { return []; diff --git a/src/Rules/RuleLevelHelper.php b/src/Rules/RuleLevelHelper.php index 109b30a2b3..d82ff0745b 100644 --- a/src/Rules/RuleLevelHelper.php +++ b/src/Rules/RuleLevelHelper.php @@ -190,7 +190,11 @@ private function findTypeToCheckImplementation( bool $isTopLevel = false, ): FoundTypeResult { - if (!$this->checkNullables && !$type->isNull()->yes()) { + if ( + !$this->checkNullables + && !$type->isNull()->yes() + && !$unionTypeCriteriaCallback(new NullType()) + ) { $type = TypeCombinator::removeNull($type); } diff --git a/tests/PHPStan/Levels/LevelsIntegrationTest.php b/tests/PHPStan/Levels/LevelsIntegrationTest.php index 12499dce44..044a088f60 100644 --- a/tests/PHPStan/Levels/LevelsIntegrationTest.php +++ b/tests/PHPStan/Levels/LevelsIntegrationTest.php @@ -41,6 +41,7 @@ public static function dataTopics(): array ['arrayDestructuring'], ['listType'], ['missingTypes'], + ['arrayOffsetAccess'], ]; if (PHP_VERSION_ID >= 80300) { $topics[] = ['constantAccesses83']; diff --git a/tests/PHPStan/Levels/data/arrayOffsetAccess-10.json b/tests/PHPStan/Levels/data/arrayOffsetAccess-10.json new file mode 100644 index 0000000000..80b743c66c --- /dev/null +++ b/tests/PHPStan/Levels/data/arrayOffsetAccess-10.json @@ -0,0 +1,7 @@ +[ + { + "message": "Possibly invalid array key type mixed.", + "line": 22, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/arrayOffsetAccess-3.json b/tests/PHPStan/Levels/data/arrayOffsetAccess-3.json new file mode 100644 index 0000000000..3e23caff09 --- /dev/null +++ b/tests/PHPStan/Levels/data/arrayOffsetAccess-3.json @@ -0,0 +1,7 @@ +[ + { + "message": "Invalid array key type DateTimeImmutable.", + "line": 17, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/arrayOffsetAccess-4.json b/tests/PHPStan/Levels/data/arrayOffsetAccess-4.json new file mode 100644 index 0000000000..8ba1c517f1 --- /dev/null +++ b/tests/PHPStan/Levels/data/arrayOffsetAccess-4.json @@ -0,0 +1,37 @@ +[ + { + "message": "Expression \"$a[42]\" on a separate line does not do anything.", + "line": 15, + "ignorable": true + }, + { + "message": "Expression \"$a[null]\" on a separate line does not do anything.", + "line": 16, + "ignorable": true + }, + { + "message": "Expression \"$a[$intOrNull]\" on a separate line does not do anything.", + "line": 18, + "ignorable": true + }, + { + "message": "Expression \"$a[$objectOrInt]\" on a separate line does not do anything.", + "line": 19, + "ignorable": true + }, + { + "message": "Expression \"$a[$objectOrNull]\" on a separate line does not do anything.", + "line": 20, + "ignorable": true + }, + { + "message": "Expression \"$a[$explicitlyMixed]\" on a separate line does not do anything.", + "line": 21, + "ignorable": true + }, + { + "message": "Expression \"$a[$implicitlyMixed]\" on a separate line does not do anything.", + "line": 22, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/arrayOffsetAccess-6.json b/tests/PHPStan/Levels/data/arrayOffsetAccess-6.json new file mode 100644 index 0000000000..1e3cefa62e --- /dev/null +++ b/tests/PHPStan/Levels/data/arrayOffsetAccess-6.json @@ -0,0 +1,12 @@ +[ + { + "message": "Method Levels\\ArrayOffsetAccess\\Foo::test() has parameter $a with no value type specified in iterable type array.", + "line": 13, + "ignorable": true + }, + { + "message": "Method Levels\\ArrayOffsetAccess\\Foo::test() has parameter $implicitlyMixed with no type specified.", + "line": 13, + "ignorable": true + } +] diff --git a/tests/PHPStan/Levels/data/arrayOffsetAccess-7.json b/tests/PHPStan/Levels/data/arrayOffsetAccess-7.json new file mode 100644 index 0000000000..2df318590a --- /dev/null +++ b/tests/PHPStan/Levels/data/arrayOffsetAccess-7.json @@ -0,0 +1,12 @@ +[ + { + "message": "Possibly invalid array key type int|object.", + "line": 19, + "ignorable": true + }, + { + "message": "Possibly invalid array key type object|null.", + "line": 20, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/arrayOffsetAccess-9.json b/tests/PHPStan/Levels/data/arrayOffsetAccess-9.json new file mode 100644 index 0000000000..50cc3c7bbb --- /dev/null +++ b/tests/PHPStan/Levels/data/arrayOffsetAccess-9.json @@ -0,0 +1,7 @@ +[ + { + "message": "Possibly invalid array key type mixed.", + "line": 21, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/arrayOffsetAccess.php b/tests/PHPStan/Levels/data/arrayOffsetAccess.php new file mode 100644 index 0000000000..cff9bd9041 --- /dev/null +++ b/tests/PHPStan/Levels/data/arrayOffsetAccess.php @@ -0,0 +1,24 @@ +