-
Notifications
You must be signed in to change notification settings - Fork 462
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
added AccessoryNonFalsyStringType #1542
Conversation
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.
This isn't enough. You need to add PHPStan\Type\Type::isNonFalsyString()
.
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.
Go through all the places where new AccessoryNonEmptyStringType()
is created and think about whether AccessoryNonFalsyStringType
also belongs there. An example - ConstantStringType::generalize().
Does this also need an addition to the typespecifier? Smth that adds the type if the string is non-empty and not '0'? |
Add a type inference test and you'll see :) My tip is that we'll have to modify StringType::tryRemove(). Which falls under the "Go through all the places where new AccessoryNonEmptyStringType() is created and think about whether AccessoryNonFalsyStringType also belongs there." todo item :) |
if ((new ConstantIntegerType(0))->isSuperTypeOf($offsetType)->yes()) { | ||
return new IntersectionType([new StringType(), new AccessoryNonFalsyStringType()]); | ||
} |
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.
memo to me: think about this case
foreach ($this->getSortedTypes() as $type) { | ||
if ($type instanceof AccessoryNonEmptyStringType | ||
|| $type instanceof AccessoryLiteralStringType | ||
|| $type instanceof AccessoryNumericStringType | ||
|| $type instanceof AccessoryNonFalsyStringType | ||
) { | ||
if ($type instanceof AccessoryNonFalsyStringType) { |
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.
This doesn't need hacks in IntersectionType.
- AccessoryNonEmptyStringType = AccessoryNonFalsyStringType + '0'
- AccessoryNonFalsyStringType = AccessoryNonEmptyStringType - '0'
This means that AccessoryNonFalsyStringType is "smaller".
AccessoryNonFalsyStringType->isSuperTypeOf(AccessoryNonEmptyStringType)
= maybe (makes sense, not every AccessoryNonEmptyStringType is AccessoryNonFalsyStringType)AccessoryNonEmptyStringType->isSuperTypeOf(AccessoryNonFalsyStringType)
= yes (makes sense, all AccessoryNonFalsyStringType are AccessoryNonEmptyStringType)
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.
isSuperTypeOf
implemented in 45c5c6a.
the hacks we see here are required to make sure a intersection cannot contain non-falsy-string
and non-empty-string
at the same time.
I guess this need to be handled via isSubTypeOf
or tryRemove
or similar instead, to get rid of these IntersectionType
changes
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.
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 cannot get rid of this hack in IntersectionType
atm, without regressing tests.
Hi, I'm unsubscribing from this PR. At this rate, I expect at least 100 pushes from you (and I'm getting each one as a separate email). Of course, you could choose to develop it locally and push it once you consider it done from your side, so I can review it. Please ping me via another channel once you consider it done and I can take a look. Thanks for understanding! |
I have no idea yet, where the current error is coming from (and whether its legit or not)
Edit: fixed with 7fd0884 |
yeah thats fine. I don't expect reviews of PRs as long as they are in draft state. pushing the intermediate state into a PR makes it easier for me to sync the work across different computers. |
public function isLiteralString(): TrinaryLogic | ||
{ | ||
return TrinaryLogic::createMaybe(); | ||
} | ||
|
||
public function tryRemove(Type $typeToRemove): ?Type | ||
{ | ||
if ($typeToRemove instanceof ConstantStringType && $typeToRemove->getValue() === '0') { | ||
return TypeCombinator::intersect($this, new AccessoryNonFalsyStringType()); | ||
} | ||
if ($typeToRemove instanceof ConstantStringType && $typeToRemove->getValue() === '') { |
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.
a few lines below there is a if ($typeToRemove instanceof AccessoryNonEmptyStringType) {
case.
I guess we also need a if ($typeToRemove instanceof AccessoryNonFalsyStringType) {
case there, but wasn't able yet to come up with a test-case
Notes to myself:
|
yeah that one is weird, a |
done
done |
I think this one is now good to review. I have 2 failling tests, I am not sure what todo about/how to fix. |
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.
Also I'd like some "accepts" tests, for example in CallMethodsRuleTest.php
Let's have a method that accepts non-falsy-string
. Are these being accepted, or reported?
'0'
- 'non-falsy-string'
- 'non-empty-string'
- 'string'
I pushed some additional tests and a fix. There's still one test failing, the expected result makes more sense to me. The problem is still gonna be in AccessoryNonEmptyStringType::isSuperTypeOf() + isSubTypeOf() and the same methods in AccessoryNonFalsyStringType. |
I don't like the final fix, but at least we are all green now :-) |
return $otherType->isSuperTypeOf($this); | ||
} | ||
|
||
if ($otherType instanceof AccessoryNonEmptyStringType) { |
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.
Need a explicit check for non-empty-string, instead of isNonEmptyString()
, which would also be true for numeric-string, which we don‘t want here
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.
you could still avoid it via the methods on the Type interface, right? Since there is also a isNumericString
I mean.
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 tried expressing it differently, but it would need to take care of at least class-string, non-falsy-string, numeric-string, constant-string.
it feels the instanceof check is better suited here
@@ -242,6 +243,12 @@ private function resolveIdentifierTypeNode(IdentifierTypeNode $typeNode, NameSco | |||
new AccessoryNonEmptyStringType(), | |||
]); | |||
|
|||
case 'non-falsy-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.
just noting here so it will not be forgotten:
on twitter there was a discussion going on whether this type should better be named truthy-string
instead (and keep 'non-falsy-string'
as a deprecated alias)
Thank you! |
implements
non-falsy-string
closes phpstan/phpstan#5317
closes phpstan/phpstan#5370