Skip to content

Commit

Permalink
Let BooleanAnd and BooleanOr make use of the left scope / types, remo…
Browse files Browse the repository at this point in the history
…ve hacky workarounds
  • Loading branch information
herndlm authored and ondrejmirtes committed Feb 15, 2022
1 parent 7abb7c9 commit c6b5430
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 8 deletions.
5 changes: 5 additions & 0 deletions src/Analyser/SpecifiedTypes.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ public function unionWith(SpecifiedTypes $other): self
return new self($sureTypeUnion, $sureNotTypeUnion);
}

public function inverse(): self
{
return new self($this->sureNotTypes, $this->sureTypes, $this->overwrite, $this->newConditionalExpressionHolders);
}

private function normalize(): self
{
$sureTypes = $this->sureTypes;
Expand Down
16 changes: 10 additions & 6 deletions src/Analyser/TypeSpecifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -482,8 +482,6 @@ public function specifyTypesInCondition(
$argType = $scope->getType($expr->right->getArgs()[0]->value);
if ($argType->isArray()->yes()) {
$result = $result->unionWith($this->create($expr->right->getArgs()[0]->value, new NonEmptyArrayType(), $context, false, $scope));
} else {
$result = $result->unionWith($this->create($expr->right->getArgs()[0]->value, new ConstantArrayType([], []), $context->negate(), false, $scope));
}
}
}
Expand All @@ -503,8 +501,6 @@ public function specifyTypesInCondition(
$argType = $scope->getType($expr->right->getArgs()[0]->value);
if ($argType instanceof StringType) {
$result = $result->unionWith($this->create($expr->right->getArgs()[0]->value, new AccessoryNonEmptyStringType(), $context, false, $scope));
} else {
$result = $result->unionWith($this->create($expr->right->getArgs()[0]->value, new ConstantStringType(''), $context->negate(), false, $scope));
}
}
}
Expand Down Expand Up @@ -670,8 +666,12 @@ public function specifyTypesInCondition(

return $this->handleDefaultTruthyOrFalseyContext($context, $expr, $scope);
} elseif ($expr instanceof BooleanAnd || $expr instanceof LogicalAnd) {
if (!$scope instanceof MutatingScope) {
throw new ShouldNotHappenException();
}
$leftTypes = $this->specifyTypesInCondition($scope, $expr->left, $context);
$rightTypes = $this->specifyTypesInCondition($scope, $expr->right, $context);
$leftScope = $scope->filterBySpecifiedTypes($context->true() ? $leftTypes : $leftTypes->inverse());
$rightTypes = $this->specifyTypesInCondition($leftScope, $expr->right, $context);
$types = $context->true() ? $leftTypes->unionWith($rightTypes) : $leftTypes->intersectWith($rightTypes);
if ($context->false()) {
return new SpecifiedTypes(
Expand All @@ -687,8 +687,12 @@ public function specifyTypesInCondition(

return $types;
} elseif ($expr instanceof BooleanOr || $expr instanceof LogicalOr) {
if (!$scope instanceof MutatingScope) {
throw new ShouldNotHappenException();
}
$leftTypes = $this->specifyTypesInCondition($scope, $expr->left, $context);
$rightTypes = $this->specifyTypesInCondition($scope, $expr->right, $context);
$leftScope = $scope->filterBySpecifiedTypes($context->true() ? $leftTypes->inverse() : $leftTypes);
$rightTypes = $this->specifyTypesInCondition($leftScope, $expr->right, $context);
$types = $context->true() ? $leftTypes->intersectWith($rightTypes) : $leftTypes->unionWith($rightTypes);
if ($context->true()) {
return new SpecifiedTypes(
Expand Down
22 changes: 20 additions & 2 deletions tests/PHPStan/Analyser/TypeSpecifierTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use PhpParser\Node\Expr\BinaryOp\Identical;
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
use PhpParser\Node\Expr\BooleanNot;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
Expand Down Expand Up @@ -988,7 +989,7 @@ public function dataCondition(): array
new Identical(new Expr\ConstFetch(new Name('null')), new Variable('a')),
),
['$a' => 'non-empty-string|null'],
['$a' => '~null'],
['$a' => '~non-empty-string|null'],
],
[
new Expr\BinaryOp\BooleanOr(
Expand All @@ -1002,7 +1003,24 @@ public function dataCondition(): array
new Identical(new Expr\ConstFetch(new Name('null')), new Variable('a')),
),
['$a' => 'non-empty-array|null'],
['$a' => '~null'],
['$a' => '~non-empty-array|null'],
],
[
new Expr\BinaryOp\BooleanAnd(
$this->createFunctionCall('is_array', 'foo'),
new Identical(
new FuncCall(
new Name('array_filter'),
[new Arg(new Variable('foo')), new Arg(new String_('is_string')), new Arg(new ConstFetch(new Name('ARRAY_FILTER_USE_KEY')))],
),
new Variable('foo'),
),
),
[
'$foo' => 'array<string, mixed>',
'array_filter($foo, \'is_string\', ARRAY_FILTER_USE_KEY)' => 'array<string, mixed>',
],
[],
],
];
}
Expand Down

0 comments on commit c6b5430

Please sign in to comment.