Skip to content

Conversation

@VincentLanglet
Copy link
Contributor

@VincentLanglet VincentLanglet commented Oct 4, 2022

Closes phpstan/phpstan#8088

The dynamic extensions was considering

array<0|1|2|3|4|5|6|7|8|9>

and

array{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

as the same

@VincentLanglet VincentLanglet changed the title Fix min max call on union types Fix min max call on array of union types Oct 4, 2022
@VincentLanglet VincentLanglet changed the title Fix min max call on array of union types [Closes 8088] Fix min max call on array of union types Oct 4, 2022
@VincentLanglet VincentLanglet changed the title [Closes 8088] Fix min max call on array of union types [Closes #8088] Fix min max call on array of union types Oct 4, 2022
@VincentLanglet VincentLanglet marked this pull request as ready for review October 4, 2022 19:31
Copy link
Member

Choose a reason for hiding this comment

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

This isn't gonna work if you have union of constant arrays. Please test that scenario + fix it with TypeUtils::getOldConstantArrays().

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 wasn't sure how you wanted that I use getOldConstantArrays.

I handled UnionType in a different way and added a test. Tell me if this is ok this way.

Copy link
Member

Choose a reason for hiding this comment

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

It's not OK, please do not use any instanceof *Type. Use TypeUtils::getOldConstantArrays() and iterate over the array of types.

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 tried a solution with getOldConstantArrays now.
But this seems more complicated to me.

Copy link
Member

Choose a reason for hiding this comment

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

I suspect this if/else is no longer necessary.

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 just tried, and if I only keep the if part, tests crash, and if I only keep the else part, test fails.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can you explain how you want the code changed @ondrejmirtes ? Because I didn't succeed having my test green as soon as I touch this if/else.

Copy link
Member

Choose a reason for hiding this comment

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

Any code that does instanceof *Type is suspicious to me. Just try deleting this piece of code and see what tests fail. And try fixing them in another way.

Recently we've been adding specific methods on Type. It also means that if you rebase on top of 1.9.x, some methods you're currently using will show up as deprecated.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do i need to retarget to 1.9.x ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, this isn't how I imagine and manage quality software development. The fix needs to make sense and is easier to do once the knowledge of the specific area is already in your headspace.

I'll be more than happy to find another way to write this code but I'll need more help then. Because I didn't understood everything during this discussion. You said "Recently we've been adding specific methods on Type" and "we need a specific method for min/max" so do you want me to add a new method to types ? What should it does ?

Copy link
Member

Choose a reason for hiding this comment

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

@herndlm can help answering that but usually you check recent merged PR history and also the above discussion to get the idea.

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 saw Pr like #1869 which introduced a new method.

My main concern was about the method to introduce.
I thought about introducing a getTypes method to all the Type, in order to write:

foreach ($iterableValueType->getTypes() as $innerType) {
    $argumentTypes[] = $innerType;
}

But i'm not sure you will like this solution.

You said "we need a specific method for min/max" but at first sight that would mean reproducing/duplicating part of the logic from MinMaxFunctionReturnTypeExtension::processType/compareTypes in every types.

Copy link
Contributor

Choose a reason for hiding this comment

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

sorry, I didn't fully dive into this yet, but it sounds like you can add a Type::max(Types ...$types): Type and min methods. moving it to type often could mean slight duplications, but the core logic for arrays should then be split into ArrayType and ConstantArrayType and we automatically add support for unions and e.g. don't need Type::getConstantArrays() & co anymore. The other types are mostly covered via the array traits and we need to think explicitly how the array accessory types like HasOffsetType should behave. it is possible then to simply add code for them as well via the new methods.

I didn't think through yet how you can solve the iterableValueType problem that seems to be here. because it sounds like it would just be moved somewhere else. but you have then max and min methods on type, so maybe that helps somehow. since max and min don't only handle arrays, it means most likely that other types need to implement too somehow, I have no clue yet how, so I'm not sure if that helps much here. Maybe you also need minArray() and maxArray() methods on type and want to keep the rest here. again, I didn't dive into this, sorry

Copy link
Contributor Author

Choose a reason for hiding this comment

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

how you can solve the iterableValueType problem

The previous logic was

  • If it's an Array
    • if the IterableValueType is an UnionType, iterate over the types.
    • else take the iterableValueType like this.

The logic I neeeded to implements in the ReturnTypeExtension is

  • If it's a ConstantArray
    • if the IterableValueType is an UnionType, iterate over the types.
    • else take the iterableValueType like this.
  • If it's just an Array
    • take the iterableValueType like this.

I just discovered in case it's a ConstantArray, it could just be replaced by the getValueTypes method !

@VincentLanglet
Copy link
Contributor Author

Do you mind taking a new look @ondrejmirtes ? I tried to remove the if part as asked without success, Am I doing something wrong ?

@VincentLanglet VincentLanglet changed the base branch from 1.8.x to 1.9.x October 18, 2022 06:59
@VincentLanglet VincentLanglet marked this pull request as draft October 18, 2022 06:59
@VincentLanglet VincentLanglet marked this pull request as ready for review October 18, 2022 07:36
@phpstan-bot
Copy link
Collaborator

This pull request has been marked as ready for review.

}
} else {
$argumentTypes[] = $iterableValueType;
foreach ($constArrayType->getValueTypes() as $innerType) {
Copy link
Member

Choose a reason for hiding this comment

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

Finally! This is what I meant that you don't need UnionType here anymore. I'm happy to merge this if the build is green.

@ondrejmirtes ondrejmirtes changed the title [Closes #8088] Fix min max call on array of union types Fix min max call on array of union types Oct 19, 2022
@ondrejmirtes ondrejmirtes merged commit d347eb6 into phpstan:1.9.x Oct 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

Development

Successfully merging this pull request may close these issues.

Wrong int inference after a max call.

4 participants