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
Fix !isset() with Variable #2710
Conversation
src/Analyser/TypeSpecifier.php
Outdated
$nullType = new NullType(); | ||
if (!$nullType->isSuperTypeOf($type)->no()) { |
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 am not sure about this condition
return $exprType; | ||
} | ||
|
||
if ($issetExpr instanceof Expr\Variable && is_string($issetExpr->name)) { |
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.
hopefully its OK to do the variable stuff in a separate PR.
whats missing is ArrayDimFetch
, PropertyFetch
, StaticPropertyFetch
which could be done in a followup?
the carbon error seems valid the larastan errors seem unrelated, as they also show up in other open PRs the presta shop error looks fishy |
This pull request has been marked as ready for review. |
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 this is the place to test all the different scenarios like I described in the original PR: #2657 (review)
So if we're doing !isset($a)
:
- If the variable is nullable, it means that after this PR it might be null or it might not exist
- If the variable is not nullable, it means that after this PR it does not exist anymore
etc...
I have more tests and a small fix open todo |
one interessting failling drupal case:
reduced it to function doBar(bool $view, bool $edit): void {
foreach (['view' => $view, 'edit' => $edit] as $operation => $result) {
assertVariableCertainty(TrinaryLogic::createYes(), $result);
$result_text = !isset($result) ? 'null' : ($result ? 'true' : 'false'); // Variable $result in isset() always exists and is not nullable.
assertVariableCertainty(TrinaryLogic::createYes(), $result); // Expected variable certainty Yes, actual: Maybe
assertType('bool', $result); // Variable $result might not be defined.
}
} -> I think its great that PHPStan realized that since |
Hi, I'm putting this on hold for a while until this problem is resolved: #2666 (comment) |
Alright, one more problem this PR should try to fix is:
Not sure why it does not work now. |
The problem in Drupal should be fixed, the code in Carbon should still fail because it was wrong from the start. |
Did my commit in forward fashion on 1.10.x, only added more tests here. |
Results look better but there's something wrong with |
I guess the problem is related that the variable is only defined via dim fetches (Maybe I can have a look tonight) |
That shouldn't matter, right? Also I found out it already fails on 1.10.x so maybe I broke it with my recent commits. |
It shouldn't - but its a notable difference of the case at hand vs working unit tests |
Another notable difference of the drupal case: the dim-fetch based declarations are wrapped in a property-fetch based isset() |
added a reduced test for the drupal case. looks like a certainty issue of regular variables (which was already contained in 1.10.40) |
Hi, my plan for today is to make 1.10.x releasable again by reverting all related changes and picking those commits into this PR. Right now it’s pretty broken and we need to do this properly in order not to endanger the stability. So we’re gonna focus the changes here and make sure the CI is green. I also need to work on other stuff like PHP 8.3 and PHPStan 1.11. |
I see thanks. If there is anything I can do to support you in other areas, feel free to note. |
I also found the cause for this problem: function book_node_links_alter(array &$links, NodeInterface $node) {
\PHPStan\dumpType(isset($node->book['depth'])); // Dumped type: false
if (isset($node->book['depth'])) {
$book_links['book_printer'] = [
];
}
\PHPStan\Testing\assertVariableCertainty(\PHPStan\TrinaryLogic::createMaybe(), $book_links); // Expected variable certainty Maybe, actual: No
if (!empty($book_links)) {
$links['book'] = [
'#links' => $book_links,
];
}
} I think everything is working as expected - as far as this PR is a concern. we conclude the isset() expression is always FALSE, therefore we don't take the IF-truethy-scope into the IF-final-scope which means the variable has a certainty of NO after the |
I think the cause for this problem is, that the scope before entering the $scope->debug();
array (
'$shortcut_id (Maybe)' => '1',
'$link_mode (Yes)' => '\'add\'|\'remove\'',
'native $shortcut_id' => '1',
'native $link_mode' => '\'add\'|\'remove\'',
'condition about $shortcut_id #1' => 'if $link_mode=\'remove\' then $shortcut_id is 1 (Yes)',
) which means we don't know about a conditional type and certainty for the ELSE case of the ternary in the end it feels like a possible future improvement..? |
I hope you don't mind the forcepushes. If you have some commits locally and I forcepush the base under your feet, can solve it easily with |
really nice, thank you. I was looking at it for hours and coulnd't make sense of it. |
I have a test-case locally for the conditon bug. let me push it into the PR |
thanks for your support! |
Another split out of #2657
implements the
part of #2657 (review)
closes phpstan/phpstan#3632
closes phpstan/phpstan#8190
closes phpstan/phpstan#8366
closes phpstan/phpstan#8659
closes phpstan/phpstan#9580
closes phpstan/phpstan#10064
closes phpstan/phpstan#10088