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
Support non-empty-array in InArrayFunctionTypeSpecifyingExtension #1108
Conversation
|
||
$specifiedTypes = new SpecifiedTypes([], []); | ||
if ($context->true()) { | ||
$arrayType = TypeCombinator::intersect($arrayType, new NonEmptyArrayType()); |
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 seems this intersection alters some array-types, so they no longer get reported as TRUE by the ImpossibleTypeChecker.. still investigating..
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.
had to add a lot of checks, to make the test-suite - especially the ImpossibleTypeChecker - happy, see e.g. for errors which happen, without these checks
...
1) PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRuleTest::testImpossibleCheckTypeFunctionCall
Failed asserting that two strings are identical.
--- Expected
+++ Actual
@@ @@
194: Call to function method_exists() with $this(CheckTypeFunctionCall\FinalClassWithMethodExists) and 'doBar' will always evaluate to false.
209: Call to function property_exists() with $this(CheckTypeFunctionCall\FinalClassWithPropertyExists) and 'fooProperty' will always evaluate to true.
212: Call to function property_exists() with $this(CheckTypeFunctionCall\FinalClassWithPropertyExists) and 'barProperty' will always evaluate to false.
-235: Call to function in_array() with arguments int, array{'foo', 'bar'} and true will always evaluate to false.
-244: Call to function in_array() with arguments 'bar'|'foo', array{'baz', 'lorem'} and true will always evaluate to false.
-248: Call to function in_array() with arguments 'bar'|'foo', array{'foo', 'bar'} and true will always evaluate to true.
-252: Call to function in_array() with arguments 'foo', array{'foo'} and true will always evaluate to true.
-256: Call to function in_array() with arguments 'foo', array{'foo', 'bar'} and true will always evaluate to true.
320: Call to function in_array() with arguments 'bar', array{}|array{'foo'} and true will always evaluate to false.
-336: Call to function in_array() with arguments 'baz', array{0: 'bar', 1?: 'foo'} and true will always evaluate to false.
-343: Call to function in_array() with arguments 'foo', array{} and true will always evaluate to false.
360: Call to function array_key_exists() with 'a' and array{a: 1, b?: 2} will always evaluate to true.
366: Call to function array_key_exists() with 'c' and array{a: 1, b?: 2} will always evaluate to false.
560: Call to function is_string() with mixed will always evaluate to false.
C:\dvl\Workspace\phpstan-src-staabm\src\Testing\RuleTestCase.php:131
C:\dvl\Workspace\phpstan-src-staabm\tests\PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRuleTest.php:47
2) PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRuleTest::testImpossibleCheckTypeFunctionCallWithoutAlwaysTrue
Failed asserting that two strings are identical.
--- Expected
+++ Actual
@@ @@
105: Call to function is_numeric() with 'blabla' will always evaluate to false.
194: Call to function method_exists() with $this(CheckTypeFunctionCall\FinalClassWithMethodExists) and 'doBar' will always evaluate to false.
212: Call to function property_exists() with $this(CheckTypeFunctionCall\FinalClassWithPropertyExists) and 'barProperty' will always evaluate to false.
-235: Call to function in_array() with arguments int, array{'foo', 'bar'} and true will always evaluate to false.
-244: Call to function in_array() with arguments 'bar'|'foo', array{'baz', 'lorem'} and true will always evaluate to false.
320: Call to function in_array() with arguments 'bar', array{}|array{'foo'} and true will always evaluate to false.
-336: Call to function in_array() with arguments 'baz', array{0: 'bar', 1?: 'foo'} and true will always evaluate to false.
-343: Call to function in_array() with arguments 'foo', array{} and true will always evaluate to false.
366: Call to function array_key_exists() with 'c' and array{a: 1, b?: 2} will always evaluate to false.
560: Call to function is_string() with mixed will always evaluate to false.
571: Call to function is_callable() with mixed will always evaluate to false.
C:\dvl\Workspace\phpstan-src-staabm\src\Testing\RuleTestCase.php:131
C:\dvl\Workspace\phpstan-src-staabm\tests\PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRuleTest.php:256
3) PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRuleTest::testBugInArrayDateFormat
Failed asserting that two strings are identical.
--- Expected
+++ Actual
@@ @@
'39: Call to function in_array() with arguments 'a', non-empty-array<int, 'a'> and true will always evaluate to true.
43: Call to function in_array() with arguments 'b', non-empty-array<int, 'a'> and true will always evaluate to false.
-47: Call to function in_array() with arguments int, array{} and true will always evaluate to false.
'
...
I am pretty sure, there is some kind of check which should be done instead, but I did not find it yet
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.
hmm maybe there is some kind of cache invalidated, because the type is altered within the type-specifying-extension?
e.g. intersecting array{'foo', 'bar'}
with NonEmptyArrayType
does not change the type itself, but it feels like since we get a new object this has some kind of side-effect on the ImpossibleTypeChecker..
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.
investigation still goes on...
before this PR, phpstan took this path to return false
phpstan-src/src/Rules/Comparison/ImpossibleCheckTypeHelper.php
Lines 201 to 220 in a355aaa
if (count($sureTypes) === 1 && count($sureNotTypes) === 0) { | |
$sureType = reset($sureTypes); | |
if ($isSpecified($sureType[0])) { | |
return null; | |
} | |
if ($this->treatPhpDocTypesAsCertain) { | |
$argumentType = $scope->getType($sureType[0]); | |
} else { | |
$argumentType = $scope->getNativeType($sureType[0]); | |
} | |
/** @var Type $resultType */ | |
$resultType = $sureType[1]; | |
$isSuperType = $resultType->isSuperTypeOf($argumentType); | |
if ($isSuperType->yes()) { | |
return true; | |
} elseif ($isSuperType->no()) { | |
return false; |
which produced the errors, now missing with this PR applied. after this change we have more then 1 sureType, and therefore the code takes a different path.
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 getting the feeling, that a TypeSpecifyingExtension
cannot specify types for different expressions in one run.
I cannot find any other TypeSpecifyingExtension
wich uses unionWith
. also every other TypeSpecifyingExtension
which I checked in the codebase always specifies its type for a single arg.
starting wit 1cb657f I changed the TypeSpecifyingExtension
to drop these hopefully unneeded checks for a change in the ImpossibleTypeChecker
f881f1e
to
1cb657f
Compare
$types = TypeCombinator::union( | ||
...array_column($sureNotTypes, 1), | ||
); |
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.
instead of union togehter all types within $sureNotTypes
, we now take the $expr
into account, and union only these refering to the same expr.
adding this here to support the change in InArrayFunctionTypeSpecifyingExtension
regresses some other parts.
I am not sure how this should progress further and therefore wait for a first round of review from ondrey.
927a1d8
to
b627cdc
Compare
The changes in #1430 should make it possible to finish this as well :) |
I've rebased it to see how the code works :) |
Wow, looks like it works in the first try :) |
Thank you! |
Thank you guys! |
as requested in phpstan/phpstan#6863 (comment)
closes phpstan/phpstan#6167