Skip to content

Commit

Permalink
isset() narrows string-key in int-keyed-array to numeric-string
Browse files Browse the repository at this point in the history
  • Loading branch information
staabm committed Sep 23, 2024
1 parent 9843dd8 commit 2f2e842
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 17 deletions.
2 changes: 1 addition & 1 deletion src/Analyser/TypeSpecifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,7 @@ public function specifyTypesInCondition(
);
} else {
$varType = $scope->getType($var->var);
$narrowedKey = AllowedArrayKeysTypes::narrowOffsetKeyType($varType);
$narrowedKey = AllowedArrayKeysTypes::narrowOffsetKeyType($varType, $dimType);
if ($narrowedKey !== null) {
$types = $types->unionWith(
$this->create(
Expand Down
26 changes: 15 additions & 11 deletions src/Rules/Arrays/AllowedArrayKeysTypes.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ public static function getType(): Type
]);
}

public static function narrowOffsetKeyType(Type $varType): ?Type {
public static function narrowOffsetKeyType(Type $varType, Type $keyType): ?Type
{
if (!$varType->isArray()->yes() || $varType->isIterableAtLeastOnce()->no()) {
return null;
}
Expand Down Expand Up @@ -66,17 +67,20 @@ public static function narrowOffsetKeyType(Type $varType): ?Type {
if (!$varIterableKeyType->isNumericString()->no() || !$varIterableKeyType->isInteger()->no()) {
$narrowedKey = TypeCombinator::union($narrowedKey, new FloatType());
}
} else {
$narrowedKey = new MixedType(
false,
new UnionType([
new ArrayType(new MixedType(), new MixedType()),
new ObjectWithoutClassType(),
new ResourceType(),
]),
);

return $narrowedKey;
} elseif ($varIterableKeyType->isInteger()->yes() && $keyType->isString()->yes()) {
return TypeCombinator::intersect($varIterableKeyType->toString(), $keyType);
}

return $narrowedKey;
return new MixedType(
false,
new UnionType([
new ArrayType(new MixedType(), new MixedType()),
new ObjectWithoutClassType(),
new ResourceType(),
]),
);
}

}
32 changes: 27 additions & 5 deletions tests/PHPStan/Analyser/nsrt/bug-11716.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ public function parse(string $glue): string
}

/**
* @param array<int, string> $arr
* @param array<int, string> $intKeyedArr
* @param array<string, string> $stringKeyedArr
*/
function narrowKey($mixed, string $s, int $i, array $generalArr, array $arr): void {
function narrowKey($mixed, string $s, int $i, array $generalArr, array $intKeyedArr, array $stringKeyedArr): void {
if (isset($generalArr[$mixed])) {
assertType('mixed~(array|object|resource)', $mixed);
} else {
Expand All @@ -59,21 +60,42 @@ function narrowKey($mixed, string $s, int $i, array $generalArr, array $arr): vo
}
assertType('string', $s);

if (isset($arr[$mixed])) {
if (isset($intKeyedArr[$mixed])) {
assertType('mixed~(array|object|resource)', $mixed);
} else {
assertType('mixed', $mixed);
}
assertType('mixed', $mixed);

if (isset($arr[$i])) {
if (isset($intKeyedArr[$i])) {
assertType('int', $i);
} else {
assertType('int', $i);
}
assertType('int', $i);

if (isset($arr[$s])) {
if (isset($intKeyedArr[$s])) {
assertType("numeric-string", $s);
} else {
assertType('string', $s);
}
assertType('string', $s);

if (isset($stringKeyedArr[$mixed])) {
assertType('mixed~(array|object|resource)', $mixed);
} else {
assertType('mixed', $mixed);
}
assertType('mixed', $mixed);

if (isset($stringKeyedArr[$i])) {
assertType('int', $i);
} else {
assertType('int', $i);
}
assertType('int', $i);

if (isset($stringKeyedArr[$s])) {
assertType('string', $s);
} else {
assertType('string', $s);
Expand Down

0 comments on commit 2f2e842

Please sign in to comment.