phpstan-src
phpstan-src copied to clipboard
Implement TypeSpecifierContext->getReturnType()
trying a minimal approach to see whether the idea works as a whole
for expression like
if (doFoo() > 0)
we want to pass the context specific return-type information into type-specifying extensions so they can decide not just on true/truethy/false/falsy but also on "remaining return type values" (e.g. preg_match returns 0|1|false)
this should help to reduce the number of hardcoded hacks within the TypeSpecifier und move over some cases into extensions (which also allows 3rd party extensions todo similar things, as they can't hard-code hack the TypeSpecifier)
ondrej quoted:
There should be a new method on the context, can be getReturnType
Let’s say we have doFoo(): int if (doFoo() > 0), in the then branch, this should return int<1, max>, in the else branch it should return int<min, 0>
the case failling in webmozart-assert is effectively
<?php
declare(strict_types=1);
class HelloWorld
{
public function sayHello($m): void
{
\PHPStan\dumpType(
is_string($m)
&& strlen($m) >= 1
&& strlen($m) <= 0
);
}
}
not sure what todo with it atm.
edit: fixed with 19749e8
debugging some more, I think more precisely the problem is here:
<?php
function sayHello(string $m): void
{
if (strlen($m) >= 1) {
if (strlen($m) <= 0) {
\PHPStan\dumpType(
$m
);
}
}
}
it dumps non-empty-string instead of *NEVER*
edit: fixed with 19749e8
This pull request has been marked as ready for review.
//cc @herndlm
Yeah, this works, but I'd like to "burn more bridges" in the first PR about this change. I don't mean "breaking backward compatibility", but what I mean is to use the new code path as much as possible.
- TypeSpecifierContext should be created with the return type. So the constructor should accept
?Type, not?int $value. - We probably don't need the constants with bitmasks at all. The createTrue etc. methods should simply create the object with a type that makes sense and continues to be correct.
- The negate method is tricky. Maybe we need to create the object with both the "if" path type and the "else" path type.
I use this approach often. It forces the code to be correct and generally uncovers any flaws about the changes 😊