From 108f6267124377263ac1c99e5f22e105367b0842 Mon Sep 17 00:00:00 2001 From: kkmuffme <11071985+kkmuffme@users.noreply.github.com> Date: Wed, 13 Dec 2023 13:59:26 +0100 Subject: [PATCH 1/5] fix literal int/string comparisons only using one literal Fix https://github.com/vimeo/psalm/issues/9552 --- .../Statements/Expression/AssertionFinder.php | 9 ++++++-- tests/TypeReconciliation/ConditionalTest.php | 23 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php b/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php index de4d2022a..740994506 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php @@ -555,8 +555,13 @@ final class AssertionFinder $var_assertion_different = $var_type->getId() !== $intersection_type->getId(); + $all_assertions = []; + foreach ($intersection_type->getAtomicTypes() as $atomic_type) { + $all_assertions[] = new IsIdentical($atomic_type); + } + if ($var_name_left && $var_assertion_different) { - $if_types[$var_name_left] = [[new IsIdentical($intersection_type->getSingleAtomic())]]; + $if_types[$var_name_left] = [$all_assertions]; } $var_name_right = ExpressionIdentifier::getExtendedVarId( @@ -568,7 +573,7 @@ final class AssertionFinder $other_assertion_different = $other_type->getId() !== $intersection_type->getId(); if ($var_name_right && $other_assertion_different) { - $if_types[$var_name_right] = [[new IsIdentical($intersection_type->getSingleAtomic())]]; + $if_types[$var_name_right] = [$all_assertions]; } return $if_types ? [$if_types] : []; diff --git a/tests/TypeReconciliation/ConditionalTest.php b/tests/TypeReconciliation/ConditionalTest.php index ca69a70a3..819d871ee 100644 --- a/tests/TypeReconciliation/ConditionalTest.php +++ b/tests/TypeReconciliation/ConditionalTest.php @@ -580,6 +580,29 @@ class ConditionalTest extends TestCase } }', ], + 'reconcileMultipleLiteralStrings' => [ + 'code' => ' [ 'code' => ' Date: Wed, 13 Dec 2023 14:10:22 +0100 Subject: [PATCH 2/5] Fix https://psalm.dev/r/aada187f50 where 2 union types are not intersected and the condition contains both types --- .../Statements/Expression/AssertionFinder.php | 2 +- tests/TypeReconciliation/ConditionalTest.php | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php b/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php index 740994506..4b81cb4ad 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php @@ -544,7 +544,7 @@ final class AssertionFinder // both side of the Identical can be asserted to the intersection of both $intersection_type = Type::intersectUnionTypes($var_type, $other_type, $codebase); - if ($intersection_type !== null && $intersection_type->isSingle()) { + if ($intersection_type !== null) { $if_types = []; $var_name_left = ExpressionIdentifier::getExtendedVarId( diff --git a/tests/TypeReconciliation/ConditionalTest.php b/tests/TypeReconciliation/ConditionalTest.php index 819d871ee..c8f3f9ab7 100644 --- a/tests/TypeReconciliation/ConditionalTest.php +++ b/tests/TypeReconciliation/ConditionalTest.php @@ -603,6 +603,21 @@ class ConditionalTest extends TestCase } }', ], + 'reconcileMultipleUnionIntersection' => [ + 'code' => ' [ 'code' => ' Date: Wed, 13 Dec 2023 14:43:55 +0100 Subject: [PATCH 3/5] fix bug equality assertion with int and float setting wrong type - required so previous commit works --- .../Statements/Expression/AssertionFinder.php | 2 +- src/Psalm/Type.php | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php b/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php index 4b81cb4ad..8c6aaa03c 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php @@ -542,7 +542,7 @@ final class AssertionFinder ); } else { // both side of the Identical can be asserted to the intersection of both - $intersection_type = Type::intersectUnionTypes($var_type, $other_type, $codebase); + $intersection_type = Type::intersectUnionTypes($var_type, $other_type, $codebase, false, false); if ($intersection_type !== null) { $if_types = []; diff --git a/src/Psalm/Type.php b/src/Psalm/Type.php index 6903c9409..1215799f7 100644 --- a/src/Psalm/Type.php +++ b/src/Psalm/Type.php @@ -712,7 +712,9 @@ abstract class Type public static function intersectUnionTypes( ?Union $type_1, ?Union $type_2, - Codebase $codebase + Codebase $codebase, + bool $allow_interface_equality = false, + bool $allow_float_int_equality = true ): ?Union { if ($type_2 === null && $type_1 === null) { throw new UnexpectedValueException('At least one type must be provided to combine'); @@ -766,6 +768,8 @@ abstract class Type $type_2_atomic, $codebase, $intersection_performed, + $allow_interface_equality, + $allow_float_int_equality, ); if (null !== $intersection_atomic) { @@ -838,7 +842,9 @@ abstract class Type Atomic $type_1_atomic, Atomic $type_2_atomic, Codebase $codebase, - bool &$intersection_performed + bool &$intersection_performed, + bool $allow_interface_equality = false, + bool $allow_float_int_equality = true ): ?Atomic { $intersection_atomic = null; $wider_type = null; @@ -884,6 +890,8 @@ abstract class Type $codebase, $type_2_atomic, $type_1_atomic, + $allow_interface_equality, + $allow_float_int_equality, )) { $intersection_atomic = $type_2_atomic; $wider_type = $type_1_atomic; @@ -892,6 +900,8 @@ abstract class Type $codebase, $type_1_atomic, $type_2_atomic, + $allow_interface_equality, + $allow_float_int_equality, )) { $intersection_atomic = $type_1_atomic; $wider_type = $type_2_atomic; From af3978281edc7e4feec1205b72fb31cbf725d27c Mon Sep 17 00:00:00 2001 From: kkmuffme <11071985+kkmuffme@users.noreply.github.com> Date: Wed, 13 Dec 2023 15:05:48 +0100 Subject: [PATCH 4/5] remove previously broken test https://github.com/vimeo/psalm/issues/10487 --- tests/TypeReconciliation/ValueTest.php | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/tests/TypeReconciliation/ValueTest.php b/tests/TypeReconciliation/ValueTest.php index 10df00217..527b4f6f7 100644 --- a/tests/TypeReconciliation/ValueTest.php +++ b/tests/TypeReconciliation/ValueTest.php @@ -272,17 +272,6 @@ class ValueTest extends TestCase if ($s === "a") {} }', ], - 'moreValueReconciliation' => [ - 'code' => ' [ 'code' => ' Date: Wed, 13 Dec 2023 15:10:15 +0100 Subject: [PATCH 5/5] add missing phpdoc in new tests --- tests/TypeReconciliation/ConditionalTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/TypeReconciliation/ConditionalTest.php b/tests/TypeReconciliation/ConditionalTest.php index c8f3f9ab7..99650002d 100644 --- a/tests/TypeReconciliation/ConditionalTest.php +++ b/tests/TypeReconciliation/ConditionalTest.php @@ -608,6 +608,7 @@ class ConditionalTest extends TestCase /** * @param int|string $param * @param float|string $param2 + * @return void */ function foo($param, $param2) { if ($param === $param2) { @@ -616,7 +617,7 @@ class ConditionalTest extends TestCase } } - function takesString(string $arg) {}', + function takesString(string $arg): void {}', ], 'reconcileNullableStringWithWeakEquality' => [ 'code' => '