Skip to content

Commit e0a913a

Browse files
committed
TASK: Narrower handle boolean literal comparisons
1 parent 88c6fd6 commit e0a913a

2 files changed

Lines changed: 53 additions & 7 deletions

File tree

src/TypeSystem/Narrower/ExpressionTypeNarrower.php

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
use PackageFactory\ComponentEngine\Definition\BinaryOperator;
2626
use PackageFactory\ComponentEngine\Parser\Ast\BinaryOperationNode;
27+
use PackageFactory\ComponentEngine\Parser\Ast\BooleanLiteralNode;
2728
use PackageFactory\ComponentEngine\Parser\Ast\ExpressionNode;
2829
use PackageFactory\ComponentEngine\Parser\Ast\IdentifierNode;
2930
use PackageFactory\ComponentEngine\Parser\Ast\NullLiteralNode;
@@ -59,15 +60,43 @@ public function narrowTypesOfSymbolsIn(ExpressionNode $expressionNode, TypeNarro
5960
}
6061

6162
if (($binaryOperationNode = $expressionNode->root) instanceof BinaryOperationNode) {
62-
// cases
63-
// `nullableString === null ? "nullableString is null" : "nullableString is not null"`
64-
// `nullableString !== null ? "nullableString is not null" : "nullableString is null"`
63+
// todo we currently only work with two operands
6564
if (count($binaryOperationNode->operands->rest) !== 1) {
6665
return NarrowedTypes::empty();
6766
}
6867
$first = $binaryOperationNode->operands->first;
6968
$second = $binaryOperationNode->operands->rest[0];
7069

70+
if (
71+
($first->root instanceof BooleanLiteralNode
72+
&& ($boolean = $first->root) instanceof BooleanLiteralNode
73+
// @phpstan-ignore-next-line
74+
&& $other = $second
75+
) || ($second->root instanceof BooleanLiteralNode
76+
&& ($boolean = $second->root) instanceof BooleanLiteralNode
77+
// @phpstan-ignore-next-line
78+
&& $other = $first
79+
)
80+
) {
81+
$contextBasedOnOperator = match ($binaryOperationNode->operator) {
82+
BinaryOperator::EQUAL => $context,
83+
BinaryOperator::NOT_EQUAL => $context->negate(),
84+
default => null,
85+
};
86+
87+
if (!$contextBasedOnOperator) {
88+
return NarrowedTypes::empty();
89+
}
90+
91+
return $this->narrowTypesOfSymbolsIn(
92+
$other,
93+
$boolean->value ? $contextBasedOnOperator : $contextBasedOnOperator->negate()
94+
);
95+
}
96+
97+
// cases
98+
// `nullableString === null ? "nullableString is null" : "nullableString is not null"`
99+
// `nullableString !== null ? "nullableString is not null" : "nullableString is null"`
71100
$comparedIdentifierValueToNull = match (true) {
72101
// case `nullableString === null`
73102
$first->root instanceof IdentifierNode && $second->root instanceof NullLiteralNode => $first->root->value,

test/Unit/TypeSystem/Resolver/TernaryOperation/TernaryOperationTypeResolverTest.php

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,27 +45,44 @@ public function ternaryOperationExamples(): array
4545
'false ? 42 : "foo"' => ['false ? 42 : "foo"', StringType::get()],
4646
'1 < 2 ? 42 : "foo"' => ['1 < 2 ? 42 : "foo"', UnionType::of(NumberType::get(), StringType::get())],
4747
'1 < 2 ? variableOfTypeString : variableOfTypeNumber' => [
48-
'1 < 2 ? variableOfTypeString : variableOfTypeNumber',
48+
'1 < 2 ? variableOfTypeString : variableOfTypeNumber',
4949
UnionType::of(NumberType::get(), StringType::get())
5050
],
51+
5152
'nullableString ? nullableString : "fallback"' => [
5253
'nullableString ? nullableString : "fallback"', StringType::get()
5354
],
55+
'nullableString ? null : nullableString' => [
56+
'nullableString ? null : nullableString', NullType::get()
57+
],
58+
5459
'nullableString === null ? "" : nullableString' => [
5560
'nullableString === null ? "" : nullableString', StringType::get()
5661
],
62+
// Patience you must have my young Padawan.
5763
'null === nullableString ? "" : nullableString' => [
5864
'null === nullableString ? "" : nullableString', StringType::get()
5965
],
66+
6067
'nullableString !== null ? nullableString : ""' => [
6168
'nullableString !== null ? nullableString : ""', StringType::get()
6269
],
63-
// Patience you must have my young Padawan.
6470
'null !== nullableString ? nullableString : ""' => [
6571
'null !== nullableString ? nullableString : ""', StringType::get()
6672
],
67-
'nullableString ? null : nullableString' => [
68-
'nullableString ? null : nullableString', NullType::get()
73+
74+
'true === (nullableString === null) ? "" : nullableString' => [
75+
'true === (nullableString === null) ? "" : nullableString', StringType::get()
76+
],
77+
'false !== (nullableString === null) ? "" : nullableString' => [
78+
'false !== (nullableString === null) ? "" : nullableString', StringType::get()
79+
],
80+
81+
'false === (nullableString === null) ? nullableString : ""' => [
82+
'false === (nullableString === null) ? nullableString : ""', StringType::get()
83+
],
84+
'true !== (nullableString === null) ? nullableString : ""' => [
85+
'true !== (nullableString === null) ? nullableString : ""', StringType::get()
6986
],
7087
];
7188
}

0 commit comments

Comments
 (0)