Skip to content

Commit cabdea2

Browse files
committed
Fix ternary-in-condition analysis explosion
1 parent 2295fee commit cabdea2

File tree

3 files changed

+68
-0
lines changed

3 files changed

+68
-0
lines changed

src/Analyser/TypeSpecifier.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,6 +1120,7 @@ public function specifyTypesInCondition(
11201120
} elseif (
11211121
$expr instanceof Expr\Ternary
11221122
&& !$context->null()
1123+
&& !$expr->cond instanceof Expr\Ternary
11231124
) {
11241125
$ifExpr = $expr->if ?? $expr->cond;
11251126
$conditionExpr = new BooleanOr(

tests/PHPStan/Analyser/AnalyserIntegrationTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,13 @@ public function testBug4702(): void
427427
$this->assertNoErrors($errors);
428428
}
429429

430+
#[RequiresPhp('>= 8.1')]
431+
public function testBug14100(): void
432+
{
433+
$errors = $this->runAnalyse(__DIR__ . '/data/bug-14100.php');
434+
$this->assertNoErrors($errors);
435+
}
436+
430437
public function testFunctionThatExistsOn72AndLater(): void
431438
{
432439
$errors = $this->runAnalyse(__DIR__ . '/data/ldap-exop-passwd.php');
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php // lint >= 8.1
2+
3+
namespace Bug14100;
4+
5+
class Locality
6+
{
7+
8+
public function getParent(): ?self
9+
{
10+
return null;
11+
}
12+
13+
public function isShownInFilter(): bool
14+
{
15+
return false;
16+
}
17+
18+
public function getId(): int
19+
{
20+
return 1;
21+
}
22+
23+
public function getType(): LocalityType
24+
{
25+
return LocalityType::CITY;
26+
}
27+
28+
}
29+
30+
enum LocalityType
31+
{
32+
33+
case REGION;
34+
case RESORT;
35+
case MOUNTAINS;
36+
case ISLAND;
37+
case WINE_AREA;
38+
case CITY;
39+
40+
public function contains(self $s): bool
41+
{
42+
return false;
43+
}
44+
45+
}
46+
47+
/** @param list<Locality> $localities */
48+
function foo(array $localities): void
49+
{
50+
usort($localities, static fn (Locality $a, Locality $b): int => (int) ($b->getParent() !== null) <=> (int) ($a->getParent() !== null)
51+
?: (int) $a->getType()->contains(LocalityType::REGION) <=> (int) $b->getType()->contains(LocalityType::REGION)
52+
?: (int) $b->getType()->contains(LocalityType::CITY) <=> (int) $a->getType()->contains(LocalityType::CITY)
53+
?: (int) $b->getType()->contains(LocalityType::RESORT) <=> (int) $a->getType()->contains(LocalityType::RESORT)
54+
?: (int) $b->getType()->contains(LocalityType::MOUNTAINS) <=> (int) $a->getType()->contains(LocalityType::MOUNTAINS)
55+
?: (int) $b->getType()->contains(LocalityType::ISLAND) <=> (int) $a->getType()->contains(LocalityType::ISLAND)
56+
?: (int) $b->getType()->contains(LocalityType::WINE_AREA) <=> (int) $a->getType()->contains(LocalityType::WINE_AREA)
57+
?: (int) $b->isShownInFilter() <=> (int) $a->isShownInFilter()
58+
?: $a->getId() <=> $b->getId()
59+
);
60+
}

0 commit comments

Comments
 (0)