mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
Fix overeager inference
This commit is contained in:
parent
d4846b14e6
commit
8b44459c7c
@ -248,6 +248,10 @@ class Algebra
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($clause->possibilities as $var => $possible_types) {
|
foreach ($clause->possibilities as $var => $possible_types) {
|
||||||
|
if ($var[0] === '*') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// if there's only one possible type, return it
|
// if there's only one possible type, return it
|
||||||
if (count($clause->possibilities) === 1 && count($possible_types) === 1) {
|
if (count($clause->possibilities) === 1 && count($possible_types) === 1) {
|
||||||
$possible_type = array_pop($possible_types);
|
$possible_type = array_pop($possible_types);
|
||||||
@ -551,6 +555,13 @@ class Algebra
|
|||||||
*/
|
*/
|
||||||
public static function negateFormula(array $clauses): array
|
public static function negateFormula(array $clauses): array
|
||||||
{
|
{
|
||||||
|
$clauses = array_filter(
|
||||||
|
$clauses,
|
||||||
|
function ($clause) {
|
||||||
|
return $clause->reconcilable;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (!$clauses) {
|
if (!$clauses) {
|
||||||
$cond_id = \mt_rand(0, 100000000);
|
$cond_id = \mt_rand(0, 100000000);
|
||||||
return [new Clause([], $cond_id, $cond_id, true)];
|
return [new Clause([], $cond_id, $cond_id, true)];
|
||||||
|
@ -350,6 +350,10 @@ class FormulaGenerator
|
|||||||
return $clauses;
|
return $clauses;
|
||||||
}
|
}
|
||||||
|
|
||||||
return [new Clause([], $conditional_object_id, $creating_object_id, true)];
|
/** @psalm-suppress MixedOperand */
|
||||||
|
$conditional_ref = '*' . $conditional->getAttribute('startFilePos')
|
||||||
|
. ':' . $conditional->getAttribute('endFilePos');
|
||||||
|
|
||||||
|
return [new Clause([$conditional_ref => ['!falsy']], $conditional_object_id, $creating_object_id)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ class AlgebraAnalyzer
|
|||||||
*
|
*
|
||||||
* @param list<Clause> $formula_1
|
* @param list<Clause> $formula_1
|
||||||
* @param list<Clause> $formula_2
|
* @param list<Clause> $formula_2
|
||||||
* @param array<string, mixed> $new_assigned_var_ids
|
* @param array<string, int> $new_assigned_var_ids
|
||||||
*/
|
*/
|
||||||
public static function checkForParadox(
|
public static function checkForParadox(
|
||||||
array $formula_1,
|
array $formula_1,
|
||||||
|
@ -307,6 +307,8 @@ class IfAnalyzer
|
|||||||
$if_scope->if_cond_changed_var_ids = $changed_var_ids;
|
$if_scope->if_cond_changed_var_ids = $changed_var_ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$if_context->reconciled_expression_clauses = [];
|
||||||
|
|
||||||
$old_if_context = clone $if_context;
|
$old_if_context = clone $if_context;
|
||||||
$context->vars_possibly_in_scope = array_merge(
|
$context->vars_possibly_in_scope = array_merge(
|
||||||
$if_context->vars_possibly_in_scope,
|
$if_context->vars_possibly_in_scope,
|
||||||
|
@ -120,10 +120,7 @@ class MethodCallPurityAnalyzer
|
|||||||
&& !$method_storage->mutation_free
|
&& !$method_storage->mutation_free
|
||||||
&& !$method_pure_compatible
|
&& !$method_pure_compatible
|
||||||
) {
|
) {
|
||||||
if (!$method_storage->mutation_free) {
|
|
||||||
$statements_analyzer->getSource()->inferred_has_mutation = true;
|
$statements_analyzer->getSource()->inferred_has_mutation = true;
|
||||||
}
|
|
||||||
|
|
||||||
$statements_analyzer->getSource()->inferred_impure = true;
|
$statements_analyzer->getSource()->inferred_impure = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +55,19 @@ class AlgebraTest extends TestCase
|
|||||||
$this->assertSame(['$b' => ['falsy']], $negated_formula[2]->possibilities);
|
$this->assertSame(['$b' => ['falsy']], $negated_formula[2]->possibilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testNegateFormulaWithUnreconcilableTerm(): void
|
||||||
|
{
|
||||||
|
$formula = [
|
||||||
|
new Clause(['$a' => ['int']], 1, 1),
|
||||||
|
new Clause(['$b' => ['int']], 1, 2, false, false),
|
||||||
|
];
|
||||||
|
|
||||||
|
$negated_formula = Algebra::negateFormula($formula);
|
||||||
|
|
||||||
|
$this->assertCount(1, $negated_formula);
|
||||||
|
$this->assertSame(['$a' => ['!int']], $negated_formula[0]->possibilities);
|
||||||
|
}
|
||||||
|
|
||||||
public function testCombinatorialExpansion(): void
|
public function testCombinatorialExpansion(): void
|
||||||
{
|
{
|
||||||
$dnf = '<?php ($b0 === true && $b4 === true && $b8 === true)
|
$dnf = '<?php ($b0 === true && $b4 === true && $b8 === true)
|
||||||
|
@ -2958,6 +2958,22 @@ class ConditionalTest extends \Psalm\Tests\TestCase
|
|||||||
return $pos;
|
return $pos;
|
||||||
}'
|
}'
|
||||||
],
|
],
|
||||||
|
'usedAssertedVarButNotWithStrongerTypeGuarantee' => [
|
||||||
|
'<?php
|
||||||
|
function broken(bool $b, ?User $u) : void {
|
||||||
|
if ($b || (rand(0, 1) && (!$u || takesUser($u)))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($u) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class User {}
|
||||||
|
|
||||||
|
function takesUser(User $a) : bool {
|
||||||
|
return true;
|
||||||
|
}'
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user