Skip to content

Commit 00c47b2

Browse files
committed
TypeSpecifier - extract resolveEqual
1 parent c880f8e commit 00c47b2

File tree

1 file changed

+118
-113
lines changed

1 file changed

+118
-113
lines changed

src/Analyser/TypeSpecifier.php

Lines changed: 118 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -194,119 +194,7 @@ public function specifyTypesInCondition(
194194
$rootExpr,
195195
);
196196
} elseif ($expr instanceof Node\Expr\BinaryOp\Equal) {
197-
$expressions = $this->findTypeExpressionsFromBinaryOperation($scope, $expr);
198-
if ($expressions !== null) {
199-
$exprNode = $expressions[0];
200-
$constantType = $expressions[1];
201-
if (!$context->null() && ($constantType->getValue() === false || $constantType->getValue() === null)) {
202-
return $this->specifyTypesInCondition(
203-
$scope,
204-
$exprNode,
205-
$context->true() ? TypeSpecifierContext::createFalsey() : TypeSpecifierContext::createFalsey()->negate(),
206-
$rootExpr,
207-
);
208-
}
209-
210-
if (!$context->null() && $constantType->getValue() === true) {
211-
return $this->specifyTypesInCondition(
212-
$scope,
213-
$exprNode,
214-
$context->true() ? TypeSpecifierContext::createTruthy() : TypeSpecifierContext::createTruthy()->negate(),
215-
$rootExpr,
216-
);
217-
}
218-
219-
if (
220-
$exprNode instanceof FuncCall
221-
&& $exprNode->name instanceof Name
222-
&& strtolower($exprNode->name->toString()) === 'gettype'
223-
&& isset($exprNode->getArgs()[0])
224-
&& $constantType->isString()->yes()
225-
) {
226-
return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\Identical($expr->left, $expr->right), $context, $rootExpr);
227-
}
228-
229-
if (
230-
$exprNode instanceof FuncCall
231-
&& $exprNode->name instanceof Name
232-
&& strtolower($exprNode->name->toString()) === 'get_class'
233-
&& isset($exprNode->getArgs()[0])
234-
&& $constantType->isString()->yes()
235-
) {
236-
return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\Identical($expr->left, $expr->right), $context, $rootExpr);
237-
}
238-
}
239-
240-
$leftType = $scope->getType($expr->left);
241-
$rightType = $scope->getType($expr->right);
242-
243-
$leftBooleanType = $leftType->toBoolean();
244-
if ($leftBooleanType instanceof ConstantBooleanType && $rightType->isBoolean()->yes()) {
245-
return $this->specifyTypesInCondition(
246-
$scope,
247-
new Expr\BinaryOp\Identical(
248-
new ConstFetch(new Name($leftBooleanType->getValue() ? 'true' : 'false')),
249-
$expr->right,
250-
),
251-
$context,
252-
$rootExpr,
253-
);
254-
}
255-
256-
$rightBooleanType = $rightType->toBoolean();
257-
if ($rightBooleanType instanceof ConstantBooleanType && $leftType->isBoolean()->yes()) {
258-
return $this->specifyTypesInCondition(
259-
$scope,
260-
new Expr\BinaryOp\Identical(
261-
$expr->left,
262-
new ConstFetch(new Name($rightBooleanType->getValue() ? 'true' : 'false')),
263-
),
264-
$context,
265-
$rootExpr,
266-
);
267-
}
268-
269-
if (
270-
!$context->null()
271-
&& $rightType->isArray()->yes()
272-
&& $leftType->isConstantArray()->yes() && $leftType->isIterableAtLeastOnce()->no()
273-
) {
274-
return $this->create($expr->right, new NonEmptyArrayType(), $context->negate(), false, $scope, $rootExpr);
275-
}
276-
277-
if (
278-
!$context->null()
279-
&& $leftType->isArray()->yes()
280-
&& $rightType->isConstantArray()->yes() && $rightType->isIterableAtLeastOnce()->no()
281-
) {
282-
return $this->create($expr->left, new NonEmptyArrayType(), $context->negate(), false, $scope, $rootExpr);
283-
}
284-
285-
$integerType = new IntegerType();
286-
$floatType = new FloatType();
287-
if (
288-
($leftType->isString()->yes() && $rightType->isString()->yes())
289-
|| ($integerType->isSuperTypeOf($leftType)->yes() && $integerType->isSuperTypeOf($rightType)->yes())
290-
|| ($floatType->isSuperTypeOf($leftType)->yes() && $floatType->isSuperTypeOf($rightType)->yes())
291-
|| ($leftType->isEnum()->yes() && $rightType->isEnum()->yes())
292-
) {
293-
return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\Identical($expr->left, $expr->right), $context, $rootExpr);
294-
}
295-
296-
$leftExprString = $this->exprPrinter->printExpr($expr->left);
297-
$rightExprString = $this->exprPrinter->printExpr($expr->right);
298-
if ($leftExprString === $rightExprString) {
299-
if (!$expr->left instanceof Expr\Variable || !$expr->right instanceof Expr\Variable) {
300-
return new SpecifiedTypes([], [], false, [], $rootExpr);
301-
}
302-
}
303-
304-
$leftTypes = $this->create($expr->left, $leftType, $context, false, $scope, $rootExpr);
305-
$rightTypes = $this->create($expr->right, $rightType, $context, false, $scope, $rootExpr);
306-
307-
return $context->true()
308-
? $leftTypes->unionWith($rightTypes)
309-
: $leftTypes->normalize($scope)->intersectWith($rightTypes->normalize($scope));
197+
return $this->resolveEqual($expr, $scope, $context, $rootExpr);
310198
} elseif ($expr instanceof Node\Expr\BinaryOp\NotEqual) {
311199
return $this->specifyTypesInCondition(
312200
$scope,
@@ -1668,6 +1556,123 @@ private function getTypeSpecifyingExtensionsForType(array $extensions, string $c
16681556
return array_merge(...$extensionsForClass);
16691557
}
16701558

1559+
public function resolveEqual(Expr\BinaryOp\Equal $expr, Scope $scope, TypeSpecifierContext $context, Expr $rootExpr): SpecifiedTypes
1560+
{
1561+
$expressions = $this->findTypeExpressionsFromBinaryOperation($scope, $expr);
1562+
if ($expressions !== null) {
1563+
$exprNode = $expressions[0];
1564+
$constantType = $expressions[1];
1565+
if (!$context->null() && ($constantType->getValue() === false || $constantType->getValue() === null)) {
1566+
return $this->specifyTypesInCondition(
1567+
$scope,
1568+
$exprNode,
1569+
$context->true() ? TypeSpecifierContext::createFalsey() : TypeSpecifierContext::createFalsey()->negate(),
1570+
$rootExpr,
1571+
);
1572+
}
1573+
1574+
if (!$context->null() && $constantType->getValue() === true) {
1575+
return $this->specifyTypesInCondition(
1576+
$scope,
1577+
$exprNode,
1578+
$context->true() ? TypeSpecifierContext::createTruthy() : TypeSpecifierContext::createTruthy()->negate(),
1579+
$rootExpr,
1580+
);
1581+
}
1582+
1583+
if (
1584+
$exprNode instanceof FuncCall
1585+
&& $exprNode->name instanceof Name
1586+
&& strtolower($exprNode->name->toString()) === 'gettype'
1587+
&& isset($exprNode->getArgs()[0])
1588+
&& $constantType->isString()->yes()
1589+
) {
1590+
return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\Identical($expr->left, $expr->right), $context, $rootExpr);
1591+
}
1592+
1593+
if (
1594+
$exprNode instanceof FuncCall
1595+
&& $exprNode->name instanceof Name
1596+
&& strtolower($exprNode->name->toString()) === 'get_class'
1597+
&& isset($exprNode->getArgs()[0])
1598+
&& $constantType->isString()->yes()
1599+
) {
1600+
return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\Identical($expr->left, $expr->right), $context, $rootExpr);
1601+
}
1602+
}
1603+
1604+
$leftType = $scope->getType($expr->left);
1605+
$rightType = $scope->getType($expr->right);
1606+
1607+
$leftBooleanType = $leftType->toBoolean();
1608+
if ($leftBooleanType instanceof ConstantBooleanType && $rightType->isBoolean()->yes()) {
1609+
return $this->specifyTypesInCondition(
1610+
$scope,
1611+
new Expr\BinaryOp\Identical(
1612+
new ConstFetch(new Name($leftBooleanType->getValue() ? 'true' : 'false')),
1613+
$expr->right,
1614+
),
1615+
$context,
1616+
$rootExpr,
1617+
);
1618+
}
1619+
1620+
$rightBooleanType = $rightType->toBoolean();
1621+
if ($rightBooleanType instanceof ConstantBooleanType && $leftType->isBoolean()->yes()) {
1622+
return $this->specifyTypesInCondition(
1623+
$scope,
1624+
new Expr\BinaryOp\Identical(
1625+
$expr->left,
1626+
new ConstFetch(new Name($rightBooleanType->getValue() ? 'true' : 'false')),
1627+
),
1628+
$context,
1629+
$rootExpr,
1630+
);
1631+
}
1632+
1633+
if (
1634+
!$context->null()
1635+
&& $rightType->isArray()->yes()
1636+
&& $leftType->isConstantArray()->yes() && $leftType->isIterableAtLeastOnce()->no()
1637+
) {
1638+
return $this->create($expr->right, new NonEmptyArrayType(), $context->negate(), false, $scope, $rootExpr);
1639+
}
1640+
1641+
if (
1642+
!$context->null()
1643+
&& $leftType->isArray()->yes()
1644+
&& $rightType->isConstantArray()->yes() && $rightType->isIterableAtLeastOnce()->no()
1645+
) {
1646+
return $this->create($expr->left, new NonEmptyArrayType(), $context->negate(), false, $scope, $rootExpr);
1647+
}
1648+
1649+
$integerType = new IntegerType();
1650+
$floatType = new FloatType();
1651+
if (
1652+
($leftType->isString()->yes() && $rightType->isString()->yes())
1653+
|| ($integerType->isSuperTypeOf($leftType)->yes() && $integerType->isSuperTypeOf($rightType)->yes())
1654+
|| ($floatType->isSuperTypeOf($leftType)->yes() && $floatType->isSuperTypeOf($rightType)->yes())
1655+
|| ($leftType->isEnum()->yes() && $rightType->isEnum()->yes())
1656+
) {
1657+
return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\Identical($expr->left, $expr->right), $context, $rootExpr);
1658+
}
1659+
1660+
$leftExprString = $this->exprPrinter->printExpr($expr->left);
1661+
$rightExprString = $this->exprPrinter->printExpr($expr->right);
1662+
if ($leftExprString === $rightExprString) {
1663+
if (!$expr->left instanceof Expr\Variable || !$expr->right instanceof Expr\Variable) {
1664+
return new SpecifiedTypes([], [], false, [], $rootExpr);
1665+
}
1666+
}
1667+
1668+
$leftTypes = $this->create($expr->left, $leftType, $context, false, $scope, $rootExpr);
1669+
$rightTypes = $this->create($expr->right, $rightType, $context, false, $scope, $rootExpr);
1670+
1671+
return $context->true()
1672+
? $leftTypes->unionWith($rightTypes)
1673+
: $leftTypes->normalize($scope)->intersectWith($rightTypes->normalize($scope));
1674+
}
1675+
16711676
public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, TypeSpecifierContext $context, Expr $rootExpr): SpecifiedTypes
16721677
{
16731678
$leftExpr = $expr->left;

0 commit comments

Comments
 (0)