Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type inference issue when using arithmetic assignments #11241

Open
KevinVanSonsbeek opened this issue Feb 4, 2025 · 4 comments
Open

Type inference issue when using arithmetic assignments #11241

KevinVanSonsbeek opened this issue Feb 4, 2025 · 4 comments

Comments

@KevinVanSonsbeek
Copy link
Contributor

When upgrading to Psalm 6 we've noticed some new errors in the codebase.

Which seem to be caused by psalm incorrectly tracking the type of a variable, if it is created as an integer, and then updated through arithmetic addition or subtraction assignments.

See
https://psalm.dev/r/6385ed8d8d
and
https://psalm.dev/r/c9b1c78210

This problem only seems to happen during addition and subtraction though. The other types of arithmetic assignments change the type of the variable back to either int or float|int.

Copy link

I found these snippets:

https://psalm.dev/r/6385ed8d8d
<?php

$var1 = 15;
/** @psalm-trace $var1 */

function getRandomIntOrNull(): int|null
{
    $int = random_int(0, 10);
    if ($int < 5) {
        return null;
    }
    
    return 5;
}

$var1 -= getRandomIntOrNull() ?? 0;
/** @psalm-trace $var1 */

if ($var1 === 15) {
    echo "No value subtracted";
}
Psalm output (using commit 53140ea):

INFO: Trace - 6:1 - $var1: 15

ERROR: TypeDoesNotContainType - 19:5 - 15 cannot be identical to 14

ERROR: TypeDoesNotContainType - 19:5 - Type 14 for $var1 is never =int(15)

INFO: Trace - 19:1 - $var1: 14
https://psalm.dev/r/c9b1c78210
<?php

$var1 = 15;
/** @psalm-trace $var1 */

function getRandomIntOrNull(): int|null
{
    $int = random_int(0, 10);
    if ($int < 5) {
        return null;
    }
    
    return 5;
}

$var1 += getRandomIntOrNull() ?? 0;
/** @psalm-trace $var1 */

if ($var1 === 15) {
    echo "No value added";
}
Psalm output (using commit 53140ea):

INFO: Trace - 6:1 - $var1: 15

ERROR: TypeDoesNotContainType - 19:5 - 15 cannot be identical to 16

ERROR: TypeDoesNotContainType - 19:5 - Type 16 for $var1 is never =int(15)

INFO: Trace - 19:1 - $var1: 16

@KevinVanSonsbeek KevinVanSonsbeek changed the title Variable type incorrectly tracked when var is assigned as int, and changed through arithmetic assignments. Type inference issue when using arithmetic assignments Feb 5, 2025
@orklah
Copy link
Collaborator

orklah commented Feb 5, 2025

Oh yeah that's weird, Psalm seems to assume any integer is 1 for these operations: https://psalm.dev/r/bda522d385

Copy link

I found these snippets:

https://psalm.dev/r/bda522d385
<?php

$var1 = 15;
/** @psalm-trace $var1 */;

function getRandomInt(): int
{
    return 5;
}

$var1 += getRandomInt();
/** @psalm-trace $var1 */;

$var1 -= getRandomInt();
/** @psalm-trace $var1 */;
Psalm output (using commit c105211):

INFO: Trace - 4:26 - $var1: 15

INFO: Trace - 12:26 - $var1: 16

INFO: Trace - 15:26 - $var1: 15

INFO: UnusedVariable - 3:1 - $var1 is never referenced or the value is not used

INFO: UnusedVariable - 11:1 - $var1 is never referenced or the value is not used

INFO: UnusedVariable - 14:1 - $var1 is never referenced or the value is not used

@orklah orklah added the bug label Feb 5, 2025
@orklah
Copy link
Collaborator

orklah commented Feb 5, 2025

Pretty sure the issue is here: https://github.com/vimeo/psalm/blob/6.x/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ArithmeticOpAnalyzer.php#L826

We assume that VirtualPlus and VirtualMinus are only used for things like $a++ or $a-- but an expression like $a -= $b must also use those.

What we should do is check for additional operands to see if there is a real type to be handled after the operator

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants