Skip to content

Commit 6b99e0c

Browse files
committed
fixup! Improve abs() return type
1 parent cd50c21 commit 6b99e0c

File tree

2 files changed

+51
-29
lines changed

2 files changed

+51
-29
lines changed

src/Type/Php/AbsFunctionDynamicReturnTypeExtension.php

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,49 +38,53 @@ public function getTypeFromFunctionCall(
3838
$type = $scope->getType($args[0]->value);
3939

4040
if ($type instanceof UnionType) {
41-
$ranges = [];
41+
$absUnionTypes = [];
4242

4343
foreach ($type->getTypes() as $unionType) {
44-
if (
45-
!$unionType instanceof ConstantIntegerType
46-
&& !$unionType instanceof IntegerRangeType
47-
&& !$unionType instanceof ConstantFloatType
48-
) {
44+
$absUnionType = $this->tryAbsType($unionType);
45+
46+
if ($absUnionType === null) {
4947
return null;
5048
}
5149

52-
$absRange = $this->absType($unionType);
53-
54-
foreach ($ranges as $index => $range) {
55-
if (!($range instanceof IntegerRangeType)) {
50+
foreach ($absUnionTypes as $index => $otherAbsUnionType) {
51+
if (!($otherAbsUnionType instanceof IntegerRangeType)) {
5652
continue;
5753
}
5854

59-
$unionRange = $range->tryUnion($absRange);
55+
$unionRange = $otherAbsUnionType->tryUnion($absUnionType);
6056

6157
if ($unionRange !== null) {
62-
$ranges[$index] = $unionRange;
58+
$absUnionTypes[$index] = $unionRange;
6359

6460
continue 2;
6561
}
6662
}
6763

68-
$ranges[] = $absRange;
64+
$absUnionTypes[] = $absUnionType;
6965
}
7066

71-
if (count($ranges) === 1) {
72-
return $ranges[0];
67+
if (count($absUnionTypes) === 1) {
68+
return $absUnionTypes[0];
7369
}
7470

75-
return new UnionType($ranges);
71+
return new UnionType($absUnionTypes);
7672
}
7773

74+
return $this->tryAbsType($type);
75+
}
76+
77+
private function tryAbsType(Type $type): ?Type
78+
{
79+
$numberType = $type->toNumber();
80+
7881
if (
79-
$type instanceof ConstantIntegerType
80-
|| $type instanceof IntegerRangeType
81-
|| $type instanceof ConstantFloatType
82+
$numberType instanceof IntegerRangeType
83+
|| $numberType instanceof ConstantIntegerType
84+
|| $numberType instanceof ConstantFloatType
85+
8286
) {
83-
return $this->absType($type);
87+
return $this->absType($numberType);
8488
}
8589

8690
return null;

tests/PHPStan/Analyser/nsrt/abs.php

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -121,19 +121,37 @@ public function constantFloat(float $float): void
121121
assertType('1.0', abs($float));
122122
}
123123

124-
public function mixedUnion(float $float): void
124+
public function string(string $string): void
125125
{
126-
/** @var 1.0|int<2, 3> $float */
127-
assertType('1.0|int<2, 3>', abs($float));
126+
/** @var string $string */
127+
assertType('float|int<0, max>', abs($string));
128128

129-
/** @var -1.0|int<-3, -2> $float */
130-
assertType('1.0|int<2, 3>', abs($float));
129+
/** @var numeric-string $string */
130+
assertType('float|int<0, max>', abs($string));
131131

132-
/** @var 2.0|int<1, 3> $float */
133-
assertType('2.0|int<1, 3>', abs($float));
132+
/** @var '-1' $string */
133+
assertType('1', abs($string));
134134

135-
/** @var -2.0|int<-3, -1> $float */
136-
assertType('2.0|int<1, 3>', abs($float));
135+
/** @var '-1'|'-2.0'|'3.0'|'4' $string */
136+
assertType('1|2.0|3.0|4', abs($string));
137+
}
138+
139+
public function mixedUnion(mixed $value): void
140+
{
141+
/** @var 1.0|int<2, 3> $value */
142+
assertType('1.0|int<2, 3>', abs($value));
143+
144+
/** @var -1.0|int<-3, -2> $value */
145+
assertType('1.0|int<2, 3>', abs($value));
146+
147+
/** @var 2.0|int<1, 3> $value */
148+
assertType('2.0|int<1, 3>', abs($value));
149+
150+
/** @var -2.0|int<-3, -1> $value */
151+
assertType('2.0|int<1, 3>', abs($value));
152+
153+
/** @var -1.0|int<2, 3>|numeric-string $value */
154+
assertType('float|int<0, max>', abs($value));
137155
}
138156

139157
public function invalidType(mixed $nonInt): void

0 commit comments

Comments
 (0)