1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-22 05:41:20 +01:00

Assert intersection type when two variables are compared (#5774)

This commit is contained in:
orklah 2021-05-18 22:14:58 +02:00 committed by GitHub
parent 3c43bc1522
commit f62b83a190
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 57 additions and 4 deletions

View File

@ -596,10 +596,6 @@ abstract class ClassLikeAnalyzer extends SourceAnalyzer
return $emit_issues ? null : true;
case self::VISIBILITY_PROTECTED:
if ($appearing_property_class === $context->self) {
return null;
}
if (!$context->self) {
if ($emit_issues && IssueBuffer::accepts(
new InaccessibleProperty(

View File

@ -437,6 +437,40 @@ class AssertionFinder
)) {
// fall through
}
} else {
// 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()) {
$assertion = $intersection_type->getAssertionString();
$if_types = [];
$var_name_left = ExpressionIdentifier::getArrayVarId(
$conditional->left,
$this_class_name,
$source
);
if ($var_name_left &&
(!$var_type->isSingle() || $var_type->getAssertionString() !== $assertion)) {
$if_types[$var_name_left] = [['~'.$assertion]];
}
$var_name_right = ExpressionIdentifier::getArrayVarId(
$conditional->right,
$this_class_name,
$source
);
if ($var_name_right &&
(!$other_type->isSingle() || $other_type->getAssertionString() !== $assertion)) {
$if_types[$var_name_right] = [['~'.$assertion]];
}
return $if_types ? [$if_types] : [];
}
}
}

View File

@ -1,6 +1,7 @@
<?php
namespace Psalm;
use Psalm\Internal\Type\Comparator\UnionTypeComparator;
use Psalm\Plugin\EventHandler\Event\StringInterpreterEvent;
use Psalm\Type\Atomic\TNever;
use function array_merge;
@ -649,6 +650,19 @@ abstract class Type
}
}
//if a type is contained by the other, the intersection is the narrowest type
if (!$intersection_performed) {
$type_1_in_2 = UnionTypeComparator::isContainedBy($codebase, $type_1, $type_2);
$type_2_in_1 = UnionTypeComparator::isContainedBy($codebase, $type_2, $type_1);
if ($type_1_in_2) {
$intersection_performed = true;
$combined_type = $type_1;
} elseif ($type_2_in_1) {
$intersection_performed = true;
$combined_type = $type_2;
}
}
if (!$type_1->initialized && !$type_2->initialized) {
$combined_type->initialized = false;
}

View File

@ -1093,6 +1093,15 @@ class TypeAlgebraTest extends \Psalm\Tests\TestCase
[],
'8.1',
],
'narrowedTypeAfterIdenticalCheckWithOtherType' => [
'<?php
function a(int $a, ?int $b = null): void
{
if ($a === $b) {
throw new InvalidArgumentException(sprintf("a can not be the same as b (b: %s).", $b));
}
}'
],
];
}