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
Make IntegerRangeType->isSubTypeOf analyse Unions #416
Conversation
1fc2d6d
to
40ea36d
Compare
yield [ | ||
IntegerRangeType::fromInterval(5, 10), | ||
new UnionType([new IntegerType(), new StringType()]), | ||
TrinaryLogic::createYes(), |
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.
It sounds to me like the correct answer here is 'maybe', since the second type might be a string, in which case an integer is not a sub-type of it.
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 int<5,10>
is a subclass of int|string
; certainly float|string
is a superclass of both float
and string
according to the isSuperTypeOf
method on the UnionType.
$this->assertSame( | ||
$expectedResult->describe(), | ||
$actualResult->describe(), | ||
sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())) |
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 message is wrong here (mentions isSuperTypeOf
instead of isSubTypeOf
)
} else { | ||
$i++; | ||
} | ||
} |
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.
(Sorry I messed up the line range selection here... the comment is meant for the entire method unionIntRanges()
)
Code to pretty much do the exact same thing already exists in TypeCombinator::union()
. In fact, a UnionType
should probably never even contain mergeable integer ranges (or const ints). This is currently not enforced, but the idea is to use TypeCombinator::union(...)
instead of new UnionType([...])
whenever in doubt that there might be overlapping types.
I understand that in your example you end up with a union type 1|2|3|4
which is then tested against int<1,4>
. This currently doesn't work properly. I wonder if the cleaner solution wouldn't just be to disallow adjacent integers in unions and enforce the usage of integer ranges (e.g. always int<1,2>
instead of 1|2
. This ensures that there's only way one to represent the same thing. With this the sub-type check would automatically start to work correctly.
yield [ | ||
IntegerRangeType::fromInterval(5, 10), | ||
new UnionType([new ConstantIntegerType(5), IntegerRangeType::fromInterval(6, 10), new StringType()]), | ||
TrinaryLogic::createYes(), |
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.
Same here, although this specific union shouldn't even exist in practice, since the 5
should be merged into int<6, 10>
.
Looks like this PR will fix these cases: https://phpstan.org/r/93116f33-5437-4d97-b06f-d04949258051 Can you add integration tests to respective rules? Thanks! |
40ea36d
to
7b0412a
Compare
Based on jlherren's feedback, I started this again to take advantage of the existing functionality in |
bad292c
to
835c69d
Compare
Hi, there's still too many failing tests. Do you plan to finish this PR? Thanks! |
835c69d
to
26e77a7
Compare
Partially resolves phpstan/phpstan#3339
26e77a7
to
ceed528
Compare
ceed528
to
ab4a783
Compare
Hi Ondrej, with the approach of converting all |
I had time to have a look at this again, here are my thoughts:
I believe this approach would fix the issue in far fewer lines of code (but I might be mistaken of course). |
efd31ce
to
0471f87
Compare
This is old and stale, feel free to start fresh on top of current master in a new PR. Thanks! |
This commit allows
int<m,n>
to be recognised as a subtype of unions likem|m+1|m+2|...|n-1|n
orint<m,n-1>|n
. It also creates a new interfacePHPStan\Type\ImplementsSubTypeOfUnion
which indicates toUnionType->superTypeOf
that it should callisSubTypeOf
on the other object. (Previously there was no need for such an interface as IterableType was the only such type.)This resolves a modified form of phpstan/phpstan#3339: https://phpstan.org/r/00e327fa-55e9-41b8-8b6e-3e8924d9a3d4
It doesn't address the fact that in the original snippet PHPStan thinks
$i
might take any value in the range [PHP_INT_MIN
,2].