-
-
Notifications
You must be signed in to change notification settings - Fork 946
Description
Feature request
I have an idea. Users need help understanding that errors like these:
<?php
declare(strict_types=1);
/**
* Calculate something and return a value that could be different each time
*
* @return int<0, 1000> result different at each call
*/
function calculateSomething(): int
{
return rand(0, 1000);
}
// calculated result can be between 0 and 1000
if (calculateSomething() > 0) {
// the new calculated result can also be between 0 and 1000
// PHPStan error: Comparison operation ">" between int<1, 1000> and 0 is always true.
if (calculateSomething() > 0) {
// can be something else
}
}and:
final class ValidateIndicatorValue {
public function validate(Indicator $indicator, int $id, \DateTimeInterface $date): void {
$value = $indicator->valueWithId($id);
if ($date->format('Y-m-d') !== $value->date()->format('Y-m-d')) {
if ($value->isLocked()) {
throw new \Exception('Cannot modify locked');
}
$value->changeIndicatorValueDate($id, $date);
// PHPStan error: If condition is always false.
if ($value->isLocked()) {
throw new \Exception('Cannot modify to a locked year');
}
}
}
}Can be solved by adding PHPDoc tag @phpstan-impure above changeIndicatorValueDate method and
calculateSomething function.
I'd like to add a tip to rules that report similar errors:
StrictComparisonOfDifferentTypesRule
IfConstantConditionRule
ImpossibleInstanceOfRule
and more from Comparison namespace
But this tip "Solve this error by adding PHPDoc tag @phpstan-impur above X()."
should be added only in this specific scenario where it'd really help.
Which means we need to track it in Scope. NodeScopeResolver has several calls to hasSideEffects
followed by invalidateExpression.
Details about this are in https://phpstan.org/blog/remembering-and-forgetting-returned-values but
the gist is that:
void functions are always impure
function returning static or $this are always impure
functions returning other types are maybe-impure
It's the last case where (if rememberPossiblyImpureFunctionValues is set to true which is the
default) default behaviour needs help by having to add @phpstan-impure above function and method
declarations.
This has two effects:
- TypeSpecifier does not remember the last-checked value of the function in the scope with the
same arguments (because it's not deterministic). - NodeScopeResolver will invalidate remembered expressions on
$objectin Scope if an impure or
void method is called on$object.
So if NodeScopeResolver encounters a possibly impure function (hasSideEffects returns maybe), it
could note this down in Scope ("this could have been an invalidation"), and when related rules
would report an error involving this expression (like calculateSomething() or $object), they
could output the suggested tip.
Best way to track this in Scope is with custom virtual expr nodes. We already do this with nodes
like IntertwinedVariableByReferenceWithExpr or PropertyInitializationExpr.
Did PHPStan help you today? Did it make you happy in any way?
No response