Bug during initialization - TIntRange::contains(): Argument #1 ($i) must be of type int, float given
Hi.
I installed psalm v6 and when I try to initialize I receive following error:
C:\dev\apache\Bolt>vendor\bin\psalm --init
Calculating best config level based on project files
Calculating best config level based on project files
JIT acceleration: OFF (disabled on Windows and PHP < 8.4)
Install PHP 8.4+ to make use of JIT on Windows for a 20%+ performance boost!
Target PHP version: 8.1 (inferred from composer.json).
Scanning files...
279 / 279...
Analyzing files...
E░E░EEE░░░░░░░░EEEE░░Uncaught TypeError: Psalm\Type\Atomic\TIntRange::contains(): Argument #1 ($i) must be of type int, float given, called in C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Internal\Type\SimpleAssertionReconciler.php on line 1979 and defined in C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Type\Atomic\TIntRange.php:73
Stack trace:
#0 C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Internal\Type\SimpleAssertionReconciler.php(1979): Psalm\Type\Atomic\TIntRange->contains(9.2233720368548E+18)
#1 C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Internal\Type\SimpleAssertionReconciler.php(163): Psalm\Internal\Type\SimpleAssertionReconciler::reconcileIsGreaterThan(Object(Psalm\Storage\Assertion\IsGreaterThan), Object(Psalm\Type\MutableUnion), false, 'int<min, max>', '$value', true, NULL, Array)
#2 C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Internal\Type\AssertionReconciler.php(180): Psalm\Internal\Type\SimpleAssertionReconciler::reconcile(Object(Psalm\Storage\Assertion\IsGreaterThan), Object(Psalm\Codebase), Object(Psalm\Type\Union), '$value', true, NULL, Array, 0, false)
#3 C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Type\Reconciler.php(277): Psalm\Internal\Type\AssertionReconciler::reconcile(Object(Psalm\Storage\Assertion\IsGreaterThan), Object(Psalm\Type\Union), '$value', Object(Psalm\Internal\Analyzer\StatementsAnalyzer), false, Array, NULL, Array, 0, true)
#4 C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Internal\Analyzer\Statements\Expression\BinaryOp\OrAnalyzer.php(229): Psalm\Type\Reconciler::reconcileKeyedTypes(Array, Array, Array, Array, Array, Array, Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Array, false, Object(Psalm\CodeLocation), true)
#5 C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Internal\Analyzer\Statements\Expression\BinaryOpAnalyzer.php(85): Psalm\Internal\Analyzer\Statements\Expression\BinaryOp\OrAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\BinaryOp\BooleanOr), Object(Psalm\Context), false)
#6 C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer.php(288): Psalm\Internal\Analyzer\Statements\Expression\BinaryOpAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\BinaryOp\BooleanOr), Object(Psalm\Context), 0, false)
#7 C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer.php(92): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::handleExpression(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\BinaryOp\BooleanOr), Object(Psalm\Context), false, NULL, NULL, NULL, false)
#8 C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Internal\Analyzer\Statements\Block\IfConditionalAnalyzer.php(118): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\BinaryOp\BooleanOr), Object(Psalm\Context))
#9 C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Internal\Analyzer\Statements\Block\IfElse\ElseIfAnalyzer.php(62): Psalm\Internal\Analyzer\Statements\Block\IfConditionalAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\BinaryOp\BooleanOr), Object(Psalm\Context), Object(Psalm\Codebase), Object(Psalm\Internal\Scope\IfScope), 4662)
#10 C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Internal\Analyzer\Statements\Block\IfElseAnalyzer.php(283): Psalm\Internal\Analyzer\Statements\Block\IfElse\ElseIfAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\ElseIf_), Object(Psalm\Internal\Scope\IfScope), Object(Psalm\Context), Object(Psalm\Context), Object(Psalm\Codebase), 4662)
#11 C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Internal\Analyzer\StatementsAnalyzer.php(511): Psalm\Internal\Analyzer\Statements\Block\IfElseAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\If_), Object(Psalm\Context))
#12 C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Internal\Analyzer\StatementsAnalyzer.php(191): Psalm\Internal\Analyzer\StatementsAnalyzer::analyzeStatement(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\If_), Object(Psalm\Context), Object(Psalm\Context))
#13 C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Internal\Analyzer\FunctionLikeAnalyzer.php(508): Psalm\Internal\Analyzer\StatementsAnalyzer->analyze(Array, Object(Psalm\Context), Object(Psalm\Context), true)
#14 C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Internal\Analyzer\ClassAnalyzer.php(1823): Psalm\Internal\Analyzer\FunctionLikeAnalyzer->analyze(Object(Psalm\Context), Object(Psalm\Internal\Provider\NodeDataProvider), Object(Psalm\Context))
#15 C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Internal\Analyzer\ClassAnalyzer.php(447): Psalm\Internal\Analyzer\ClassAnalyzer->analyzeClassMethod(Object(PhpParser\Node\Stmt\ClassMethod), Object(Psalm\Storage\ClassLikeStorage), Object(Psalm\Internal\Analyzer\ClassAnalyzer), Object(Psalm\Context), Object(Psalm\Context))
#16 C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Internal\Analyzer\FileAnalyzer.php(197): Psalm\Internal\Analyzer\ClassAnalyzer->analyze(Object(Psalm\Context), Object(Psalm\Context))
#17 C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Internal\Codebase\Analyzer.php(1583): Psalm\Internal\Analyzer\FileAnalyzer->analyze()
#18 C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Internal\Codebase\Analyzer.php(514): Psalm\Internal\Codebase\Analyzer->analysisWorker(21, 'C:\\dev\\apache\\B...')
#19 C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Internal\Codebase\Analyzer.php(264): Psalm\Internal\Codebase\Analyzer->doAnalysis(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 1)
#20 C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Internal\Analyzer\ProjectAnalyzer.php(530): Psalm\Internal\Codebase\Analyzer->analyzeFiles(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 1, false, true)
#21 C:\dev\apache\Bolt\vendor\vimeo\psalm\src\Psalm\Internal\Cli\Psalm.php(383): Psalm\Internal\Analyzer\ProjectAnalyzer->check('C:\\dev\\apache\\B...', true)
#22 C:\dev\apache\Bolt\vendor\vimeo\psalm\psalm(9): Psalm\Internal\Cli\Psalm::run(Array)
#23 C:\dev\apache\Bolt\vendor\bin\psalm(119): include('C:\\dev\\apache\\B...')
#24 {main}
(Psalm 6.0.0@b8e96bb617bf59382113b1b56cef751f648a7dc9 crashed due to an uncaught Throwable)
Hey @stefanak-michal, can you reproduce the issue on https://psalm.dev? These will be used as phpunit tests when implementing the feature or fixing this bug.
By testing each file separately I found out this error is thrown at this file: https://github.com/neo4j-php/Bolt/blob/master/src/packstream/v1/Packer.php
it's problem with using number -9223372036854775808. Php automatically use it as double, but psalm look at it as int.
Minimal reproducer: https://psalm.dev/r/ae89633509
I found these snippets:
https://psalm.dev/r/ae89633509
<?php
function packInteger(int $value)
{
if ($value >= 0) {}
elseif ($value <= 9223372036854775807) {}
}
Psalm encountered an internal error:
/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TIntRange.php: Psalm\Type\Atomic\TIntRange::contains(): Argument #1 ($i) must be of type int, float given, called in /vendor/vimeo/psalm/src/Psalm/Internal/Type/SimpleAssertionReconciler.php on line 1979
We hit the same issue in Symfony with this lines:
if ($unsigned64 >= (1 << 63)) {
$unsigned64 -= (1 << 64);
}
Version: Psalm dev-master@cdceda044f0255e4eb1da0557ff1479e6d317e01
Uncaught PsalmPhar\Amp\Parallel\Worker\TaskFailureError: TypeError thrown in context with message "Psalm\Type\Atomic\TIntRange::__construct(): Argument #2 ($max_bound) must be of type ?int, float given
In this line: https://github.com/vimeo/psalm/blob/279f3eab037923d3f9d3ea3de1a16b425653e30c/src/Psalm/Internal/Type/SimpleAssertionReconciler.php#L2073
If $assertion->value === PHP_INT_MIN, then $assertion->value - 1 is converted to float.
Same thing in
https://github.com/vimeo/psalm/blob/279f3eab037923d3f9d3ea3de1a16b425653e30c/src/Psalm/Internal/Type/SimpleAssertionReconciler.php#L1965
If $assertion->value === PHP_INT_MAX, then $assertion->value + 1 is converted to float.