Skip to content

Commit

Permalink
Improve type inference from conditional return type
Browse files Browse the repository at this point in the history
  • Loading branch information
Richard van Velzen authored and ondrejmirtes committed Aug 8, 2022
1 parent 229df9b commit 8aab460
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 16 deletions.
37 changes: 21 additions & 16 deletions src/Analyser/TypeSpecifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -1085,30 +1085,35 @@ public function getConditionalSpecifiedTypes(
return null;
}

$targetType = $conditionalType->getTarget();
$ifType = $conditionalType->getIf();
$elseType = $conditionalType->getElse();

if ($leftType->isSuperTypeOf($ifType)->yes() && $rightType->isSuperTypeOf($elseType)->yes()) {
return $this->create(
$argsMap[$parameterName],
$conditionalType->getTarget(),
$conditionalType->isNegated() ? TypeSpecifierContext::createFalse() : TypeSpecifierContext::createTrue(),
false,
$scope,
);
$context = $conditionalType->isNegated() ? TypeSpecifierContext::createFalse() : TypeSpecifierContext::createTrue();
} elseif ($leftType->isSuperTypeOf($elseType)->yes() && $rightType->isSuperTypeOf($ifType)->yes()) {
$context = $conditionalType->isNegated() ? TypeSpecifierContext::createTrue() : TypeSpecifierContext::createFalse();
} else {
return null;
}

if ($leftType->isSuperTypeOf($elseType)->yes() && $rightType->isSuperTypeOf($ifType)->yes()) {
return $this->create(
$argsMap[$parameterName],
$conditionalType->getTarget(),
$conditionalType->isNegated() ? TypeSpecifierContext::createTrue() : TypeSpecifierContext::createFalse(),
false,
$scope,
);
$specifiedTypes = $this->create(
$argsMap[$parameterName],
$targetType,
$context,
false,
$scope,
);

if ($targetType instanceof ConstantBooleanType) {
if (!$targetType->getValue()) {
$context = $context->negate();
}

$specifiedTypes = $specifiedTypes->unionWith($this->specifyTypesInCondition($scope, $argsMap[$parameterName], $context));
}

return null;
return $specifiedTypes;
}

/**
Expand Down
13 changes: 13 additions & 0 deletions tests/PHPStan/Analyser/data/conditional-types-inference.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,16 @@ function (int $value) {
assertIsInt($value);
assertType('int', $value);
};

/**
* @return ($condition is true ? void : never)
*/
function invariant(bool $condition, string $message): void
{
assert($condition, $message);
}

function (mixed $value) {
invariant(is_array($value), 'must be array');
assertType('array', $value);
};

0 comments on commit 8aab460

Please sign in to comment.