Skip to content

Commit

Permalink
Introduce TypeResult
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Oct 18, 2024
1 parent 6ac62d3 commit a815d57
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 24 deletions.
4 changes: 2 additions & 2 deletions src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,7 @@ private function resolveType(string $exprString, Expr $node): Type
$leftType = $this->getType($node->left);
$rightType = $this->getType($node->right);

return $this->initializerExprTypeResolver->resolveEqualType($leftType, $rightType);
return $this->initializerExprTypeResolver->resolveEqualType($leftType, $rightType)->type;
}

if ($node instanceof Expr\BinaryOp\NotEqual) {
Expand Down Expand Up @@ -959,7 +959,7 @@ private function resolveType(string $exprString, Expr $node): Type
return new BooleanType();
}

return $this->initializerExprTypeResolver->resolveIdenticalType($leftType, $rightType);
return $this->initializerExprTypeResolver->resolveIdenticalType($leftType, $rightType)->type;
}

if ($node instanceof Expr\BinaryOp\NotIdentical) {
Expand Down
55 changes: 33 additions & 22 deletions src/Reflection/InitializerExprTypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
use PHPStan\Type\TypehintHelper;
use PHPStan\Type\TypeResult;
use PHPStan\Type\TypeTraverser;
use PHPStan\Type\TypeUtils;
use PHPStan\Type\TypeWithClassName;
Expand Down Expand Up @@ -298,7 +299,7 @@ public function getType(Expr $expr, InitializerExprContext $context): Type
return $this->resolveIdenticalType(
$this->getType($expr->left, $context),
$this->getType($expr->right, $context),
);
)->type;
}

if ($expr instanceof BinaryOp\NotIdentical) {
Expand All @@ -309,7 +310,7 @@ public function getType(Expr $expr, InitializerExprContext $context): Type
return $this->resolveEqualType(
$this->getType($expr->left, $context),
$this->getType($expr->right, $context),
);
)->type;
}

