Skip to content

Commit

Permalink
fixed non-falsy-string inference with '0'
Browse files Browse the repository at this point in the history
  • Loading branch information
staabm committed Aug 30, 2022
1 parent 43dd007 commit 5a52370
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 9 deletions.
13 changes: 11 additions & 2 deletions src/Type/Accessory/AccessoryNonEmptyStringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use PHPStan\Type\CompoundType;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Constant\ConstantIntegerType;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\ErrorType;
use PHPStan\Type\FloatType;
use PHPStan\Type\GeneralizePrecision;
Expand All @@ -16,10 +17,10 @@
use PHPStan\Type\Traits\NonGenericTypeTrait;
use PHPStan\Type\Traits\NonIterableTypeTrait;
use PHPStan\Type\Traits\NonObjectTypeTrait;
use PHPStan\Type\Traits\NonRemoveableTypeTrait;
use PHPStan\Type\Traits\UndecidedBooleanTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
use PHPStan\Type\UnionType;
use PHPStan\Type\VerbosityLevel;

Expand All @@ -31,7 +32,6 @@ class AccessoryNonEmptyStringType implements CompoundType, AccessoryType
use NonIterableTypeTrait;
use UndecidedComparisonCompoundTypeTrait;
use NonGenericTypeTrait;
use NonRemoveableTypeTrait;
use UndecidedBooleanTypeTrait;

/** @api */
Expand Down Expand Up @@ -202,4 +202,13 @@ public static function __set_state(array $properties): Type
return new self();
}

public function tryRemove(Type $typeToRemove): ?Type
{
if ($typeToRemove instanceof ConstantStringType && $typeToRemove->getValue() === '0') {
return TypeCombinator::intersect($this, new AccessoryNonFalsyStringType());
}

return null;
}

}
13 changes: 11 additions & 2 deletions src/Type/Accessory/AccessoryNumericStringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use PHPStan\Type\CompoundType;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Constant\ConstantIntegerType;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\ErrorType;
use PHPStan\Type\FloatType;
use PHPStan\Type\GeneralizePrecision;
Expand All @@ -16,10 +17,10 @@
use PHPStan\Type\Traits\NonGenericTypeTrait;
use PHPStan\Type\Traits\NonIterableTypeTrait;
use PHPStan\Type\Traits\NonObjectTypeTrait;
use PHPStan\Type\Traits\NonRemoveableTypeTrait;
use PHPStan\Type\Traits\UndecidedBooleanTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
use PHPStan\Type\UnionType;
use PHPStan\Type\VerbosityLevel;

Expand All @@ -32,7 +33,6 @@ class AccessoryNumericStringType implements CompoundType, AccessoryType
use UndecidedBooleanTypeTrait;
use UndecidedComparisonCompoundTypeTrait;
use NonGenericTypeTrait;
use NonRemoveableTypeTrait;

/** @api */
public function __construct()
Expand Down Expand Up @@ -205,4 +205,13 @@ public static function __set_state(array $properties): Type
return new self();
}

public function tryRemove(Type $typeToRemove): ?Type
{
if ($typeToRemove instanceof ConstantStringType && $typeToRemove->getValue() === '0') {
return TypeCombinator::intersect($this, new AccessoryNonFalsyStringType());
}

return null;
}

}
5 changes: 1 addition & 4 deletions src/Type/StringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use PHPStan\Reflection\ReflectionProviderStaticAccessor;
use PHPStan\TrinaryLogic;
use PHPStan\Type\Accessory\AccessoryNonEmptyStringType;
use PHPStan\Type\Accessory\AccessoryNonFalsyStringType;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Constant\ConstantIntegerType;
use PHPStan\Type\Constant\ConstantStringType;
Expand Down Expand Up @@ -163,12 +162,10 @@ public function isLiteralString(): TrinaryLogic

public function tryRemove(Type $typeToRemove): ?Type
{
if ($typeToRemove instanceof ConstantStringType && $typeToRemove->getValue() === '0') {
return TypeCombinator::intersect($this, new AccessoryNonFalsyStringType());
}
if ($typeToRemove instanceof ConstantStringType && $typeToRemove->getValue() === '') {
return TypeCombinator::intersect($this, new AccessoryNonEmptyStringType());
}

if ($typeToRemove instanceof AccessoryNonEmptyStringType) {
return new ConstantStringType('');
}
Expand Down
1 change: 1 addition & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1001,6 +1001,7 @@ public function dataFileAsserts(): iterable
yield from $this->gatherAssertTypes(__DIR__ . '/data/composer-array-bug.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/tagged-unions.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-7492.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-7877.php');
}

/**
Expand Down
24 changes: 24 additions & 0 deletions tests/PHPStan/Analyser/data/bug-7877.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php declare(strict_types=1);

namespace Bug7877;

use function PHPStan\Testing\assertType;

function foo(string $s): void
{
if ('' !== $s) {
assertType('non-empty-string', $s);

if ('0' !== $s) {
assertType('non-falsy-string', $s);
}
}

if ('0' !== $s) {
assertType('string', $s);
} else {
assertType("'0'", $s);
}
assertType('string', $s);
}

14 changes: 13 additions & 1 deletion tests/PHPStan/Analyser/data/non-falsy-string.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function removeZero(string $s) {
return;
}

assertType('non-falsy-string', $s);
assertType('string', $s);
}

/**
Expand Down Expand Up @@ -130,4 +130,16 @@ public function doSubstr($nonFalsey, $positiveInt, $postiveRange, $negativeRange

assertType('non-falsy-string', substr($nonFalsey, 0, $positiveInt));
}

function numericIntoFalsy(string $s): void
{
if (is_numeric($s)) {
assertType('numeric-string', $s);

if ('0' !== $s) {
assertType('non-falsy-string&numeric-string', $s);
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -197,4 +197,11 @@ public function testBug2741(): void
]);
}

public function testBug7881(): void
{
$this->treatPhpDocTypesAsCertain = true;

$this->analyse([__DIR__ . '/data/bug-7881.php'], []);
}

}
20 changes: 20 additions & 0 deletions tests/PHPStan/Rules/Comparison/data/bug-7881.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Bug7881;

/**
* @param array<string> $base
*
* @return array<int>
*/
function base_str_to_arr(string $str, &$base): array
{
$arr = [];

while ('0' === $str || strlen($str) !== 0) {
echo 'toto';
}

return $arr;
}

0 comments on commit 5a52370

Please sign in to comment.