1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00

Change empty type assertions to "falsy"

As empty has a special meaning
This commit is contained in:
Matthew Brown 2017-10-22 11:57:41 -04:00
parent 032cd3b897
commit f6e01b5925
6 changed files with 49 additions and 49 deletions

View File

@ -59,7 +59,7 @@ class AssertionFinder
$this_class_name,
$source
)) {
$if_types[$var_name] = '!empty';
$if_types[$var_name] = '!falsy';
return $if_types;
}
@ -72,7 +72,7 @@ class AssertionFinder
);
if ($var_name) {
$if_types[$var_name] = '!empty';
$if_types[$var_name] = '!falsy';
}
return $if_types;
@ -122,7 +122,7 @@ class AssertionFinder
if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\Identical) {
$if_types[$var_name] = 'null';
} else {
$if_types[$var_name] = 'empty';
$if_types[$var_name] = 'falsy';
}
} elseif ($var_type && $conditional instanceof PhpParser\Node\Expr\BinaryOp\Identical) {
$null_type = Type::getNull();
@ -194,7 +194,7 @@ class AssertionFinder
if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\Identical) {
$if_types[$var_name] = 'false';
} else {
$if_types[$var_name] = 'empty';
$if_types[$var_name] = 'falsy';
}
} elseif ($var_type && $conditional instanceof PhpParser\Node\Expr\BinaryOp\Identical) {
$false_type = Type::getFalse();
@ -360,7 +360,7 @@ class AssertionFinder
if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\NotIdentical) {
$if_types[$var_name] = '!null';
} else {
$if_types[$var_name] = '!empty';
$if_types[$var_name] = '!falsy';
}
}
@ -388,7 +388,7 @@ class AssertionFinder
if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\NotIdentical) {
$if_types[$var_name] = '!false';
} else {
$if_types[$var_name] = '!empty';
$if_types[$var_name] = '!falsy';
}
}
@ -440,7 +440,7 @@ class AssertionFinder
);
if ($var_name) {
$if_types[$var_name] = 'empty';
$if_types[$var_name] = 'falsy';
}
return $if_types;

View File

