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
Implement OversizedArrayVisitor to improve huge constant array performance #2116
Conversation
it needs a few fixes for existing tests, but what do you think about the approach in general? |
Can you explain your reasoning behind this code? I don't entirely understand it. |
the idea is, that phpstan is slow when analyzing huge arrays, like gist because it tries to get the most precise result. we already have an OversizedArrayType, but it works in a way that it needs to build up the constant array using ConstantTypes and then collapsing it into a OversizedArrayType, after realizing its too big. in huge cases even the steps to build up the Constant types and collapse them into OversizedArrayType already takes minutes. this PR tries to add a very lightweight, but imprecise type inference when very big constant arrays are analyzed. see the blackfire profile of said gist, where we are super slow because of the sheer number of constant-integer types invovled |
I need at least 1) and 3) to be true. I understand that 2) might be a different problem. |
runs locally in 13 seconds. on the latest 1.9.x-dev it runs in 1min 18 secs.
I don't think this counts as a constant array in a sense this Visitor could improve. analyzing this source requires a already built up scope, or at least knowledge about the returned types of methods.
I will work on this one now |
ef9f751
to
c3955a3
Compare
src/Analyser/TypeSpecifier.php
Outdated
@@ -1080,31 +1076,7 @@ private function specifyTypesForConstantStringBinaryExpression( | |||
&& strtolower($exprNode->name->toString()) === 'gettype' | |||
&& isset($exprNode->getArgs()[0]) | |||
) { | |||
$type = null; | |||
if ($constantType->getValue() === 'string') { |
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.
extracted into new helper for re-use in new visitor
04ea982
to
a732639
Compare
This pull request has been marked as ready for review. |
19f2442
to
b33c3cc
Compare
b33c3cc
to
500ae8a
Compare
51baa57
to
36e9381
Compare
This pull request has been marked as ready for review. |
fails because I have removed a |
phpstan/phpstan#8215 sees a ~25x improvement
phpstan/phpstan#8146 (comment) sees a 2x improvement
|
I don't get what's exactly happening in the visitor, it's a lot of code. And I don't think it has to be a visitor, to me it looks like it's essentially caching for something that could be in InitializerExprTypeResolver where Array_ type is resolved. |
ohh thats a good point. let me see whether I can get rid of the Visitor. |
great suggestion, it got even simpler now. |
This pull request has been marked as ready for review. |
e972230
to
690a128
Compare
$isList = false; | ||
|
||
$itemKeyType = $getTypeCallback($key); | ||
if (!$itemKeyType instanceof ConstantScalarType || $key instanceof ClassConstFetch) { |
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.
We skip const class fetch, as I was not able to make ArrayType accept a OversizedArrayType with reduced precision when using Constant enumerations like self::SOME_*
.
See failing test when removing this check
} | ||
|
||
$itemValueType = $getTypeCallback($value); | ||
if (!$itemValueType instanceof ConstantScalarType || $value instanceof ClassConstFetch) { |
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 we could also add support for arrays where const arrays call methods/functions as long as the return type is defined.
example:
…
public function getData(): array
{
return [
'Bács-Kiskun' => [
'Ágasegyháza' => [
'constituencies' => ['Bács-Kiskun 4.'],
'coordinates' => ['lat' => 46.8386043, 'lng' => 19.4502899],
],
$this->returnsString() => [
'constituencies' => ['Bács-Kiskun 3.'],
'coordinates' => ['lat' => 46.6898175, 'lng' => 19.205086],
],
'Apostag' => [
'constituencies' => ['Bács-Kiskun 3.'],
'coordinates' => ['lat' => 46.8812652, 'lng' => $this->returnsFloat()],
],
I did not yet work on it, as I think we are still discussing whether the change itself is acceptable.
I just pushed a simplification of the buildDegradedConstantArray method as I imagine it should work. A few problems with it though - some tests fail. I think that we'll have to modify not only accepts, but Also - it's not always correct. When |
761c269
to
905a21f
Compare
Hi, I'm taking over this PR and I'll try to finish it. Thanks. |
I tried several things which didn't work. Thanks for taking it |
9ebf4a4
to
1573a79
Compare
@@ -809,4 +809,15 @@ public function testBug8223(): void | |||
]); | |||
} | |||
|
|||
public function testBug8146b(): void |
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.
nit: I misstyped the testname
public function testBug8146b(): void | |
public function testBug8146c(): void |
248dd35
to
7d40377
Compare
7d40377
to
f1e0ed2
Compare
This pull request has been marked as ready for review. |
Thank you. |
Thank you 🙏 |
Do you think we can disable this new behavior? Now, my huge const is oversimplified and the array shape is not guessed as precisely as before. |
@ddebin Please open a new issue and make sure to include a code sample. |
implements the idea described in phpstan/phpstan#8215 (comment)
closes phpstan/phpstan#8215
with this fix, the snippet is analyzable in 2 seconds, while it takes several minutes before.