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) {
|
||||
if ($var[0] === '*') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if there's only one possible type, return it
|
||||
if (count($clause->possibilities) === 1 && count($possible_types) === 1) {
|
||||
$possible_type = array_pop($possible_types);
|
||||
@ -551,6 +555,13 @@ class Algebra
|
||||
*/
|
||||
public static function negateFormula(array $clauses): array
|
||||
{
|
||||
$clauses = array_filter(
|
||||
$clauses,
|
||||
function ($clause) {
|
||||
return $clause->reconcilable;
|
||||
}
|
||||
);
|
||||
|
||||
if (!$clauses) {
|
||||
$cond_id = \mt_rand(0, 100000000);
|
||||
return [new Clause([], $cond_id, $cond_id, true)];
|
||||
|
@ -350,6 +350,10 @@ class FormulaGenerator
|
||||
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_2
|
||||
* @param array<string, mixed> $new_assigned_var_ids
|
||||
* @param array<string, int> $new_assigned_var_ids
|
||||
*/
|
||||
public static function checkForParadox(
|
||||
array $formula_1,
|
||||
|
@ -307,6 +307,8 @@ class IfAnalyzer
|
||||
$if_scope->if_cond_changed_var_ids = $changed_var_ids;
|
||||
}
|
||||
|
||||
$if_context->reconciled_expression_clauses = [];
|
||||
|
||||
$old_if_context = clone $if_context;
|
||||
$context->vars_possibly_in_scope = array_merge(
|
||||
$if_context->vars_possibly_in_scope,
|
||||
|
@ -120,10 +120,7 @@ class MethodCallPurityAnalyzer
|
||||
&& !$method_storage->mutation_free
|
||||
&& !$method_pure_compatible
|
||||
) {
|
||||
if (!$method_storage->mutation_free) {
|
||||
$statements_analyzer->getSource()->inferred_has_mutation = true;
|
||||
}
|
||||
|
||||
$statements_analyzer->getSource()->inferred_impure = true;
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,19 @@ class AlgebraTest extends TestCase
|
||||
$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
|
||||
{
|
||||
$dnf = '<?php ($b0 === true && $b4 === true && $b8 === true)
|
||||
|
@ -2958,6 +2958,22 @@ class ConditionalTest extends \Psalm\Tests\TestCase
|
||||
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