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

Improve falsey type specification with constant string comparison #1015

Conversation

herndlm
Copy link
Contributor

@herndlm herndlm commented Feb 12, 2022

Closes phpstan/phpstan#6329

This makes use of type subtraction to add information about constant strings that cannot be part of the type.

E.g. is_string($a) && '' !== $a || null === $a with $a being mixed would lead to a MixedType sureType with the empty constant string '' substracted for the inner BooleanAnd expression. And that leads to a intersection of StringType and AccessoryNonEmptyStringType.

Previously, it would determine that the empty constant string '' is a sureNotType but loose that information on merging left and right types for the outer BooleanOr.

But I'm not sure if this is the best fix :) Initially I tried adapting the left/right type merging, particularly the intersection for BooleanOr, but that made things even worse by breaking other things.

@herndlm
Copy link
Contributor Author

herndlm commented Feb 12, 2022

The related failing webmozart tests seem to be the fix for https://github.com/phpstan/phpstan-webmozart-assert/blob/1.0.9/tests/Type/WebMozartAssert/data/type.php#L25 :)

@herndlm herndlm marked this pull request as ready for review February 12, 2022 22:57
@@ -234,6 +235,13 @@ public function specifyTypesInCondition(
}
}
}

if ($context->falsey() && $constantType instanceof ConstantStringType) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I did not understand the change fully, but would this also make sense for other constant types here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Tbh I'm also not a 100% sure if this is the right/best fix. But I thought the same, yeah. Will take a look later. Also thought of getting an opinion from Ondrej first maybe


function foo($a): void
{
if (is_string($a) && '' !== $a) {
Copy link
Contributor

Choose a reason for hiding this comment

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

do you need the same test, with switched arguments?

assertType('non-empty-string', $a);
}

if (is_string($a) && '' !== $a || null === $a) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Same for is_string($a) && strlen($a) > 0 || null === $a ?

@herndlm herndlm marked this pull request as draft February 13, 2022 11:39
@herndlm
Copy link
Contributor Author

herndlm commented Feb 13, 2022

ok, forget this PR for now..

While trying to make it work with bool and int too (same problem there, I updated the snippet in the error report), I realized that this is a too specific workaroundish adaption that is not ideal.
So I'm basically back at square one :/

Anyways, I think I need to adapt something in the BooleanOr handling of TypeSpecifier and I think it is very much related to SpecifiedTypes::intersectWith (the sureNotType gets lost there because it only exists in one of the types, e.g. either left or right and is then ignored). But adapting that breaks other things. But I did not wrap my head around how the union and intersect logic there with a truthy or falsey context is exactly supposed to work.

Well, I'll keep this PR open a bit longer but promise to not add commits and comments as long as I don't have a full fix ;) I already have another idea

@herndlm
Copy link
Contributor Author

herndlm commented Feb 13, 2022

My other approach is simpler, cleaner, makes sense and works 🎉

I'll clean it up and create a new PR in the evening. UPDATE: superseded by #1016

@herndlm herndlm closed this Feb 13, 2022
@herndlm herndlm deleted the improve-falsey-context-type-specification-with-constant-string-comparison branch February 13, 2022 20:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants