diff --git a/src/Type/UnionTypeHelper.php b/src/Type/UnionTypeHelper.php index 6f39d0a61a..70d14331a7 100644 --- a/src/Type/UnionTypeHelper.php +++ b/src/Type/UnionTypeHelper.php @@ -86,6 +86,10 @@ public static function sortTypes(array $types): array return 0; } + if ($a instanceof IntegerRangeType && $b instanceof IntegerRangeType) { + return $a->getMin() <=> $b->getMin(); + } + if ($a instanceof ConstantStringType && $b instanceof ConstantStringType) { return strcasecmp($a->getValue(), $b->getValue()); } diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index 81438fba31..bba3227ac7 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -2343,7 +2343,7 @@ public function dataBinaryOperations(): array '@$stringOrNull ?: 12', ], [ - 'int<1, max>|int', + 'int|int<1, max>', '$integer ?: 12', ], [ @@ -5244,7 +5244,7 @@ public function dataArrayFunctions(): array 'array_filter($union)', ], [ - 'array|int|true>', + 'array|int<1, max>|true>', 'array_filter($withPossiblyFalsey)', ], [ diff --git a/tests/PHPStan/Analyser/TypeSpecifierTest.php b/tests/PHPStan/Analyser/TypeSpecifierTest.php index 5df0e023f6..1a3e013604 100644 --- a/tests/PHPStan/Analyser/TypeSpecifierTest.php +++ b/tests/PHPStan/Analyser/TypeSpecifierTest.php @@ -702,7 +702,7 @@ public function dataCondition(): array ) ), [ - '$n' => '~int<6, max>|int', + '$n' => '~int|int<6, max>', ], [ '$n' => '~int<3, 5>', diff --git a/tests/PHPStan/Analyser/data/bug-2954.php b/tests/PHPStan/Analyser/data/bug-2954.php index 2a8a1e1ba1..1727d11b76 100644 --- a/tests/PHPStan/Analyser/data/bug-2954.php +++ b/tests/PHPStan/Analyser/data/bug-2954.php @@ -6,7 +6,7 @@ function (int $x) { if ($x === 0) return; - assertType('int<1, max>|int', $x); + assertType('int|int<1, max>', $x); $x++; assertType('int', $x); @@ -14,7 +14,7 @@ function (int $x) { function (int $x) { if ($x === 0) return; - assertType('int<1, max>|int', $x); + assertType('int|int<1, max>', $x); ++$x; assertType('int', $x); @@ -22,7 +22,7 @@ function (int $x) { function (int $x) { if ($x === 0) return; - assertType('int<1, max>|int', $x); + assertType('int|int<1, max>', $x); $x--; assertType('int', $x); @@ -30,7 +30,7 @@ function (int $x) { function (int $x) { if ($x === 0) return; - assertType('int<1, max>|int', $x); + assertType('int|int<1, max>', $x); --$x; assertType('int', $x); diff --git a/tests/PHPStan/Analyser/data/integer-range-types.php b/tests/PHPStan/Analyser/data/integer-range-types.php index 2704b2d388..6c390c4c64 100644 --- a/tests/PHPStan/Analyser/data/integer-range-types.php +++ b/tests/PHPStan/Analyser/data/integer-range-types.php @@ -21,18 +21,18 @@ function (int $i) { assertType('int', $i); } - assertType('int<3, max>|int', $i); + assertType('int|int<3, max>', $i); if ($i < 3 && $i > 5) { assertType('*NEVER*', $i); } else { - assertType('int<3, max>|int', $i); + assertType('int|int<3, max>', $i); } if ($i > 3 && $i < 5) { assertType('4', $i); } else { - assertType('3|int<5, max>|int', $i); + assertType('3|int|int<5, max>', $i); } if ($i >= 3 && $i <= 5) { diff --git a/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php b/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php index 87cea09280..aba5d5170c 100644 --- a/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php @@ -159,11 +159,11 @@ public function testStrictComparison(): void 438, ], [ - 'Strict comparison using === between int<2, max>|int|string and 1.0 will always evaluate to false.', + 'Strict comparison using === between int|int<2, max>|string and 1.0 will always evaluate to false.', 464, ], [ - 'Strict comparison using === between int<2, max>|int|string and stdClass will always evaluate to false.', + 'Strict comparison using === between int|int<2, max>|string and stdClass will always evaluate to false.', 466, ], [ @@ -333,11 +333,11 @@ public function testStrictComparisonWithoutAlwaysTrue(): void 438, ], [ - 'Strict comparison using === between int<2, max>|int|string and 1.0 will always evaluate to false.', + 'Strict comparison using === between int|int<2, max>|string and 1.0 will always evaluate to false.', 464, ], [ - 'Strict comparison using === between int<2, max>|int|string and stdClass will always evaluate to false.', + 'Strict comparison using === between int|int<2, max>|string and stdClass will always evaluate to false.', 466, ], [ diff --git a/tests/PHPStan/Type/TypeCombinatorTest.php b/tests/PHPStan/Type/TypeCombinatorTest.php index 35aa806db8..f0328fb297 100644 --- a/tests/PHPStan/Type/TypeCombinatorTest.php +++ b/tests/PHPStan/Type/TypeCombinatorTest.php @@ -1426,6 +1426,14 @@ public function dataUnion(): array UnionType::class, 'int<1, 3>|int<7, 9>', ], + [ + [ + IntegerRangeType::fromInterval(7, 9), + IntegerRangeType::fromInterval(1, 3), + ], + UnionType::class, + 'int<1, 3>|int<7, 9>', + ], [ [ IntegerRangeType::fromInterval(1, 3), @@ -3204,7 +3212,7 @@ public function dataRemove(): array new BenevolentUnionType([new IntegerType(), new StringType()]), new ConstantIntegerType(1), UnionType::class, - 'int<2, max>|int|string', + 'int|int<2, max>|string', ], [ new BenevolentUnionType([new IntegerType(), new StringType()]),