if ($expr instanceof BinaryOp\NotEqual) {
Expand Down Expand Up @@ -1349,34 +1350,42 @@ public function getShiftRightType(Expr $left, Expr $right, callable $getTypeCall
return $this->resolveCommonMath(new Expr\BinaryOp\ShiftRight($left, $right), $leftType, $rightType);
}

public function resolveIdenticalType(Type $leftType, Type $rightType): BooleanType
/**
* @return TypeResult<BooleanType>
*/
public function resolveIdenticalType(Type $leftType, Type $rightType): TypeResult
{
if ($leftType instanceof NeverType || $rightType instanceof NeverType) {
return new ConstantBooleanType(false);
return new TypeResult(new ConstantBooleanType(false), []);
}

if ($leftType instanceof ConstantScalarType && $rightType instanceof ConstantScalarType) {
return new ConstantBooleanType($leftType->getValue() === $rightType->getValue());
return new TypeResult(new ConstantBooleanType($leftType->getValue() === $rightType->getValue()), []);
}

$leftTypeFiniteTypes = $leftType->getFiniteTypes();
$rightTypeFiniteType = $rightType->getFiniteTypes();
if (count($leftTypeFiniteTypes) === 1 && count($rightTypeFiniteType) === 1) {
return new ConstantBooleanType($leftTypeFiniteTypes[0]->equals($rightTypeFiniteType[0]));
return new TypeResult(new ConstantBooleanType($leftTypeFiniteTypes[0]->equals($rightTypeFiniteType[0])), []);
}

if ($leftType->isSuperTypeOf($rightType)->no() && $rightType->isSuperTypeOf($leftType)->no()) {
return new ConstantBooleanType(false);
$leftIsSuperTypeOfRight = $leftType->isSuperTypeOfWithReason($rightType);
$rightIsSuperTypeOfLeft = $rightType->isSuperTypeOfWithReason($leftType);
if ($leftIsSuperTypeOfRight->no() && $rightIsSuperTypeOfLeft->no()) {
return new TypeResult(new ConstantBooleanType(false), array_merge($leftIsSuperTypeOfRight->reasons, $rightIsSuperTypeOfLeft->reasons));
}

if ($leftType instanceof ConstantArrayType && $rightType instanceof ConstantArrayType) {
return $this->resolveConstantArrayTypeComparison($leftType, $rightType, fn ($leftValueType, $rightValueType): BooleanType => $this->resolveIdenticalType($leftValueType, $rightValueType));
return $this->resolveConstantArrayTypeComparison($leftType, $rightType, fn ($leftValueType, $rightValueType): TypeResult => $this->resolveIdenticalType($leftValueType, $rightValueType));
}

return new BooleanType();
return new TypeResult(new BooleanType(), []);
}

public function resolveEqualType(Type $leftType, Type $rightType): BooleanType
/**
* @return TypeResult<BooleanType>
*/
public function resolveEqualType(Type $leftType, Type $rightType): TypeResult
{
if (
($leftType->isEnum()->yes() && $rightType->isTrue()->no())
Expand All @@ -1386,16 +1395,17 @@ public function resolveEqualType(Type $leftType, Type $rightType): BooleanType
}

if ($leftType instanceof ConstantArrayType && $rightType instanceof ConstantArrayType) {
return $this->resolveConstantArrayTypeComparison($leftType, $rightType, fn ($leftValueType, $rightValueType): BooleanType => $this->resolveEqualType($leftValueType, $rightValueType));
return $this->resolveConstantArrayTypeComparison($leftType, $rightType, fn ($leftValueType, $rightValueType): TypeResult => $this->resolveEqualType($leftValueType, $rightValueType));
}

return $leftType->looseCompare($rightType, $this->phpVersion);
return new TypeResult($leftType->looseCompare($rightType, $this->phpVersion), []);
}

/**
* @param callable(Type, Type): BooleanType $valueComparisonCallback
* @param callable(Type, Type): TypeResult<BooleanType> $valueComparisonCallback
* @return TypeResult<BooleanType>
*/
private function resolveConstantArrayTypeComparison(ConstantArrayType $leftType, ConstantArrayType $rightType, callable $valueComparisonCallback): BooleanType
private function resolveConstantArrayTypeComparison(ConstantArrayType $leftType, ConstantArrayType $rightType, callable $valueComparisonCallback): TypeResult
{
$leftKeyTypes = $leftType->getKeyTypes();
$rightKeyTypes = $rightType->getKeyTypes();
Expand All @@ -1412,7 +1422,7 @@ private function resolveConstantArrayTypeComparison(ConstantArrayType $leftType,

if (count($rightKeyTypes) === 0) {
if (!$leftOptional) {
return new ConstantBooleanType(false);
return new TypeResult(new ConstantBooleanType(false), []);
}
continue;
}
Expand All @@ -1425,13 +1435,13 @@ private function resolveConstantArrayTypeComparison(ConstantArrayType $leftType,
$found = true;
break;
} elseif (!$rightType->isOptionalKey($j)) {
return new ConstantBooleanType(false);
return new TypeResult(new ConstantBooleanType(false), []);
}
}

if (!$found) {
if (!$leftOptional) {
return new ConstantBooleanType(false);
return new TypeResult(new ConstantBooleanType(false), []);
}
continue;
}
Expand All @@ -1448,21 +1458,22 @@ private function resolveConstantArrayTypeComparison(ConstantArrayType $leftType,
}
}

$leftIdenticalToRight = $valueComparisonCallback($leftValueTypes[$i], $rightValueTypes[$j]);
$leftIdenticalToRightResult = $valueComparisonCallback($leftValueTypes[$i], $rightValueTypes[$j]);
$leftIdenticalToRight = $leftIdenticalToRightResult->type;
if ($leftIdenticalToRight->isFalse()->yes()) {
return new ConstantBooleanType(false);
return $leftIdenticalToRightResult;
}
$resultType = TypeCombinator::union($resultType, $leftIdenticalToRight);
}

foreach (array_keys($rightKeyTypes) as $j) {
if (!$rightType->isOptionalKey($j)) {
return new ConstantBooleanType(false);
return new TypeResult(new ConstantBooleanType(false), []);
}
$resultType = new BooleanType();
}

return $resultType->toBoolean();
return new TypeResult($resultType->toBoolean(), []);
}

private function callOperatorTypeSpecifyingExtensions(Expr\BinaryOp $expr, Type $leftType, Type $rightType): ?Type
Expand Down
22 changes: 22 additions & 0 deletions src/Type/TypeResult.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php declare(strict_types = 1);

namespace PHPStan\Type;

/**
* @template-covariant T of Type
*/
final class TypeResult
{

/**
* @param T $type
* @param list<string> $reasons
*/
public function __construct(
public readonly Type $type,
public readonly array $reasons,
)
{
}

}

0 comments on commit a815d57

Please sign in to comment.