Skip to content

Commit 400ba6d

Browse files
committed
Fix infinite recursion with TemplateIterableType
1 parent 43c44ee commit 400ba6d

File tree

3 files changed

+39
-1
lines changed

3 files changed

+39
-1
lines changed

src/Type/UnionType.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use PHPStan\ShouldNotHappenException;
2121
use PHPStan\TrinaryLogic;
2222
use PHPStan\Type\Generic\GenericClassStringType;
23+
use PHPStan\Type\Generic\TemplateIterableType;
2324
use PHPStan\Type\Generic\TemplateMixedType;
2425
use PHPStan\Type\Generic\TemplateType;
2526
use PHPStan\Type\Generic\TemplateTypeMap;
@@ -236,7 +237,7 @@ public function isSuperTypeOfWithReason(Type $otherType): IsSuperTypeOfResult
236237
{
237238
if (
238239
($otherType instanceof self && !$otherType instanceof TemplateUnionType)
239-
|| $otherType instanceof IterableType
240+
|| ($otherType instanceof IterableType && !$otherType instanceof TemplateIterableType)
240241
|| $otherType instanceof NeverType
241242
|| $otherType instanceof ConditionalType
242243
|| $otherType instanceof ConditionalTypeForParameter

tests/PHPStan/Analyser/AnalyserIntegrationTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,16 @@ public function testBug5231Two(): void
451451
$this->assertNotEmpty($errors);
452452
}
453453

454+
public function testBug13218(): void
455+
{
456+
if (PHP_VERSION_ID < 80000) {
457+
$this->markTestSkipped('Test requires PHP 8.0.');
458+
}
459+
460+
$errors = $this->runAnalyse(__DIR__ . '/data/bug-13218.php');
461+
$this->assertNoErrors($errors);
462+
}
463+
454464
public function testBug5529(): void
455465
{
456466
$errors = $this->runAnalyse(__DIR__ . '/nsrt/bug-5529.php');
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php // lint >= 8.0
2+
3+
declare(strict_types = 1);
4+
5+
namespace Bug13218;
6+
7+
/**
8+
* @template TSteps of iterable<mixed>|int
9+
*/
10+
class Progress
11+
{
12+
public mixed $total = 0;
13+
14+
/**
15+
* Create a new ProgressBar instance.
16+
*
17+
* @param TSteps $steps
18+
*/
19+
public function __construct(public string $label, public iterable|int $steps, public string $hint = '')
20+
{
21+
$this->total = match (true) {
22+
is_int($this->steps) => $this->steps,
23+
is_countable($this->steps) => count($this->steps),
24+
is_iterable($this->steps) => iterator_count($this->steps),
25+
};
26+
}
27+
}

0 commit comments

Comments
 (0)