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 isset specification in falsy scope #1781
Improve isset specification in falsy scope #1781
Conversation
0d1bc48
to
743db92
Compare
Both the composer and doctrine failure seem legit. Composer deals with arrays in negated contexts where only booleans are allowed, see https://github.com/composer/composer/blob/9a69c12a0799d5a974f5ec5d2e78be3495b0b06c/src/Composer/Command/DiagnoseCommand.php#L725 Doctrine checks the $className with |
743db92
to
129868e
Compare
I figured out how to do it more generically with the help of Unfortunately I had to revert a tiny change from my previous #1784. It was not there until a couple hours ago still anyways :P The reason is that it will mess with the falsy scope by not unsetting But anyways, I think this PR improves falsy |
// the problem is that `empty($config)` translates to `!isset($config) || !$config` | ||
// and before specified types of the left and right side are intersected they are "normalized" | ||
// by removing the sureNotType from $scope->getType() which is `stdClass|array|null` here | ||
assertNativeType('array{}|null', $config); |
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.
regarding this - here SpecifiedTypes::normalize()
wouldn't even be needed and then it would work.. I think I can inline the normalization into SpecifiedTypes::intersectWith()
and make it a bit smarter. I'd look at that in a dedicated PR.
ah I remember what the ugly parts here were - the Scope
that needs to be passed to intersect then or the other type that needs to be passed to normalize. ugh
then the simplest working thing would be to use the correct type, e.g. the following on MutatingScope
to use it inside SpecifiedTypes
:
public function getTypeOrNativeType(Expr $node): Type
{
return $this->treatPhpDocTypesAsCertain
? $this->getNativeType($node)
: $this->getType($node);
}
or also pass around $treatPhpDocTypesAsCertain
🤔
but IIIRC there were/are other PRs or issues that touch the same subject
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 don't think this is right. Native type has to be evaluated alongside the full type. We're always interested in both at the same time. That means that TypeSpecifier and SpecifiedTypes should carry both at the same time.
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'm gonna try further looking into this since it bothers me quite a bit
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 it's a stepping stone to implement my suggestions here: #1627 (comment)
Thank you! |
Continues specifying the type for a variable in a falsy
isset
if it exists in the scope.This affectively leads to a more refined variable type and "fixes" type narrowing with
empty()
in a truthy scope too (seeTypeSpecifierTest
changes). The reason for that is that e.g.empty($foo)
translates to!isset($foo) || !$foo
and without types for$foo
on the left side of theBooleanOr
SpecifiedTypes::intersectWith()
would simply drop the type info for the right side.