Skip to content

Commit 18e9b45

Browse files
staabmphpstan-bot
authored andcommitted
Fix infinite loop in recursive generics (phpstan#5288)
1 parent 3dfce48 commit 18e9b45

File tree

3 files changed

+32
-1
lines changed

3 files changed

+32
-1
lines changed

src/Type/Generic/GenericObjectType.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use PHPStan\Type\IntersectionType;
2020
use PHPStan\Type\IsSuperTypeOfResult;
2121
use PHPStan\Type\ObjectType;
22+
use PHPStan\Type\RecursionGuard;
2223
use PHPStan\Type\Type;
2324
use PHPStan\Type\TypeWithClassName;
2425
use PHPStan\Type\UnionType;
@@ -95,7 +96,11 @@ public function getReferencedClasses(): array
9596
{
9697
$classes = parent::getReferencedClasses();
9798
foreach ($this->types as $type) {
98-
foreach ($type->getReferencedClasses() as $referencedClass) {
99+
$referencedClasses = RecursionGuard::runOnObjectIdentity($type, static fn () => $type->getReferencedClasses());
100+
if ($referencedClasses instanceof ErrorType) {
101+
continue;
102+
}
103+
foreach ($referencedClasses as $referencedClass) {
99104
$classes[] = $referencedClass;
100105
}
101106
}

tests/PHPStan/Analyser/AnalyserIntegrationTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,6 +1499,13 @@ public function testBug14324(): void
14991499
$this->assertNoErrors($errors);
15001500
}
15011501

1502+
public function testBug13801(): void
1503+
{
1504+
// endless loop crash
1505+
$errors = $this->runAnalyse(__DIR__ . '/data/bug-13801.php');
1506+
$this->assertNoErrors($errors);
1507+
}
1508+
15021509
/**
15031510
* @param string[]|null $allAnalysedFiles
15041511
* @return list<Error>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Bug13801;
6+
7+
/**
8+
* @template TValue of object
9+
*/
10+
interface Cast
11+
{
12+
}
13+
14+
/**
15+
* @template TCast of Cast<static>
16+
*/
17+
interface Castable
18+
{
19+
}

0 commit comments

Comments
 (0)