-
Notifications
You must be signed in to change notification settings - Fork 550
Preserve constant array when setting a union of constant scalar keys #4520
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
base: 2.1.x
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -693,6 +693,20 @@ public function getOffsetValueType(Type $offsetType): Type | |
|
|
||
| public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = true): Type | ||
| { | ||
| if ($offsetType !== null) { | ||
| $constantScalars = $offsetType->getConstantScalarTypes(); | ||
| $constantScalarsCount = count($constantScalars); | ||
| if ($constantScalarsCount > 1 && $constantScalarsCount < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need similar handling for integer ranges with less than array-limit elements?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that would make sense! |
||
| $arrays = []; | ||
| foreach ($constantScalars as $constantScalar) { | ||
| $builder = ConstantArrayTypeBuilder::createFromConstantArray($this); | ||
| $builder->setOffsetValueType($constantScalar, $valueType); | ||
| $arrays[] = $builder->getArray(); | ||
| } | ||
|
|
||
| return TypeCombinator::union(...$arrays); | ||
| } | ||
| } | ||
|
Comment on lines
696
to
709
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder, whether this code should be moved into the impl of
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should be handled there but this code should not be copied, but adapted (it's not so easy to do it there). I just wanted to try a quick PoC first. |
||
| $builder = ConstantArrayTypeBuilder::createFromConstantArray($this); | ||
| $builder->setOffsetValueType($offsetType, $valueType); | ||
|
|
||
|
|
@@ -701,6 +715,19 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $uni | |
|
|
||
| public function setExistingOffsetValueType(Type $offsetType, Type $valueType): Type | ||
| { | ||
| $constantScalars = $offsetType->getConstantScalarTypes(); | ||
| $constantScalarsCount = count($constantScalars); | ||
| if ($constantScalarsCount > 1 && $constantScalarsCount < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT) { | ||
| $arrays = []; | ||
| foreach ($constantScalars as $constantScalar) { | ||
| $builder = ConstantArrayTypeBuilder::createFromConstantArray($this); | ||
| $builder->setOffsetValueType($constantScalar, $valueType); | ||
| $arrays[] = $builder->getArray(); | ||
| } | ||
|
|
||
| return TypeCombinator::union(...$arrays); | ||
| } | ||
|
|
||
| $builder = ConstantArrayTypeBuilder::createFromConstantArray($this); | ||
| $builder->setOffsetValueType($offsetType, $valueType); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| <?php | ||
|
|
||
| namespace SetConstantUnionOffsetOnConstantArray; | ||
|
|
||
| use function PHPStan\Testing\assertType; | ||
|
|
||
| class Foo | ||
| { | ||
|
|
||
| /** | ||
| * @param array{foo: int} $a | ||
| */ | ||
| public function doFoo(array $a): void | ||
| { | ||
| $k = rand(0, 1) ? 'a' : 'b'; | ||
| $a[$k] = 256; | ||
| assertType('array{foo: int, a: 256}|array{foo: int, b: 256}', $a); | ||
| } | ||
|
|
||
| } |
Uh oh!
There was an error while loading. Please reload this page.
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.
looking at this
unionValuesparameter, makes me feel we nearly everytime ignore it.I wonder whether this bool represents the same 2 use-cases as
setOffsetValueType()vs.setExistingOffsetValueType().like
unionValues=trueis the same assetOffsetValueType()and
unionValues=falseis the same assetExistingOffsetValueType()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 unionValues parameter is some hack I came up with, there's no deeper thought in it and it's likely the proper solution is different.
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.
What is the purpose of this hack ?
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 did some research yesterday. it was introduced with 5d64483