1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-22 13:51:54 +01:00

Merge pull request #10484 from kkmuffme/literal-string-equality-removes-type-incorrectly-and-union-equality-incorrect-type

fix literal int/string comparisons only using one literal
This commit is contained in:
orklah 2023-12-13 18:48:22 +01:00 committed by GitHub
commit f7fe4cf026
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 60 additions and 17 deletions

View File

@ -542,9 +542,9 @@ 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 && $intersection_type->isSingle()) {
if ($intersection_type !== null) {
$if_types = [];
$var_name_left = ExpressionIdentifier::getExtendedVarId(
@ -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] : [];

View File

@ -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;

View File

@ -580,6 +580,45 @@ class ConditionalTest extends TestCase
}
}',
],
'reconcileMultipleLiteralStrings' => [
'code' => '<?php
/**
* @param string $param
* @param "a"|"b"|"c" $param2
* @return void
*/
function foo($param, $param2) {
if ( $param === $param2 ) {
if ($param === "a") {
echo "x";
}
if ($param === "b") {
echo "y";
}
if ($param === "c") {
echo "z";
}
}
}',
],
'reconcileMultipleUnionIntersection' => [
'code' => '<?php
/**
* @param int|string $param
* @param float|string $param2
* @return void
*/
function foo($param, $param2) {
if ($param === $param2) {
takesString($param);
takesString($param2);
}
}
function takesString(string $arg): void {}',
],
'reconcileNullableStringWithWeakEquality' => [
'code' => '<?php
function foo(?string $s) : void {

View File

@ -272,17 +272,6 @@ class ValueTest extends TestCase
if ($s === "a") {}
}',
],
'moreValueReconciliation' => [
'code' => '<?php
$a = rand(0, 1) ? "a" : "b";
$b = rand(0, 1) ? "a" : "b";
$s = rand(0, 1) ? $a : $b;
if (rand(0, 1)) $s = "c";
if ($s === $a) {
} elseif ($s === $b) {}',
],
'negativeInts' => [
'code' => '<?php
class C {