@ -929,7 +929,7 @@ class ExpressionChecker
if ($var_id && isset($context->vars_in_scope[$var_id])) {
$left_inferred_reconciled = TypeChecker::reconcileTypes(
'!empty',
'!falsy',
$context->vars_in_scope[$var_id],
'',
$statements_checker,
@ -2057,7 +2057,7 @@ class ExpressionChecker
} elseif ($stmt->cond) {
if (isset($stmt->cond->inferredType)) {
$if_return_type_reconciled = TypeChecker::reconcileTypes(
'!empty',
'!falsy',
$stmt->cond->inferredType,
'',
$statements_checker,

View File

@ -165,7 +165,7 @@ class TypeChecker
return Type::getMixed();
}
if ($new_var_type[0] !== '!' && $new_var_type !== 'empty') {
if ($new_var_type[0] !== '!' && $new_var_type !== 'falsy') {
if ($new_var_type[0] === '^') {
$new_var_type = substr($new_var_type, 1);
}
@ -173,7 +173,7 @@ class TypeChecker
return Type::parseString($new_var_type);
}
return $new_var_type === '!empty' ? Type::getMixed() : null;
return $new_var_type === '!falsy' ? Type::getMixed() : null;
}
if ($new_var_type === 'mixed' && $existing_var_type->isMixed()) {
@ -217,10 +217,10 @@ class TypeChecker
return Type::getMixed();
}
if (in_array($new_var_type, ['!empty', '!null'], true)) {
if (in_array($new_var_type, ['!falsy', '!null'], true)) {
$existing_var_type->removeType('null');
if ($new_var_type === '!empty') {
if ($new_var_type === '!falsy') {
$existing_var_type->removeType('false');
if ($existing_var_type->hasType('array') &&
@ -292,7 +292,7 @@ class TypeChecker
$new_var_type = substr($new_var_type, 1);
}
if ($new_var_type === 'empty') {
if ($new_var_type === 'falsy') {
if ($existing_var_type->hasType('bool')) {
$existing_var_type->removeType('bool');
$existing_var_type->types['false'] = new TFalse;

View File

@ -6,8 +6,8 @@ class Clause
/**
* An array of strings of the form
* [
* '$a' => ['empty'],
* '$b' => ['!empty'],
* '$a' => ['falsy'],
* '$b' => ['!falsy'],
* '$c' => ['!null'],
* '$d' => ['string', 'int']
* ]
@ -23,8 +23,8 @@ class Clause
/**
* An array of things that are not true
* [
* '$a' => ['!empty'],
* '$b' => ['empty'],
* '$a' => ['!falsy'],
* '$b' => ['falsy'],
* '$c' => ['null'],
* '$d' => ['!string', '!int']
* ]

View File

@ -357,7 +357,7 @@ class Context
// if the clause contains any possibilities that would be altered
foreach ($clause->possibilities[$remove_var_id] as $type) {
// empty and !empty are not definitive for arrays and scalar types
if (($type === '!empty' || $type === 'empty') &&
if (($type === '!falsy' || $type === 'falsy') &&
($new_type->hasArray() || $new_type->hasNumericType())
) {
$type_changed = true;

View File

@ -87,36 +87,36 @@ class TypeReconciliationTest extends TestCase
public function testNegateFormula()
{
$formula = [
new Clause(['$a' => ['!empty']]),
new Clause(['$a' => ['!falsy']]),
];
$negated_formula = AlgebraChecker::negateFormula($formula);
$this->assertSame(1, count($negated_formula));
$this->assertSame(['$a' => ['empty']], $negated_formula[0]->possibilities);
$this->assertSame(['$a' => ['falsy']], $negated_formula[0]->possibilities);
$formula = [
new Clause(['$a' => ['!empty'], '$b' => ['!empty']]),
new Clause(['$a' => ['!falsy'], '$b' => ['!falsy']]),
];
$negated_formula = AlgebraChecker::negateFormula($formula);
$this->assertSame(2, count($negated_formula));
$this->assertSame(['$a' => ['empty']], $negated_formula[0]->possibilities);
$this->assertSame(['$b' => ['empty']], $negated_formula[1]->possibilities);
$this->assertSame(['$a' => ['falsy']], $negated_formula[0]->possibilities);
$this->assertSame(['$b' => ['falsy']], $negated_formula[1]->possibilities);
$formula = [
new Clause(['$a' => ['!empty']]),
new Clause(['$b' => ['!empty']]),
new Clause(['$a' => ['!falsy']]),
new Clause(['$b' => ['!falsy']]),
];
$negated_formula = AlgebraChecker::negateFormula($formula);
$this->assertSame(1, count($negated_formula));
$this->assertSame(['$a' => ['empty'], '$b' => ['empty']], $negated_formula[0]->possibilities);
$this->assertSame(['$a' => ['falsy'], '$b' => ['falsy']], $negated_formula[0]->possibilities);
$formula = [
new Clause(['$a' => ['int', 'string'], '$b' => ['!empty']]),
new Clause(['$a' => ['int', 'string'], '$b' => ['!falsy']]),
];
$negated_formula = AlgebraChecker::negateFormula($formula);
@ -124,7 +124,7 @@ class TypeReconciliationTest extends TestCase
$this->assertSame(3, count($negated_formula));
$this->assertSame(['$a' => ['!int']], $negated_formula[0]->possibilities);
$this->assertSame(['$a' => ['!string']], $negated_formula[1]->possibilities);
$this->assertSame(['$b' => ['empty']], $negated_formula[2]->possibilities);
$this->assertSame(['$b' => ['falsy']], $negated_formula[2]->possibilities);
}
/**
@ -135,13 +135,13 @@ class TypeReconciliationTest extends TestCase
$this->assertTrue(
(new Clause(
[
'$a' => ['!empty'],
'$b' => ['!empty'],
'$a' => ['!falsy'],
'$b' => ['!falsy'],
]
))->contains(
new Clause(
[
'$a' => ['!empty'],
'$a' => ['!falsy'],
]
)
)
@ -150,13 +150,13 @@ class TypeReconciliationTest extends TestCase
$this->assertFalse(
(new Clause(
[
'$a' => ['!empty'],
'$a' => ['!falsy'],
]
))->contains(
new Clause(
[
'$a' => ['!empty'],
'$b' => ['!empty'],
'$a' => ['!falsy'],
'$b' => ['!falsy'],
]
)
)
@ -169,15 +169,15 @@ class TypeReconciliationTest extends TestCase
public function testSimplifyCNF()
{
$formula = [
new Clause(['$a' => ['!empty']]),
new Clause(['$a' => ['empty'], '$b' => ['empty']]),
new Clause(['$a' => ['!falsy']]),
new Clause(['$a' => ['falsy'], '$b' => ['falsy']]),
];
$simplified_formula = AlgebraChecker::simplifyCNF($formula);
$this->assertSame(2, count($simplified_formula));
$this->assertSame(['$a' => ['!empty']], $simplified_formula[0]->possibilities);
$this->assertSame(['$b' => ['empty']], $simplified_formula[1]->possibilities);
$this->assertSame(['$a' => ['!falsy']], $simplified_formula[0]->possibilities);
$this->assertSame(['$b' => ['falsy']], $simplified_formula[1]->possibilities);
}
/**
@ -191,21 +191,21 @@ class TypeReconciliationTest extends TestCase
'notNullWithMyObjectPipeFalse' => ['MyObject|false', '!null', 'MyObject|false'],
'notNullWithMixed' => ['mixed', '!null', 'mixed'],
'notEmptyWithMyObject' => ['MyObject', '!empty', 'MyObject'],
'notEmptyWithMyObjectPipeNull' => ['MyObject', '!empty', 'MyObject|null'],
'notEmptyWithMyObjectPipeFalse' => ['MyObject', '!empty', 'MyObject|false'],
'notEmptyWithMixed' => ['mixed', '!empty', 'mixed'],
'notEmptyWithMyObject' => ['MyObject', '!falsy', 'MyObject'],
'notEmptyWithMyObjectPipeNull' => ['MyObject', '!falsy', 'MyObject|null'],
'notEmptyWithMyObjectPipeFalse' => ['MyObject', '!falsy', 'MyObject|false'],
'notEmptyWithMixed' => ['mixed', '!falsy', 'mixed'],
// @todo in the future this should also work
//'notEmptyWithMyObjectFalseTrue' => ['MyObject|true', '!empty', 'MyObject|bool'],
//'notEmptyWithMyObjectFalseTrue' => ['MyObject|true', '!falsy', 'MyObject|bool'],
'notEmptyWithMyObjectPipeNull' => ['null', 'null', 'MyObject|null'],
'notEmptyWithMixed' => ['null', 'null', 'mixed'],
'emptyWithMyObject' => ['null', 'empty', 'MyObject'],
'emptyWithMyObjectPipeFalse' => ['false', 'empty', 'MyObject|false'],
'emptyWithMyObjectPipeBool' => ['false', 'empty', 'MyObject|bool'],
'emptyWithMixed' => ['mixed', 'empty', 'mixed'],
'emptyWithBool' => ['false', 'empty', 'bool'],
'emptyWithMyObject' => ['null', 'falsy', 'MyObject'],
'emptyWithMyObjectPipeFalse' => ['false', 'falsy', 'MyObject|false'],
'emptyWithMyObjectPipeBool' => ['false', 'falsy', 'MyObject|bool'],
'emptyWithMixed' => ['mixed', 'falsy', 'mixed'],
'emptyWithBool' => ['false', 'falsy', 'bool'],
'notMyObjectWithMyObjectPipeBool' => ['bool', '!MyObject', 'MyObject|bool'],
'notMyObjectWithMyObjectPipeNull' => ['null', '!MyObject', 'MyObject|null'],