psalm icon indicating copy to clipboard operation
psalm copied to clipboard

Bug during initialization - TIntRange::contains(): Argument #1 ($i) must be of type int, float given

Open stefanak-michal opened this issue 11 months ago • 7 comments

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)

stefanak-michal avatar Jan 27 '25 10:01 stefanak-michal

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.

psalm-github-bot[bot] avatar Jan 27 '25 10:01 psalm-github-bot[bot]

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

stefanak-michal avatar Jan 27 '25 10:01 stefanak-michal

it's problem with using number -9223372036854775808. Php automatically use it as double, but psalm look at it as int.

stefanak-michal avatar Jan 27 '25 12:01 stefanak-michal

Minimal reproducer: https://psalm.dev/r/ae89633509

orklah avatar Jan 28 '25 19:01 orklah

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

psalm-github-bot[bot] avatar Jan 28 '25 19:01 psalm-github-bot[bot]

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

GromNaN avatar Sep 02 '25 07:09 GromNaN

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.

GromNaN avatar Sep 08 '25 07:09 GromNaN