Skip to content

Commit 6c45175

Browse files
committed
Array shape from general array with single finite key
1 parent 1485ccb commit 6c45175

6 files changed

+47
-13
lines changed

phpstan-baseline.neon

+6
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,12 @@ parameters:
210210
count: 1
211211
path: src/PhpDoc/TypeNodeResolver.php
212212

213+
-
214+
message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#'
215+
identifier: phpstanApi.instanceofType
216+
count: 1
217+
path: src/PhpDoc/TypeNodeResolver.php
218+
213219
-
214220
message: '#^Doing instanceof PHPStan\\Type\\Generic\\GenericObjectType is error\-prone and deprecated\.$#'
215221
identifier: phpstanApi.instanceofType

src/PhpDoc/TypeNodeResolver.php

+13-3
Original file line numberDiff line numberDiff line change
@@ -664,11 +664,21 @@ static function (string $variance): TemplateTypeVariance {
664664
if (count($genericTypes) === 1) { // array<ValueType>
665665
$arrayType = new ArrayType(new BenevolentUnionType([new IntegerType(), new StringType()]), $genericTypes[0]);
666666
} elseif (count($genericTypes) === 2) { // array<KeyType, ValueType>
667-
$keyType = TypeCombinator::intersect($genericTypes[0], new UnionType([
667+
$keyType = TypeCombinator::intersect($genericTypes[0]->toArrayKey(), new UnionType([
668668
new IntegerType(),
669669
new StringType(),
670-
]));
671-
$arrayType = new ArrayType($keyType->toArrayKey(), $genericTypes[1]);
670+
]))->toArrayKey();
671+
$finiteTypes = $keyType->getFiniteTypes();
672+
if (
673+
count($finiteTypes) === 1
674+
&& ($finiteTypes[0] instanceof ConstantStringType || $finiteTypes[0] instanceof ConstantIntegerType)
675+
) {
676+
$arrayBuilder = ConstantArrayTypeBuilder::createEmpty();
677+
$arrayBuilder->setOffsetValueType($finiteTypes[0], $genericTypes[1]);
678+
$arrayType = TypeCombinator::union($arrayBuilder->getArray(), ConstantArrayTypeBuilder::createEmpty()->getArray());
679+
} else {
680+
$arrayType = new ArrayType($keyType, $genericTypes[1]);
681+
}
672682
} else {
673683
return new ErrorType();
674684
}

tests/PHPStan/Analyser/nsrt/array-intersect-key.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public function normalArrays(array $arr, array $arr2, array $otherArrs): void
4545
/** @var array<17, int> $otherArrs */
4646
assertType('array<17, string>', array_intersect_key($arr, $otherArrs));
4747
/** @var array<null, int> $otherArrs */
48-
assertType('array{}', array_intersect_key($arr, $otherArrs));
48+
assertType('array<\'\', string>', array_intersect_key($arr, $otherArrs));
4949

5050
if (array_key_exists(17, $arr2)) {
5151
assertType('non-empty-array<17, string>&hasOffset(17)', array_intersect_key($arr2, [17 => 'bar']));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace ArrayShapeFromGeneralArrayWithSingleFiniteKey;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class Foo
8+
{
9+
10+
/**
11+
* @param array<1, string> $a
12+
*/
13+
public function doFoo(array $a): void
14+
{
15+
assertType('array{}|array{1: string}', $a);
16+
}
17+
18+
/**
19+
* @param non-empty-array<1, string> $a
20+
*/
21+
public function doBar(array $a): void
22+
{
23+
assertType('array{1: string}', $a);
24+
}
25+
26+
}

tests/PHPStan/Analyser/nsrt/bug-5287-php81.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ function foo4(array $arr): void
4848
function foo5(array $arr): void
4949
{
5050
$arrSpread = [...$arr];
51-
assertType('non-empty-array<int|string, bool|int>', $arrSpread);
51+
assertType('non-empty-array<bool|int>', $arrSpread);
5252
}
5353

5454
/**

tests/PHPStan/Rules/PhpDoc/IncompatiblePhpDocTypeRuleTest.php

-8
Original file line numberDiff line numberDiff line change
@@ -216,10 +216,6 @@ public function testBug3753(): void
216216
'PHPDoc tag @param for parameter $foo contains unresolvable type.',
217217
20,
218218
],
219-
[
220-
'PHPDoc tag @param for parameter $bars contains unresolvable type.',
221-
28,
222-
],
223219
]);
224220
}
225221

@@ -291,10 +287,6 @@ public function testParamOut(): void
291287
'Parameter $i for PHPDoc tag @param-out is not passed by reference.',
292288
37,
293289
],
294-
[
295-
'PHPDoc tag @param-out for parameter $i contains unresolvable type.',
296-
44,
297-
],
298290
[
299291
'PHPDoc tag @param-out for parameter $i contains generic type Exception<int, float> but class Exception is not generic.',
300292
51,

0 commit comments

Comments
 (0)