Skip to content

Commit f882eff

Browse files
committed
Fix arithmetic operations with BenevolentUnionType
1 parent 7abcc51 commit f882eff

File tree

3 files changed

+69
-2
lines changed

3 files changed

+69
-2
lines changed

src/Type/UnionType.php

+24-2
Original file line numberDiff line numberDiff line change
@@ -735,12 +735,12 @@ public function isConstantScalarValue(): TrinaryLogic
735735

736736
public function getConstantScalarTypes(): array
737737
{
738-
return $this->pickFromTypes(static fn (Type $type) => $type->getConstantScalarTypes());
738+
return $this->notBenevolentPickFromTypes(static fn (Type $type) => $type->getConstantScalarTypes());
739739
}
740740

741741
public function getConstantScalarValues(): array
742742
{
743-
return $this->pickFromTypes(static fn (Type $type) => $type->getConstantScalarValues());
743+
return $this->notBenevolentPickFromTypes(static fn (Type $type) => $type->getConstantScalarValues());
744744
}
745745

746746
public function isTrue(): TrinaryLogic
@@ -1008,4 +1008,26 @@ protected function pickFromTypes(callable $getValues): array
10081008
return $values;
10091009
}
10101010

1011+
/**
1012+
* @template T
1013+
* @param callable(Type $type): list<T> $getValues
1014+
* @return list<T>
1015+
*/
1016+
private function notBenevolentPickFromTypes(callable $getValues): array
1017+
{
1018+
$values = [];
1019+
foreach ($this->types as $type) {
1020+
$innerValues = $getValues($type);
1021+
if ($innerValues === []) {
1022+
return [];
1023+
}
1024+
1025+
foreach ($innerValues as $innerType) {
1026+
$values[] = $innerType;
1027+
}
1028+
}
1029+
1030+
return $values;
1031+
}
1032+
10111033
}

tests/PHPStan/Analyser/NodeScopeResolverTest.php

+1
Original file line numberDiff line numberDiff line change
@@ -1201,6 +1201,7 @@ public function dataFileAsserts(): iterable
12011201
yield from $this->gatherAssertTypes(__DIR__ . '/data/list-shapes.php');
12021202
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-7607.php');
12031203
yield from $this->gatherAssertTypes(__DIR__ . '/data/ibm_db2.php');
1204+
yield from $this->gatherAssertTypes(__DIR__ . '/data/benevolent-union-math.php');
12041205
}
12051206

12061207
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace BenevolentUnionMath;
4+
5+
use function PHPStan\Testing\assertType;
6+
use function strtotime;
7+
8+
class Foo
9+
{
10+
11+
public function doFoo($s, $r)
12+
{
13+
$timeS = strtotime($s);
14+
assertType('(int|false)', $timeS);
15+
16+
$timeR = strtotime($r);
17+
assertType('(int|false)', $timeR);
18+
19+
assertType('int', $timeS - $timeR);
20+
}
21+
22+
}
23+
24+
class HelloWorld
25+
{
26+
public function sayHello(int $x): void
27+
{
28+
$dbresponse = $this->getBenevolent();
29+
assertType('array<string, (float|int|string|null)>|null', $dbresponse);
30+
31+
if ($dbresponse === null) {return;}
32+
33+
assertType('array<string, (float|int|string|null)>', $dbresponse);
34+
assertType('(float|int|string|null)', $dbresponse['Value']);
35+
assertType('int<0, max>', strlen($dbresponse['Value']));
36+
}
37+
38+
/**
39+
* @return array<string, __benevolent<float|int|string|null>>|null
40+
*/
41+
private function getBenevolent(): ?array{
42+
return rand(10) > 1 ? null : [];
43+
}
44+
}

0 commit comments

Comments
 (0)