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

Use isArray, isConstantArray instead of instanceof in TypeCombinartor::union #2118

Merged
merged 9 commits into from Dec 19, 2022

Conversation

rajyan
Copy link
Contributor

@rajyan rajyan commented Dec 16, 2022

Refactored union of ArrayTypes by extracting processArrayAccessoryTypes as a private function.
Also, changed to use isArray isConstantArray instead of instanceof ArrayType.

I think we can apply the bucket idea of phpstan/phpstan#8499 if we filter ArrayTypes, ConstantIntegerTypes|IntegerRangeType and union them before creating buckets.

@@ -239,7 +239,7 @@ public function getLastIterableValueType(): Type

public function isArray(): TrinaryLogic
{
return TrinaryLogic::createYes();
return TrinaryLogic::createMaybe();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't checked the rest of this PR but this is certainly wrong. If something is a list then we know it's an array...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand you're changing this so that some other algorithm results in an outcome we want, but the typesystem layer always has to tell the truth, otherwise something else breaks...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't checked the rest of this PR but this is certainly wrong. If something is a list then we know it's an array...

I thought that AccessoryType themselves are not isArray, they have to be always intersected with an array, but looking at the failing test, this assumption seems false as you are saying...

I can solve this PR without this change, I just wanted to check what fails with this :) (at least the tests didn't fail, maybe we need some regression tests)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm likely to accept whatever you come up with, but make sure to do some benchmarks too :) It's really easy to think you've sped things up, but in reality you might have slowed them down :) Thanks.

@rajyan
Copy link
Contributor Author

rajyan commented Dec 17, 2022

I tried to just refactor and keep the original behavior, but there seems to be a slight difference somewhere...

@rajyan
Copy link
Contributor Author

rajyan commented Dec 17, 2022

╭─ ~/Contribution/phpstan-src  refactor-union *2 !1 ···································· 1 ✘  4s  22:01:50 
╰─ hyperfine 'bin/phpstan analyse src/Analyser/NodeScopeResolver.php src/Analyser/MutatingScope.php'
Benchmark 1: bin/phpstan analyse src/Analyser/NodeScopeResolver.php src/Analyser/MutatingScope.php
  Time (mean ± σ):      9.168 s ±  0.106 s    [User: 8.924 s, System: 0.195 s]
  Range (min … max):    9.056 s …  9.407 s    10 runs
 
╭─ ~/Contribution/phpstan-src  refactor-union *2 ·············································· ✔  22:06:01 
╰─ git switch 1.9.x
Switched to branch '1.9.x'
Your branch is up to date with 'origin/1.9.x'.
╭─ ~/Contribution/phpstan-src  1.9.x *2 ······················································· ✔  22:06:04 
╰─ hyperfine 'bin/phpstan analyse src/Analyser/NodeScopeResolver.php src/Analyser/MutatingScope.php'
Benchmark 1: bin/phpstan analyse src/Analyser/NodeScopeResolver.php src/Analyser/MutatingScope.php
  Time (mean ± σ):      9.754 s ±  0.070 s    [User: 9.481 s, System: 0.214 s]
  Range (min … max):    9.696 s …  9.893 s    10 runs

I believe this refactor should have a slight performance improvement as I expected, because number of union calls has been decreased.

@rajyan
Copy link
Contributor Author

rajyan commented Dec 19, 2022

╭─ ~/Contribution/phpstan-src  refactor-union *2 ··· INT ✘  30s  09:53:14 
╰─ hyperfine 'bin/phpstan analyse src/Analyser/NodeScopeResolver.php src/Analyser/MutatingScope.php'
Benchmark 1: bin/phpstan analyse src/Analyser/NodeScopeResolver.php src/Analyser/MutatingScope.php
  Time (mean ± σ):      9.121 s ±  0.069 s    [User: 8.884 s, System: 0.190 s]
  Range (min … max):    9.055 s …  9.259 s    10 runs
 
╭─ ~/Contribution/phpstan-src  refactor-union *2 ···· ✔  1m 31s  09:54:46 
╰─ git switch 1.9.x
Switched to branch '1.9.x'
Your branch is up to date with 'origin/1.9.x'.
╭─ ~/Contribution/phpstan-src  1.9.x *2 ······················ ✔  09:54:53 
╰─ hyperfine 'bin/phpstan analyse src/Analyser/NodeScopeResolver.php src/Analyser/MutatingScope.php'
Benchmark 1: bin/phpstan analyse src/Analyser/NodeScopeResolver.php src/Analyser/MutatingScope.php
  Time (mean ± σ):      9.160 s ±  0.061 s    [User: 8.921 s, System: 0.185 s]
  Range (min … max):    9.067 s …  9.271 s    10 runs
 
  Warning: The first benchmarking run for this command was significantly slower than the rest (9.271 s). This could be caused by (filesystem) caches that were not filled until after the first run. You should consider using the '--warmup' option to fill those caches before the actual benchmark. Alternatively, use the '--prepare' option to clear the caches before each timing run.

This is the final performance comparison.
This PR is preparation for #2078 looks like there isn't a significant performance improvement.

@rajyan rajyan changed the title Refactor union Use isArray, isConstantArray instead of instanceof in TypeCombinartor::union Dec 19, 2022
@rajyan rajyan marked this pull request as ready for review December 19, 2022 01:00
@phpstan-bot
Copy link
Collaborator

This pull request has been marked as ready for review.

Comment on lines -221 to -239
$arrayTypes = $arrayTypes;

$commonArrayAccessoryTypesKeys = [];
if (count($arrayAccessoryTypes) > 1) {
$commonArrayAccessoryTypesKeys = array_keys(array_intersect_key(...$arrayAccessoryTypes));
} elseif (count($arrayAccessoryTypes) > 0) {
$commonArrayAccessoryTypesKeys = array_keys($arrayAccessoryTypes[0]);
}

$arrayAccessoryTypesToProcess = [];
foreach ($commonArrayAccessoryTypesKeys as $commonKey) {
$typesToUnion = [];
foreach ($arrayAccessoryTypes as $array) {
foreach ($array[$commonKey] as $arrayAccessoryType) {
$typesToUnion[] = $arrayAccessoryType;
}
}
$arrayAccessoryTypesToProcess[] = self::union(...$typesToUnion);
}
Copy link
Contributor Author

@rajyan rajyan Dec 19, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this logic is replaced by count($arrayType) === count($accessoryType[$key]) in
https://github.com/phpstan/phpstan-src/pull/2118/files#diff-fef252fe8071200a31b3d282d1442135d62297098c9b20fd731f3888398ee973R549-R562

also, there is no need to union accessoryTypes except HasOffsetValueType, because the types are all the same.

@ondrejmirtes ondrejmirtes merged commit 679538e into phpstan:1.9.x Dec 19, 2022
@ondrejmirtes
Copy link
Member

Thank you!

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