Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 0 additions & 18 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -435,24 +435,6 @@ parameters:
count: 1
path: src/Reflection/InitializerExprTypeResolver.php

-
rawMessage: Binary operation "*" between bool|float|int|string|null and bool|float|int|string|null results in an error.
identifier: binaryOp.invalid
count: 1
path: src/Reflection/InitializerExprTypeResolver.php

-
rawMessage: Binary operation "+" between bool|float|int|string|null and bool|float|int|string|null results in an error.
identifier: binaryOp.invalid
count: 1
path: src/Reflection/InitializerExprTypeResolver.php

-
rawMessage: Binary operation "-" between bool|float|int|string|null and bool|float|int|string|null results in an error.
identifier: binaryOp.invalid
count: 1
path: src/Reflection/InitializerExprTypeResolver.php

-
rawMessage: Binary operation "^" between bool|float|int|string|null and bool|float|int|string|null results in an error.
identifier: binaryOp.invalid
Expand Down
42 changes: 41 additions & 1 deletion src/Reflection/InitializerExprTypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -1288,7 +1288,7 @@
return new ErrorType();
}

$resultType = $this->getTypeFromValue($leftNumberType->getValue() / $rightNumberType->getValue()); // @phpstan-ignore binaryOp.invalid
$resultType = $this->getTypeFromValue($leftNumberType->getValue() / $rightNumberType->getValue());
$resultTypes[] = $resultType;
}
}
Expand Down Expand Up @@ -2119,6 +2119,13 @@
return new ErrorType();
}

if ($leftNumberType instanceof ErrorType) {
$leftNumberType = $this->filterNumberTypeFromUnion($leftType) ?? $leftNumberType;
}
if ($rightNumberType instanceof ErrorType) {
$rightNumberType = $this->filterNumberTypeFromUnion($rightType) ?? $rightNumberType;
}

if ($leftNumberType instanceof ErrorType || $rightNumberType instanceof ErrorType) {
return new ErrorType();
}
Expand Down Expand Up @@ -2155,6 +2162,39 @@
return $resultType;
}

/**
* When toNumber() on a union returns ErrorType because some members (strings)
* can't be proven numeric, try to extract the numeric parts.
* Only skips ErrorType from string members, since string-to-number conversion
* always produces a result in PHP (with possible deprecation warning).
*/
private function filterNumberTypeFromUnion(Type $type): ?Type
{
if (!$type instanceof UnionType) {
return null;
}

$numberTypes = [];
$hasSkipped = false;
foreach ($type->getTypes() as $memberType) {
$numberType = $memberType->toNumber();
if ($numberType instanceof ErrorType) {
if ($memberType->isString()->yes()) {

Check warning on line 2182 in src/Reflection/InitializerExprTypeResolver.php

View workflow job for this annotation

GitHub Actions / Mutation Testing (8.4, ubuntu-latest)

Escaped Mutant for Mutator "PHPStan\Infection\TrinaryLogicMutator": @@ @@ foreach ($type->getTypes() as $memberType) { $numberType = $memberType->toNumber(); if ($numberType instanceof ErrorType) { - if ($memberType->isString()->yes()) { + if (!$memberType->isString()->no()) { $hasSkipped = true; continue; }

Check warning on line 2182 in src/Reflection/InitializerExprTypeResolver.php

View workflow job for this annotation

GitHub Actions / Mutation Testing (8.3, ubuntu-latest)

Escaped Mutant for Mutator "PHPStan\Infection\TrinaryLogicMutator": @@ @@ foreach ($type->getTypes() as $memberType) { $numberType = $memberType->toNumber(); if ($numberType instanceof ErrorType) { - if ($memberType->isString()->yes()) { + if (!$memberType->isString()->no()) { $hasSkipped = true; continue; }
$hasSkipped = true;
continue;
}
return null;
}
$numberTypes[] = $numberType;
}

if ($numberTypes === [] || !$hasSkipped) {
return null;
}

return TypeCombinator::union(...$numberTypes);
}

/**
* @param ConstantIntegerType|IntegerRangeType $range
* @param BinaryOp\Div|BinaryOp\Minus|BinaryOp\Mul|BinaryOp\Plus|BinaryOp\ShiftLeft|BinaryOp\ShiftRight $node
Expand Down
36 changes: 36 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-11129b.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php declare(strict_types = 1);

namespace Bug11129b;

use function PHPStan\Testing\assertType;

class HelloWorld
{
/** @param array<string> $array */
public function sayHello(array $array): void
{
$pos = 0;
foreach ($array as $element) {
++$pos;

if ($pos < 10) {
$pos = '0' . $pos;
}
}
assertType('0|float|(non-falsy-string&uppercase-string)', $pos);
}

/** @param array<string> $array */
public function withPlusOne(array $array): void
{
$pos = 0;
foreach ($array as $element) {
$pos = $pos + 1;

if ($pos < 10) {
$pos = '0' . $pos;
}
}
assertType('0|float|(non-falsy-string&uppercase-string)', $pos);
}
}
Loading