Skip to content

Commit 1865530

Browse files
VincentLangletphpstan-bot
authored andcommitted
Fix ObjectType::equals() treating generic and non-generic types as equal
- ObjectType::equals(GenericObjectType) incorrectly returned true when both had the same class name, because it didn't check whether generic type arguments differed - This caused MutatingScope::mergeWith() native type optimization to replace native types (e.g. ArrayObject) with PHPDoc-enriched types (e.g. ArrayObject<string, string>), contaminating native type tracking after any branch merge - With treatPhpDocTypesAsCertain: false, this led to false "will always evaluate to true" errors for is_string/is_int checks on foreach values from generic objects - Added get_class equality check in ObjectType::equals() which also subsumes the old instanceof EnumCaseObjectType check - Removed now-unneeded baseline entry for the EnumCaseObjectType instanceof check - New regression test in tests/PHPStan/Rules/Comparison/data/bug-14429.php
1 parent 3a4c0e2 commit 1865530

File tree

4 files changed

+52
-7
lines changed

4 files changed

+52
-7
lines changed

phpstan-baseline.neon

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,12 +1473,6 @@ parameters:
14731473
count: 1
14741474
path: src/Type/ObjectShapeType.php
14751475

1476-
-
1477-
rawMessage: 'Doing instanceof PHPStan\Type\Enum\EnumCaseObjectType is error-prone and deprecated. Use Type::getEnumCases() instead.'
1478-
identifier: phpstanApi.instanceofType
1479-
count: 1
1480-
path: src/Type/ObjectType.php
1481-
14821476
-
14831477
rawMessage: Doing instanceof PHPStan\Type\Generic\GenericObjectType is error-prone and deprecated.
14841478
identifier: phpstanApi.instanceofType

src/Type/ObjectType.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
use function array_map;
5757
use function array_values;
5858
use function count;
59+
use function get_class;
5960
use function implode;
6061
use function in_array;
6162
use function sprintf;
@@ -628,7 +629,7 @@ public function equals(Type $type): bool
628629
return false;
629630
}
630631

631-
if ($type instanceof EnumCaseObjectType) {
632+
if (get_class($type) !== static::class) {
632633
return false;
633634
}
634635

tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,4 +1207,11 @@ public function testBug13799(): void
12071207
]);
12081208
}
12091209

1210+
#[RequiresPhp('>= 8.1')]
1211+
public function testBug14429(): void
1212+
{
1213+
$this->treatPhpDocTypesAsCertain = false;
1214+
$this->analyse([__DIR__ . '/data/bug-14429.php'], []);
1215+
}
1216+
12101217
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php // lint >= 8.1
2+
3+
declare(strict_types = 1);
4+
5+
namespace Bug14429;
6+
7+
function throw_if(bool $condition, string $message): void
8+
{
9+
if ($condition) { throw new \Exception($message); }
10+
}
11+
12+
class Foo
13+
{
14+
/**
15+
* @param list<string> $tags
16+
* @param list<float> $scores
17+
* @param \ArrayObject<string, string> $stringMap
18+
* @param \ArrayObject<string, int> $intKeyMap
19+
*/
20+
public function __construct(
21+
public array $tags,
22+
public array $scores,
23+
public ?\ArrayObject $stringMap = null,
24+
public ?\ArrayObject $intKeyMap = null,
25+
) {
26+
foreach ($tags as $tagsItem) {
27+
throw_if(!is_string($tagsItem), 'tags item must be string');
28+
}
29+
foreach ($scores as $scoresItem) {
30+
throw_if(!is_int($scoresItem) && !is_float($scoresItem), 'scores item must be number');
31+
}
32+
if ($stringMap !== null) {
33+
foreach ($stringMap as $stringMapValue) {
34+
throw_if(!is_string($stringMapValue), 'stringMap value must be string');
35+
}
36+
}
37+
if ($intKeyMap !== null) {
38+
foreach ($intKeyMap as $intKeyMapValue) {
39+
throw_if(!is_int($intKeyMapValue), 'intKeyMap value must be int');
40+
}
41+
}
42+
}
43+
}

0 commit comments

Comments
 (0)