diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/CastAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/CastAnalyzer.php index 8bbfd456e5f..f318fa6a10f 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/CastAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/CastAnalyzer.php @@ -45,7 +45,6 @@ use function array_merge; use function array_pop; use function array_values; -use function count; use function get_class; /** @@ -77,12 +76,26 @@ public static function analyze( $valid_int_type = Type::getInt(false, (int)$maybe_type->getSingleStringLiteral()->value); } - if (count($maybe_type->getAtomicTypes()) === 1 - && $maybe_type->getSingleAtomic() instanceof Type\Atomic\TBool) { - $valid_int_type = new Union([ - new TLiteralInt(0), - new TLiteralInt(1), - ]); + if ($maybe_type->hasBool()) { + $casted_type = clone $maybe_type; + if (isset($casted_type->getAtomicTypes()['bool'])) { + $casted_type->addType(new TLiteralInt(0)); + $casted_type->addType(new TLiteralInt(1)); + } else { + if (isset($casted_type->getAtomicTypes()['true'])) { + $casted_type->addType(new TLiteralInt(1)); + } + if (isset($casted_type->getAtomicTypes()['false'])) { + $casted_type->addType(new TLiteralInt(0)); + } + } + $casted_type->removeType('bool'); + $casted_type->removeType('true'); + $casted_type->removeType('false'); + + if ($casted_type->isInt()) { + $valid_int_type = $casted_type; + } } if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph) { diff --git a/tests/CastTest.php b/tests/CastTest.php new file mode 100644 index 00000000000..e14c6680993 --- /dev/null +++ b/tests/CastTest.php @@ -0,0 +1,47 @@ +,ignored_issues?:list,php_version?:string}> + */ + public function providerValidCodeParse(): iterable + { + yield 'castFalseOrIntToInt' => [ + 'code' => ' */ + $intOrFalse = 10; + $int = (int) $intOrFalse; + ', + 'assertions' => [ + '$int===' => '0|int<10, 20>', + ], + ]; + yield 'castTrueOrIntToInt' => [ + 'code' => ' */ + $intOrTrue = 10; + $int = (int) $intOrTrue; + ', + 'assertions' => [ + '$int===' => '1|int<10, 20>', + ], + ]; + yield 'castBoolOrIntToInt' => [ + 'code' => ' */ + $intOrBool = 10; + $int = (int) $intOrBool; + ', + 'assertions' => [ + '$int===' => '0|1|int<10, 20>', + ], + ]; + } +}