Skip to content

Commit

Permalink
Fix
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Nov 4, 2023
1 parent a5eece2 commit c1310c4
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 5 deletions.
20 changes: 15 additions & 5 deletions src/Analyser/NodeScopeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -3740,20 +3740,30 @@ private function processAssignVar(
$throwPoints = $result->getThrowPoints();
$assignedExpr = $this->unwrapAssign($assignedExpr);
$type = $scope->getType($assignedExpr);
$truthySpecifiedTypes = $this->typeSpecifier->specifyTypesInCondition($scope, $assignedExpr, TypeSpecifierContext::createTruthy());
$falseySpecifiedTypes = $this->typeSpecifier->specifyTypesInCondition($scope, $assignedExpr, TypeSpecifierContext::createFalsey());

$conditionalExpressions = [];
if ($assignedExpr instanceof Ternary && $assignedExpr->if !== null) {
$condScope = $this->processExprNode($assignedExpr->cond, $scope, static function (): void {
}, ExpressionContext::createDeep())->getScope();
$truthySpecifiedTypes = $this->typeSpecifier->specifyTypesInCondition($condScope, $assignedExpr->cond, TypeSpecifierContext::createTruthy());
$falseySpecifiedTypes = $this->typeSpecifier->specifyTypesInCondition($condScope, $assignedExpr->cond, TypeSpecifierContext::createFalsey());
$truthyScope = $condScope->filterBySpecifiedTypes($truthySpecifiedTypes);
$falsyScope = $condScope->filterBySpecifiedTypes($falseySpecifiedTypes);
$truthyType = $truthyScope->getType($assignedExpr->if);
$falseyType = $falsyScope->getType($assignedExpr->else);
} else {
$truthySpecifiedTypes = $this->typeSpecifier->specifyTypesInCondition($scope, $assignedExpr, TypeSpecifierContext::createTruthy());
$falseySpecifiedTypes = $this->typeSpecifier->specifyTypesInCondition($scope, $assignedExpr, TypeSpecifierContext::createFalsey());

$truthyType = TypeCombinator::removeFalsey($type);
$falseyType = TypeCombinator::intersect($type, StaticTypeFactory::falsey());
$truthyType = TypeCombinator::removeFalsey($type);
$falseyType = TypeCombinator::intersect($type, StaticTypeFactory::falsey());
}

$conditionalExpressions = $this->processSureTypesForConditionalExpressionsAfterAssign($scope, $var->name, $conditionalExpressions, $truthySpecifiedTypes, $truthyType);
$conditionalExpressions = $this->processSureNotTypesForConditionalExpressionsAfterAssign($scope, $var->name, $conditionalExpressions, $truthySpecifiedTypes, $truthyType);
$conditionalExpressions = $this->processSureTypesForConditionalExpressionsAfterAssign($scope, $var->name, $conditionalExpressions, $falseySpecifiedTypes, $falseyType);
$conditionalExpressions = $this->processSureNotTypesForConditionalExpressionsAfterAssign($scope, $var->name, $conditionalExpressions, $falseySpecifiedTypes, $falseyType);

// TODO conditional expressions for native type should be handled too
$scope = $result->getScope()->assignVariable($var->name, $type, $scope->getNativeType($assignedExpr));
foreach ($conditionalExpressions as $exprString => $holders) {
$scope = $scope->addConditionalExpressions($exprString, $holders);
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 @@ -911,6 +911,7 @@ public function dataFileAsserts(): iterable
yield from $this->gatherAssertTypes(__DIR__ . '/data/array-reverse.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-6889.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-6891.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-10088.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/shuffle.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/simplexml.php');

Expand Down
69 changes: 69 additions & 0 deletions tests/PHPStan/Analyser/data/bug-10088.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

namespace Bug10088;

use PHPStan\TrinaryLogic;
use stdClass;
use function PHPStan\Testing\assertVariableCertainty;

class Foo
{

function doFoo(): void {
if (rand(0,1)) {
$shortcut_id = 1;
assertVariableCertainty(TrinaryLogic::createYes(), $shortcut_id);
}

assertVariableCertainty(TrinaryLogic::createMaybe(), $shortcut_id);

$link_mode = isset($shortcut_id) ? "remove" : "add";
if ($link_mode === "add") {
assertVariableCertainty(TrinaryLogic::createNo(), $shortcut_id);
} else {
assertVariableCertainty(TrinaryLogic::createYes(), $shortcut_id);
}

assertVariableCertainty(TrinaryLogic::createMaybe(), $shortcut_id);
}

/**
* @param mixed[] $period
*/
public function testCarbon(array $period): void
{
foreach ($period as $date) {
break;
}

assertVariableCertainty(TrinaryLogic::createMaybe(), $date);
$this->assertInstanceOfStdClass($date ?? null);
assertVariableCertainty(TrinaryLogic::createYes(), $date);
}

/**
* @param mixed $m
* @phpstan-assert stdClass $m
*/
private function assertInstanceOfStdClass($m): void
{
if (!$m instanceof stdClass) {
throw new \Exception();
}
}

/**
* @param mixed[] $period
*/
public function testCarbon2(array $period): void
{
foreach ($period as $date) {
break;
}

assertVariableCertainty(TrinaryLogic::createMaybe(), $date);
assert(($date ?? null) instanceof stdClass);
assertVariableCertainty(TrinaryLogic::createYes(), $date);
}

}

0 comments on commit c1310c4

Please sign in to comment.