- Notifications
You must be signed in to change notification settings - Fork 545
Recognize constants as constant types #1163
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Obviously this breaks on PHP < 8 💥
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you should run this test only on php8, or/and add an php7 alternative test-case with a different expectation.
src/PhpDoc/TypeNodeResolver.php Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since A and B or similar short-names might be considered a constant in this case, I think tryResolveConstant should at first try whether there is a class defined with this name. Only if not, try whether its actually a constant.
what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, constant can be tried only when it's UPPER_CASE and class of that name does not exist.
| I love it. this kills 2 birds with one stone. it implements phpstan/phpstan#6160 and fixes one of the psalm-special-cases within the conditional-type language phpstan/phpstan#3853 (comment) |
ondrejmirtes left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hate to bring the bad news but:
- I like to resolve constants here to solve phpstan/phpstan#6160
- But I don't think it makes sense to support this in conditional types. The code here reports
int<5, max>: https://phpstan.org/r/853028b5-3d52-4f51-ae64-1655458ef879 So typehintingPHP_MAJOR_VERSIONin a PHPDoc also has to resolve toint<5, max>thanks todynamicConstantNames(https://phpstan.org/config-reference#constants).
Which makes it useless for conditional types. But it's fine for me - having PHP_MAJOR_VERSION conditional in a stub is useful only for built-in PHP functions, and these can be solved by writing code in an extension. I don't want to have a small cosmetic advantage at a cost of doing some horrible hacks to make this work in stubs :)
| Also wildcard support would be a great addition, some people expect that to work (phpstan/phpstan#6972). Needs modification in phpdoc-parser too. |
See phpstan#1163 for discussion. `TypeNodeResolver` needs to be able to resolve constants the same way as `MutatingScope` does
See #1163 for discussion. `TypeNodeResolver` needs to be able to resolve constants the same way as `MutatingScope` does
5b11ca8 to db4d492 Compare
If you don't mind I'd like to tackle that separately. This PR has become quite large enough as-is 🥲 |
| I agree, we can leave the wildcards for a later time :) |
ondrejmirtes left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perfect! Can you please check that NameScope doesn't contain use function uses as they are useless for it?
| Checking the code they probably aren't there thanks to |
src/PhpDoc/TypeNodeResolver.php Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should just be if ($this->getReflectionProvider()->hasClass($stringName)) {.
Because if something looks like a constant FOO_BAR but there's a class FOO_BAR, I want ObjectType of the class, not the constant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should still always result in the class taking precedence, but does a slightly cheaper heuristic check.
It's covered in the test as well: https://github.com/phpstan/phpstan-src/pull/1163/files#diff-f60365c259ff216f4d228e0c46729817e679144be2a7bf2e7395ace7fd344284R47
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it hits that condition:
private function mightBeConstant(string $name): bool { return preg_match('((?:^|\\\\)[A-Z_][A-Z0-9_]*$)', $name) > 0; }This just matches UPPER_CASE names, right? But the constant in question has CamelCaps namespace.
Because when I read that code in case of FOO_BAR the first return new ObjectType($stringName); is skipped because mightBeConstant() === true. And then tryResolveConstant is successful because the constant exists. So constant takes precedence over class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The namespace isn't considered, only the last part of $name (so BAR in that case). If the constant took precedence the type in the test would be 10, instead of the class name (ConstantPhpdocType\BAR).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now it makes sense to me :) I'm ready to merge this, thanks.
It shouldn't because only |
Closes phpstan/phpstan#6160. This was just a wild idea. Probably not the best way forward, but at least it shows the potential
d07a223 to 97f7026 Compare | Thank you! Please send an update to the documentation: https://phpstan.org/writing-php-code/phpdoc-types (add a new section "Global constants"). |
Documentation for phpstan/phpstan-src#1163
| Did you consider introducing a new |
| @vudaltsov You're commenting on a two year old PR. You should open a new feature request and describe your use case. |
Closes phpstan/phpstan#6160. This was just a wild idea. Probably not the best way forward, but at least it shows the potential