psalm: False positive: mixed is a reserved word

Reproducer: https://github.com/derrabus/psalm-mixed-reproducer

When installing Symfony Cache 6 in a project, I get a strange error:

ERROR: ReservedWord - src/MyClass.php:12:19 - mixed is a reserved word (see https://psalm.dev/095)
        if (1 === $cache->getItem(__FUNCTION__)->get()) {

As you can see, the highlighted code does not contain the mixed keyword at all.

If I downgrade Symfony cache to 5.4, the error is gone.

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 19 (5 by maintainers)

Commits related to this issue

Most upvoted comments

Say, if we checked minimum PHP versions allowed by all installed dependencies and added a notice if they are higher then the inferred target version - would it have helped?

This could have helped understand the issue, but not fixing it. For now, the only fix I see is either ignoring the error in the config as done by Doctrine, or analysing the project based on the current PHP version (with which the deps are compatible).

Alternatively, what if we defaulted to the PHP version Psalm runs with, but added a notice saying that your project should also check with the lowest version it specifies in composer.json?

if you cannot parse the dependencies based on their own min PHP version, this looks like the best behavior, as it will produce a working analysis. We should still find a way for this warning to be opted-out IMO, so that projects running multiple CI jobs on different PHP versions can disable this warning (as they are doing that check in the other CI job)

Please note that the feature that takes the min php version from composer.json was just designed for ease of use, especially for users that are beginners in using Psalm and don’t have yet all the configs in mind.

It is just a default php version that makes sense for a lot of users to analyse with.

Now the case for libraries is different. In a majority of cases, the library have to support more than one version of PHP and may want to be forward compatible.

If that’s the case, there is more than keywords that can change in dependencies. Old versions of dependencies may have a completely different API, or simply a different param type or return type.

It feels weird to focus on the fact that mixed is not really a reserved keyword and not consider at all that, if the dependencies were really installed in PHP 7.3, the param that’s mixed in PHP 8.1 could have been a string at that time.

tl;dr: If you run Psalm in version 7.3 against PHP 8.1 dependencies, Psalm may miss a lot of issues. I think a sane way to approach this would be to run composer with --prefer-lowest and analyse with 7.3, then run normally and analyse with 8.1.

But shouldn’t I rather be getting an error telling me that strictly comparing an instance of that mixed class to an integer is pointless.

I suppose you would get that error if class existed, and wasn’t named ‘mixed’. Psalm just thinks it found a more serious issue that makes reporting other potential issues in that expression superfluous.

Reporting UndefinedClass here would be technically correct, but I guess it was judged that errors like ‘UndefinedClass: class void does not exist’ were too confusing (similar to https://3v4l.org/qktSv#v7.0.33), and it was better to flag potential keywords with a separate issue type (this also allows you to selectively suppress it).

symfony/cache:6 is PHP8 only, right? But your project is set to check against 7.4.

Right, but then again, Psalm is supposed to check my code for errors and not the dependencies’. Also, it is odd that this is the only error reported: Symfony 6 uses quite some more PHP 8 language features, why is Psalm complaining about the mixed type only?

If you want a more real-life example, we’ve found this in the CI of https://github.com/doctrine/dbal. Here, the codebase has to remain compatible with PHP 7.3, but allows dependencies that operate on a higher language level.

Running with --php-version=8.0 gets rid of the issue.

But this is not what I want. If my codebase would really use the mixed keyword, I certainly want to know. Should I run Psalm twice with different sets of dependencies or what would your recommondation be in that regard?

I don’t think there’s anything to fix here

Even if I was just using the tool wrong, I still believe that the output should be different:

  • Psalm reports an error that originates in one of my dependencies.
  • Psalm highlights a piece of code that is perfectly fine.