Skip to content

Commit 07607df

Browse files
Fix NumericString to array key
1 parent cb8f910 commit 07607df

File tree

8 files changed

+64
-12
lines changed

8 files changed

+64
-12
lines changed

src/Type/Accessory/AccessoryNumericStringType.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,13 @@ public function toArray(): Type
218218

219219
public function toArrayKey(): Type
220220
{
221-
return new IntegerType();
221+
return new UnionType([
222+
new IntegerType(),
223+
new IntersectionType([
224+
new StringType(),
225+
new AccessoryNumericStringType(),
226+
]),
227+
]);
222228
}
223229

224230
public function isNull(): TrinaryLogic

src/Type/Constant/ConstantArrayType.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -601,11 +601,17 @@ public function findTypeAndMethodNames(): array
601601

602602
public function hasOffsetValueType(Type $offsetType): TrinaryLogic
603603
{
604-
$offsetType = $offsetType->toArrayKey();
604+
$offsetArrayKeyType = $offsetType->toArrayKey();
605+
606+
return $this->recursiveHasOffsetValueType($offsetArrayKeyType);
607+
}
608+
609+
private function recursiveHasOffsetValueType(Type $offsetType): TrinaryLogic
610+
{
605611
if ($offsetType instanceof UnionType) {
606612
$results = [];
607613
foreach ($offsetType->getTypes() as $innerType) {
608-
$results[] = $this->hasOffsetValueType($innerType);
614+
$results[] = $this->recursiveHasOffsetValueType($innerType);
609615
}
610616

611617
return TrinaryLogic::extremeIdentity(...$results);
@@ -615,7 +621,7 @@ public function hasOffsetValueType(Type $offsetType): TrinaryLogic
615621
if ($finiteTypes !== []) {
616622
$results = [];
617623
foreach ($finiteTypes as $innerType) {
618-
$results[] = $this->hasOffsetValueType($innerType);
624+
$results[] = $this->recursiveHasOffsetValueType($innerType);
619625
}
620626

621627
return TrinaryLogic::extremeIdentity(...$results);

src/Type/IntersectionType.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,10 @@ public function toArray(): Type
957957
public function toArrayKey(): Type
958958
{
959959
if ($this->isNumericString()->yes()) {
960-
return new IntegerType();
960+
return new UnionType([
961+
new IntegerType(),
962+
$this,
963+
]);
961964
}
962965

963966
if ($this->isString()->yes()) {

tests/PHPStan/Analyser/nsrt/bug-3133.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public function doLorem(
5252
{
5353
$a = [];
5454
$a[$numericString] = 'foo';
55-
assertType('non-empty-array<int, \'foo\'>', $a);
55+
assertType('non-empty-array<int|numeric-string, \'foo\'>', $a);
5656
}
5757

5858
}

tests/PHPStan/Analyser/nsrt/isset-coalesce-empty-type.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ class Bug4671
296296
*/
297297
public function doFoo(int $intput, array $strings): void
298298
{
299-
assertType('false', isset($strings[(string) $intput]));
299+
assertType('bool', isset($strings[(string) $intput]));
300300
}
301301

302302
}

tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1051,7 +1051,17 @@ public function testBug11337(): void
10511051

10521052
public function testBug10715(): void
10531053
{
1054-
$this->analyse([__DIR__ . '/data/bug-10715.php'], []);
1054+
$this->analyse([__DIR__.'/data/bug-10715.php'], []);
1055+
}
1056+
1057+
public function testBug4163(): void
1058+
{
1059+
$this->analyse([__DIR__ . '/data/bug-4163.php'], [
1060+
[
1061+
'Method Bug4163\HelloWorld::lall() should return array<string, string> but returns array<int|string, string>.',
1062+
28,
1063+
],
1064+
]);
10551065
}
10561066

10571067
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug4163;
4+
5+
class HelloWorld
6+
{
7+
/**
8+
* @phpstan-var numeric
9+
*/
10+
public $lall = 0;
11+
12+
/**
13+
* @phpstan-return array<string, string>
14+
*/
15+
function lall() {
16+
$helloCollection = [new HelloWorld(), new HelloWorld()];
17+
$result = [];
18+
19+
foreach ($helloCollection as $hello) {
20+
$key = (string)$hello->lall;
21+
22+
if (!isset($result[$key])) {
23+
$lall = 'do_something_here';
24+
$result[$key] = $lall;
25+
}
26+
}
27+
28+
return $result;
29+
}
30+
}

tests/PHPStan/Rules/Variables/IssetRuleTest.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -233,10 +233,7 @@ public function testBug4671(): void
233233
{
234234
$this->treatPhpDocTypesAsCertain = true;
235235
$this->strictUnnecessaryNullsafePropertyFetch = false;
236-
$this->analyse([__DIR__ . '/data/bug-4671.php'], [[
237-
'Offset numeric-string on array<string, string> in isset() does not exist.',
238-
13,
239-
]]);
236+
$this->analyse([__DIR__ . '/data/bug-4671.php'], []);
240237
}
241238

242239
public function testVariableCertaintyInIsset(): void

0 commit comments

Comments
 (0)