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:
parent
032cd3b897
commit
f6e01b5925
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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']
|
||||
* ]
|
||||
|
@ -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;
|
||||
|
@ -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'],
|
||||
|
Loading…
Reference in New Issue
Block a user