Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve comparison operators and fix IntegerRangeType overflowing #372

Merged
merged 3 commits into from
Nov 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
48 changes: 11 additions & 37 deletions src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -524,46 +524,20 @@ private function resolveType(Expr $node): Type
return new NeverType(true);
}

if (
$node instanceof Expr\BinaryOp\Greater
|| $node instanceof Expr\BinaryOp\GreaterOrEqual
|| $node instanceof Expr\BinaryOp\Smaller
|| $node instanceof Expr\BinaryOp\SmallerOrEqual
) {
$leftType = $this->getType($node->left);
$rightType = $this->getType($node->right);

if ($rightType instanceof ConstantIntegerType) {
$rightValue = $rightType->getValue();

if ($node instanceof Expr\BinaryOp\Greater) {
$rightIntervalType = IntegerRangeType::fromInterval($rightValue + 1, null);
} elseif ($node instanceof Expr\BinaryOp\GreaterOrEqual) {
$rightIntervalType = IntegerRangeType::fromInterval($rightValue, null);
} elseif ($node instanceof Expr\BinaryOp\Smaller) {
$rightIntervalType = IntegerRangeType::fromInterval(null, $rightValue - 1);
} else {
$rightIntervalType = IntegerRangeType::fromInterval(null, $rightValue);
}

return $rightIntervalType->isSuperTypeOf($leftType->toInteger())->toBooleanType();
} elseif ($leftType instanceof ConstantIntegerType) {
$leftValue = $leftType->getValue();
if ($node instanceof Expr\BinaryOp\Smaller) {
return $this->getType($node->left)->isSmallerThan($this->getType($node->right))->toBooleanType();
}

if ($node instanceof Expr\BinaryOp\Smaller) {
$leftIntervalType = IntegerRangeType::fromInterval($leftValue + 1, null);
} elseif ($node instanceof Expr\BinaryOp\SmallerOrEqual) {
$leftIntervalType = IntegerRangeType::fromInterval($leftValue, null);
} elseif ($node instanceof Expr\BinaryOp\Greater) {
$leftIntervalType = IntegerRangeType::fromInterval(null, $leftValue - 1);
} else {
$leftIntervalType = IntegerRangeType::fromInterval(null, $leftValue);
}
if ($node instanceof Expr\BinaryOp\SmallerOrEqual) {
return $this->getType($node->left)->isSmallerThan($this->getType($node->right), true)->toBooleanType();
}

return $leftIntervalType->isSuperTypeOf($rightType->toInteger())->toBooleanType();
}
if ($node instanceof Expr\BinaryOp\Greater) {
return $this->getType($node->right)->isSmallerThan($this->getType($node->left))->toBooleanType();
}

return new BooleanType();
if ($node instanceof Expr\BinaryOp\GreaterOrEqual) {
return $this->getType($node->right)->isSmallerThan($this->getType($node->left), true)->toBooleanType();
}

if (
Expand Down
30 changes: 21 additions & 9 deletions src/Analyser/TypeSpecifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -398,23 +398,29 @@ public function specifyTypesInCondition(
}

if ($leftType instanceof ConstantIntegerType) {
if ($expr->right instanceof Expr\PostDec) {
if ($expr->right instanceof Expr\PostInc) {
$result = $result->unionWith($this->createRangeTypes(
$expr->right->var,
IntegerRangeType::fromInterval($leftType->getValue() + $offset - 1, null),
IntegerRangeType::fromInterval($leftType->getValue(), null, $offset + 1),
$context
));
} elseif ($expr->right instanceof Expr\PreDec) {
} elseif ($expr->right instanceof Expr\PostDec) {
$result = $result->unionWith($this->createRangeTypes(
$expr->right->var,
IntegerRangeType::fromInterval($leftType->getValue() + $offset, null),
IntegerRangeType::fromInterval($leftType->getValue(), null, $offset - 1),
$context
));
} elseif ($expr->right instanceof Expr\PreInc || $expr->right instanceof Expr\PreDec) {
$result = $result->unionWith($this->createRangeTypes(
$expr->right->var,
IntegerRangeType::fromInterval($leftType->getValue(), null, $offset),
$context
));
}

$result = $result->unionWith($this->createRangeTypes(
$expr->right,
IntegerRangeType::fromInterval($leftType->getValue() + $offset, null),
IntegerRangeType::fromInterval($leftType->getValue(), null, $offset),
$context
));
}
Expand All @@ -423,20 +429,26 @@ public function specifyTypesInCondition(
if ($expr->left instanceof Expr\PostInc) {
$result = $result->unionWith($this->createRangeTypes(
$expr->left->var,
IntegerRangeType::fromInterval(null, $rightType->getValue() - $offset + 1),
IntegerRangeType::fromInterval(null, $rightType->getValue(), -$offset + 1),
$context
));
} elseif ($expr->left instanceof Expr\PostDec) {
$result = $result->unionWith($this->createRangeTypes(
$expr->left->var,
IntegerRangeType::fromInterval(null, $rightType->getValue(), -$offset - 1),
$context
));
} elseif ($expr->left instanceof Expr\PreInc) {
} elseif ($expr->left instanceof Expr\PreInc || $expr->left instanceof Expr\PreDec) {
$result = $result->unionWith($this->createRangeTypes(
$expr->left->var,
IntegerRangeType::fromInterval(null, $rightType->getValue() - $offset),
IntegerRangeType::fromInterval(null, $rightType->getValue(), -$offset),
$context
));
}

$result = $result->unionWith($this->createRangeTypes(
$expr->left,
IntegerRangeType::fromInterval(null, $rightType->getValue() - $offset),
IntegerRangeType::fromInterval(null, $rightType->getValue(), -$offset),
$context
));
}
Expand Down
2 changes: 2 additions & 0 deletions src/Type/Accessory/AccessoryNumericStringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use PHPStan\Type\Traits\NonIterableTypeTrait;
use PHPStan\Type\Traits\NonObjectTypeTrait;
use PHPStan\Type\Traits\UndecidedBooleanTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;

Expand All @@ -27,6 +28,7 @@ class AccessoryNumericStringType implements CompoundType, AccessoryType
use NonObjectTypeTrait;
use NonIterableTypeTrait;
use UndecidedBooleanTypeTrait;
use UndecidedComparisonCompoundTypeTrait;
use NonGenericTypeTrait;

public function getReferencedClasses(): array
Expand Down
2 changes: 2 additions & 0 deletions src/Type/Accessory/HasMethodType.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use PHPStan\Type\IntersectionType;
use PHPStan\Type\Traits\NonGenericTypeTrait;
use PHPStan\Type\Traits\ObjectTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;

Expand All @@ -19,6 +20,7 @@ class HasMethodType implements AccessoryType, CompoundType

use ObjectTypeTrait;
use NonGenericTypeTrait;
use UndecidedComparisonCompoundTypeTrait;

private string $methodName;

Expand Down
2 changes: 2 additions & 0 deletions src/Type/Accessory/HasOffsetType.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use PHPStan\Type\Traits\MaybeObjectTypeTrait;
use PHPStan\Type\Traits\NonGenericTypeTrait;
use PHPStan\Type\Traits\TruthyBooleanTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;

Expand All @@ -25,6 +26,7 @@ class HasOffsetType implements CompoundType, AccessoryType
use MaybeObjectTypeTrait;
use TruthyBooleanTypeTrait;
use NonGenericTypeTrait;
use UndecidedComparisonCompoundTypeTrait;

private \PHPStan\Type\Type $offsetType;

Expand Down
2 changes: 2 additions & 0 deletions src/Type/Accessory/HasPropertyType.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use PHPStan\Type\IntersectionType;
use PHPStan\Type\Traits\NonGenericTypeTrait;
use PHPStan\Type\Traits\ObjectTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;

Expand All @@ -17,6 +18,7 @@ class HasPropertyType implements AccessoryType, CompoundType

use ObjectTypeTrait;
use NonGenericTypeTrait;
use UndecidedComparisonCompoundTypeTrait;

private string $propertyName;

Expand Down
2 changes: 2 additions & 0 deletions src/Type/Accessory/NonEmptyArrayType.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use PHPStan\Type\Traits\NonGenericTypeTrait;
use PHPStan\Type\Traits\NonObjectTypeTrait;
use PHPStan\Type\Traits\TruthyBooleanTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;

Expand All @@ -22,6 +23,7 @@ class NonEmptyArrayType implements CompoundType, AccessoryType
use NonObjectTypeTrait;
use TruthyBooleanTypeTrait;
use NonGenericTypeTrait;
use UndecidedComparisonCompoundTypeTrait;

public function getReferencedClasses(): array
{
Expand Down
2 changes: 2 additions & 0 deletions src/Type/ArrayType.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
use PHPStan\Type\Traits\MaybeCallableTypeTrait;
use PHPStan\Type\Traits\NonObjectTypeTrait;
use PHPStan\Type\Traits\UndecidedBooleanTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonTypeTrait;

class ArrayType implements Type
{

use MaybeCallableTypeTrait;
use NonObjectTypeTrait;
use UndecidedBooleanTypeTrait;
use UndecidedComparisonTypeTrait;

private \PHPStan\Type\Type $keyType;

Expand Down
2 changes: 2 additions & 0 deletions src/Type/BooleanType.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use PHPStan\Type\Traits\NonIterableTypeTrait;
use PHPStan\Type\Traits\NonObjectTypeTrait;
use PHPStan\Type\Traits\UndecidedBooleanTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonTypeTrait;

class BooleanType implements Type
{
Expand All @@ -21,6 +22,7 @@ class BooleanType implements Type
use NonIterableTypeTrait;
use NonObjectTypeTrait;
use UndecidedBooleanTypeTrait;
use UndecidedComparisonTypeTrait;
use NonGenericTypeTrait;

public function describe(VerbosityLevel $level): string
Expand Down
2 changes: 2 additions & 0 deletions src/Type/CallableType.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use PHPStan\Type\Traits\MaybeObjectTypeTrait;
use PHPStan\Type\Traits\MaybeOffsetAccessibleTypeTrait;
use PHPStan\Type\Traits\TruthyBooleanTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;

class CallableType implements CompoundType, ParametersAcceptor
{
Expand All @@ -21,6 +22,7 @@ class CallableType implements CompoundType, ParametersAcceptor
use MaybeObjectTypeTrait;
use MaybeOffsetAccessibleTypeTrait;
use TruthyBooleanTypeTrait;
use UndecidedComparisonCompoundTypeTrait;

/** @var array<int, \PHPStan\Reflection\ParameterReflection> */
private array $parameters;
Expand Down
2 changes: 2 additions & 0 deletions src/Type/ClosureType.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@
use PHPStan\Type\Constant\ConstantIntegerType;
use PHPStan\Type\Generic\TemplateTypeMap;
use PHPStan\Type\Traits\NonGenericTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonTypeTrait;

class ClosureType implements TypeWithClassName, ParametersAcceptor
{

use NonGenericTypeTrait;
use UndecidedComparisonTypeTrait;

private ObjectType $objectType;

Expand Down
2 changes: 2 additions & 0 deletions src/Type/CompoundType.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ public function isSubTypeOf(Type $otherType): TrinaryLogic;

public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic;

public function isGreaterThan(Type $otherType, bool $orEqual = false): TrinaryLogic;

}
2 changes: 2 additions & 0 deletions src/Type/FloatType.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use PHPStan\Type\Traits\NonIterableTypeTrait;
use PHPStan\Type\Traits\NonObjectTypeTrait;
use PHPStan\Type\Traits\UndecidedBooleanTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonTypeTrait;

class FloatType implements Type
{
Expand All @@ -19,6 +20,7 @@ class FloatType implements Type
use NonIterableTypeTrait;
use NonObjectTypeTrait;
use UndecidedBooleanTypeTrait;
use UndecidedComparisonTypeTrait;
use NonGenericTypeTrait;

/**
Expand Down
3 changes: 3 additions & 0 deletions src/Type/Generic/TemplateObjectType.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PHPStan\Type\IntersectionType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\ObjectWithoutClassType;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;
use PHPStan\Type\TypeUtils;
use PHPStan\Type\UnionType;
Expand All @@ -15,6 +16,8 @@
final class TemplateObjectType extends ObjectType implements TemplateType
{

use UndecidedComparisonCompoundTypeTrait;

private TemplateTypeScope $scope;

private string $name;
Expand Down
3 changes: 3 additions & 0 deletions src/Type/Generic/TemplateObjectWithoutClassType.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use PHPStan\Type\CompoundType;
use PHPStan\Type\IntersectionType;
use PHPStan\Type\ObjectWithoutClassType;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;
use PHPStan\Type\TypeUtils;
use PHPStan\Type\UnionType;
Expand All @@ -14,6 +15,8 @@
class TemplateObjectWithoutClassType extends ObjectWithoutClassType implements TemplateType
{

use UndecidedComparisonCompoundTypeTrait;

private TemplateTypeScope $scope;

private string $name;
Expand Down