Skip to content

Commit f6289bd

Browse files
committed
WIP Attempt to fix zero
1 parent 3ec1bd6 commit f6289bd

File tree

3 files changed

+61
-4
lines changed

3 files changed

+61
-4
lines changed

src/Analyser/TypeSpecifier.php

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,7 +1611,7 @@ private function processBooleanNotSureConditionalTypes(Scope $scope, SpecifiedTy
16111611
}
16121612

16131613
/**
1614-
* @return array{Expr, ConstantScalarType}|null
1614+
* @return array{Expr, ConstantScalarType, Type}|null
16151615
*/
16161616
private function findTypeExpressionsFromBinaryOperation(Scope $scope, Node\Expr\BinaryOp $binaryOperation): ?array
16171617
{
@@ -1633,13 +1633,13 @@ private function findTypeExpressionsFromBinaryOperation(Scope $scope, Node\Expr\
16331633
&& !$rightExpr instanceof ConstFetch
16341634
&& !$rightExpr instanceof ClassConstFetch
16351635
) {
1636-
return [$binaryOperation->right, $leftType];
1636+
return [$binaryOperation->right, $leftType, $rightType];
16371637
} elseif (
16381638
$rightType instanceof ConstantScalarType
16391639
&& !$leftExpr instanceof ConstFetch
16401640
&& !$leftExpr instanceof ClassConstFetch
16411641
) {
1642-
return [$binaryOperation->left, $rightType];
1642+
return [$binaryOperation->left, $rightType, $leftType];
16431643
}
16441644

16451645
return null;
@@ -1950,6 +1950,7 @@ public function resolveEqual(Expr\BinaryOp\Equal $expr, Scope $scope, TypeSpecif
19501950
if ($expressions !== null) {
19511951
$exprNode = $expressions[0];
19521952
$constantType = $expressions[1];
1953+
$otherType = $expressions[2];
19531954

19541955
if (!$context->null() && $constantType->getValue() === null) {
19551956
$trueTypes = [
@@ -1981,6 +1982,30 @@ public function resolveEqual(Expr\BinaryOp\Equal $expr, Scope $scope, TypeSpecif
19811982
);
19821983
}
19831984

1985+
if (!$context->null() && $constantType->getValue() === 0 && !$otherType->isInteger()->yes()) {
1986+
/* There is a difference between php 7.x and 8.x on the equality
1987+
* behavior between zero and the empty string, so to be conservative
1988+
* we leave it untouched regardless of the language version */
1989+
if ($context->true()) {
1990+
$trueTypes = [
1991+
new NullType(),
1992+
new ConstantBooleanType(false),
1993+
new ConstantIntegerType(0),
1994+
new ConstantFloatType(0.0),
1995+
new StringType(),
1996+
];
1997+
} else {
1998+
$trueTypes = [
1999+
new NullType(),
2000+
new ConstantBooleanType(false),
2001+
new ConstantIntegerType(0),
2002+
new ConstantFloatType(0.0),
2003+
new ConstantStringType('0'),
2004+
];
2005+
}
2006+
return $this->create($exprNode, new UnionType($trueTypes), $context, false, $scope, $rootExpr);
2007+
}
2008+
19842009
if (!$context->null() && $constantType->getValue() === '') {
19852010
/* There is a difference between php 7.x and 8.x on the equality
19862011
* behavior between zero and the empty string, so to be conservative

tests/PHPStan/Analyser/nsrt/equal-narrow.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,38 @@ function doTrue($x, $y, $z): void
115115
}
116116
}
117117

118+
/**
119+
* @param 0|0.0|1|''|'0'|'x'|array{}|bool|object|null $x
120+
* @param int|string|null $y
121+
* @param mixed $z
122+
*/
123+
function doZero($x, $y, $z): void
124+
{
125+
// PHP 7.x/8.x compatibility: Keep zero in both cases
126+
if ($x == 0) {
127+
assertType("0|0.0|''|'0'|'x'|false|null", $x);
128+
} else {
129+
assertType("1|''|'x'|array{}|object|true", $x);
130+
}
131+
if (0 != $x) {
132+
assertType("1|''|'x'|array{}|object|true", $x);
133+
} else {
134+
assertType("0|0.0|''|'0'|'x'|false|null", $x);
135+
}
136+
137+
if ($y == 0) {
138+
assertType("0|string|null", $y);
139+
} else {
140+
assertType("int<min, -1>|int<1, max>|string", $y);
141+
}
142+
143+
if ($z == 0) {
144+
assertType("0|0.0|string|false|null", $z);
145+
} else {
146+
assertType("mixed~(0|0.0|'0'|false|null)", $z);
147+
}
148+
}
149+
118150
/**
119151
* @param 0|0.0|1|''|'0'|'x'|array{}|bool|object|null $x
120152
* @param int|string|null $y

tests/PHPStan/Analyser/nsrt/integer-range-types.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ public function zeroIssues($positive, $negative)
449449

450450
function subtract($m) {
451451
if ($m != 0) {
452-
assertType("mixed", $m); // could be "mixed~0|0.0|''|'0'|array{}|false|null"
452+
assertType("mixed~(0|0.0|'0'|false|null)", $m); // could be "mixed~(0|0.0|''|'0'|false|null)"
453453
assertType('int', (int) $m);
454454
}
455455
if ($m !== 0) {

0 commit comments

Comments
 (0)