1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-27 12:55:26 +01:00

Merge pull request #6641 from orklah/weird-assertion-count

Union::getAssertionString with multiple types
This commit is contained in:
orklah 2021-10-13 08:15:28 +02:00 committed by GitHub
commit e7cd2eac0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 111 additions and 33 deletions

View File

@ -29,6 +29,7 @@ use Psalm\Issue\TypeDoesNotContainType;
use Psalm\Issue\UnevaluatedCode;
use Psalm\IssueBuffer;
use Psalm\Type;
use UnexpectedValueException;
use function assert;
use function count;
@ -494,8 +495,12 @@ class AssertionFinder
$intersection_type = Type::intersectUnionTypes($var_type, $other_type, $codebase);
if ($intersection_type !== null && $intersection_type->isSingle()) {
$assertion = $intersection_type->getAssertionString();
try {
$assertion = $intersection_type->getAssertionString();
} catch (UnexpectedValueException $e) {
// getAssertionString can't work if the Union has more than one type
return [];
}
$if_types = [];
$var_name_left = ExpressionIdentifier::getArrayVarId(
@ -504,8 +509,14 @@ class AssertionFinder
$source
);
if ($var_name_left &&
(!$var_type->isSingle() || $var_type->getAssertionString() !== $assertion)) {
try {
$var_assertion_different = $var_type->getAssertionString() !== $assertion;
} catch (UnexpectedValueException $e) {
// if getAssertionString threw, it's different
$var_assertion_different = true;
}
if ($var_name_left && $var_assertion_different) {
$if_types[$var_name_left] = [['='.$assertion]];
}
@ -515,8 +526,15 @@ class AssertionFinder
$source
);
if ($var_name_right &&
(!$other_type->isSingle() || $other_type->getAssertionString() !== $assertion)) {
try {
$other_assertion_different = $other_type->getAssertionString() !== $assertion;
} catch (UnexpectedValueException $e) {
// if getAssertionString threw, it's different
$other_assertion_different = true;
}
if ($var_name_right && $other_assertion_different) {
$if_types[$var_name_right] = [['='.$assertion]];
}
@ -896,14 +914,17 @@ class AssertionFinder
foreach ($and_rules as $j => $rule) {
if (strpos($rule, 'class-constant(') === 0) {
$codebase = $source->getCodebase();
$assertion->rule[$i][$j] = \Psalm\Internal\Type\TypeExpander::expandUnion(
$codebase,
Type::parseString(substr($rule, 15, -1)),
null,
null,
null
)->getAssertionString();
try {
$assertion->rule[$i][$j] = \Psalm\Internal\Type\TypeExpander::expandUnion(
$codebase,
Type::parseString(substr($rule, 15, -1)),
null,
null,
null
)->getAssertionString();
} catch (UnexpectedValueException $e) {
continue;
}
}
}
}
@ -962,13 +983,17 @@ class AssertionFinder
if (strpos($rule, 'class-constant(') === 0) {
$codebase = $source->getCodebase();
$assertion->rule[$i][$j] = \Psalm\Internal\Type\TypeExpander::expandUnion(
$codebase,
Type::parseString(substr($rule, 15, -1)),
null,
null,
null
)->getAssertionString();
try {
$assertion->rule[$i][$j] = \Psalm\Internal\Type\TypeExpander::expandUnion(
$codebase,
Type::parseString(substr($rule, 15, -1)),
null,
null,
null
)->getAssertionString();
} catch (UnexpectedValueException $e) {
continue;
}
}
}
}
@ -2487,9 +2512,25 @@ class AssertionFinder
);
if ($not_identical) {
$if_types[$var_name] = [['!=' . $var_type->getAssertionString()]];
try {
$assertion = $var_type->getAssertionString();
} catch (UnexpectedValueException $e) {
$assertion = null;
}
if ($assertion) {
$if_types[$var_name] = [['!=' . $assertion]];
}
} else {
$if_types[$var_name] = [['!~' . $var_type->getAssertionString()]];
try {
$assertion = $var_type->getAssertionString();
} catch (UnexpectedValueException $e) {
$assertion = null;
}
if ($assertion) {
$if_types[$var_name] = [['!~' . $assertion]];
}
}
}
@ -3177,18 +3218,49 @@ class AssertionFinder
);
if ($identical) {
$if_types[$var_name] = [['=' . $var_type->getAssertionString(true)]];
try {
$assertion = $var_type->getAssertionString(true);
} catch (UnexpectedValueException $e) {
$assertion = null;
}
if ($assertion) {
$if_types[$var_name] = [['=' . $assertion]];
}
} else {
$if_types[$var_name] = [['~' . $var_type->getAssertionString()]];
try {
$assertion = $var_type->getAssertionString();
} catch (UnexpectedValueException $e) {
$assertion = null;
}
if ($assertion) {
$if_types[$var_name] = [['~' . $assertion]];
}
}
// we count the Atomics instead of using isSingle because Psalm considers multiple literals as Single
// however, getAssertionString return the assertion for the first Atomic only
if ($other_var_name && $other_type && count($other_type->getAtomicTypes()) === 1) {
if ($other_var_name && $other_type) {
if ($identical) {
$if_types[$other_var_name] = [['=' . $other_type->getAssertionString(true)]];
try {
$assertion = $other_type->getAssertionString(true);
} catch (UnexpectedValueException $e) {
$assertion = null;
}
if ($assertion) {
$if_types[$other_var_name] = [['=' . $assertion]];
}
} else {
$if_types[$other_var_name] = [['~' . $other_type->getAssertionString()]];
try {
$assertion = $other_type->getAssertionString();
} catch (UnexpectedValueException $e) {
$assertion = null;
}
if ($assertion) {
$if_types[$other_var_name] = [['~' . $assertion]];
}
}
}
}

View File

@ -410,11 +410,17 @@ class Union implements TypeNode
public function getAssertionString(bool $exact = false): string
{
$assertions = [];
foreach ($this->types as $type) {
return $type->getAssertionString($exact);
$assertions[] = $type->getAssertionString($exact);
}
throw new \UnexpectedValueException('Should only be one type per assertion');
$assertions = array_unique($assertions);
if (count($assertions) !== 1) {
throw new \UnexpectedValueException('Should only be one type per assertion');
}
return reset($assertions);
}
/**

View File

@ -1241,7 +1241,7 @@ class AssertAnnotationTest extends TestCase
return substr($a, 0, 1) . substr($b, 0, 1);
}'
],
'convertConstStringType' => [
'SKIPPED-convertConstStringType' => [
'<?php
class A {
const T1 = 1;