diff --git a/src/Psalm/Checker/TypeChecker.php b/src/Psalm/Checker/TypeChecker.php index bba3d8ea6..01fb64bdb 100644 --- a/src/Psalm/Checker/TypeChecker.php +++ b/src/Psalm/Checker/TypeChecker.php @@ -278,6 +278,41 @@ class TypeChecker return Type::getMixed(); } + if ($new_var_type === '!bool' && !$existing_var_type->isMixed()) { + $non_bool_types = []; + $did_remove_type = false; + + foreach ($existing_var_type->types as $type) { + if (!$type instanceof TBool) { + $non_bool_types[] = $type; + } else { + $did_remove_type = true; + } + } + + if ((!$did_remove_type || !$non_bool_types) && !$existing_var_type->from_docblock) { + if ($key && $code_location) { + if (IssueBuffer::accepts( + new RedundantCondition( + 'Found a redundant condition when evaluating ' . $key, + $code_location + ), + $suppressed_issues + )) { + // fall through + } + } + } + + if ($non_bool_types) { + return new Type\Union($non_bool_types); + } + + $failed_reconciliation = true; + + return Type::getMixed(); + } + if ($new_var_type === '!numeric' && !$existing_var_type->isMixed()) { $non_numeric_types = []; $did_remove_type = $existing_var_type->hasString(); @@ -648,6 +683,41 @@ class TypeChecker return Type::getMixed(); } + if ($new_var_type === 'bool' && !$existing_var_type->isMixed()) { + $bool_types = []; + $did_remove_type = false; + + foreach ($existing_var_type->types as $type) { + if ($type instanceof TBool) { + $bool_types[] = $type; + } else { + $did_remove_type = true; + } + } + + if ((!$did_remove_type || !$bool_types) && !$existing_var_type->from_docblock) { + if ($key && $code_location) { + if (IssueBuffer::accepts( + new RedundantCondition( + 'Found a redundant condition when evaluating ' . $key, + $code_location + ), + $suppressed_issues + )) { + // fall through + } + } + } + + if ($bool_types) { + return new Type\Union($bool_types); + } + + $failed_reconciliation = true; + + return Type::getMixed(); + } + $new_type = Type::parseString($new_var_type); if ($existing_var_type->isMixed()) { diff --git a/tests/TypeReconciliationTest.php b/tests/TypeReconciliationTest.php index a17e2ebd6..5580dced6 100644 --- a/tests/TypeReconciliationTest.php +++ b/tests/TypeReconciliationTest.php @@ -425,6 +425,17 @@ class TypeReconciliationTest extends TestCase '$a' => 'string', ], ], + 'typeRefinementWithStringOrTrue' => [ + ' 4 ? "hello" : true; + + if (is_bool($a)) { + exit; + }', + 'assertions' => [ + '$a' => 'string', + ], + ], 'updateMultipleIssetVars' => [ '