RoundFunctionReturnTypeExtension supports types with ConstantScalar - #3349
ShioPy0101 wants to merge 26 commits into
Conversation
465733b to
276f471
Compare
|
which problem does this change solve? whats your real world use-case? |
|
I'm sure there are several use cases for this, but one I quickly spotted in my private code is the following pattern, which uses Ideally it would be even more useful if a float range type was implemented, but I feel like this is worthwhile enough on its own. const MAX = 1000;
const PER_PAGE = 30;
$last_page = (int)floor(MAX / PER_PAGE); |
98e7404 to
e4ad097
Compare
|
Hi @ShioPy0101, are you still interested by this PR ? Could you rebase and target 2.3.x branch ? |
e4ad097 to
143a1c6
Compare
There was a problem hiding this comment.
octoscan found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.
There was a problem hiding this comment.
zizmor found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.
143a1c6 to
77a4c85
Compare
|
Hi @VincentLanglet, I’ve rebased the PR onto 2.3.x and updated the target branch. Could you take another look when you have a chance? Thank you for bringing this PR back to my attention. |
| $returnValueTypes = []; | ||
| break; |
There was a problem hiding this comment.
You could return null directly no ?
There was a problem hiding this comment.
Yes, you're right. I'll simplify this to return null directly.
| $returnValueTypes = []; | ||
|
|
||
| foreach ($constantScalarValues as $constantScalarValue) { | ||
| if (!is_int($constantScalarValue) && !is_float($constantScalarValue)) { |
There was a problem hiding this comment.
Why this check ?
I saw in test you have the assertion
assertType('float', round($IntOrNumStr));
but can't we also understand '2.5' ?
There was a problem hiding this comment.
Thank you for pointing this out. I agree that constant numeric strings can also be handled in non-strict mode. I’ll update the implementation and tests while preserving the strict-types behavior.
| $modeType = $scope->getType($modeArg); | ||
| $mode = $modeType->getConstantScalarValues(); | ||
|
|
||
| if (count($mode) === 1 && in_array($mode[0], [PHP_ROUND_HALF_UP, PHP_ROUND_HALF_DOWN, PHP_ROUND_HALF_EVEN, PHP_ROUND_HALF_ODD], true)) { |
There was a problem hiding this comment.
There is now new RoundingMode
https://www.php.net/manual/en/enum.roundingmode.php
There was a problem hiding this comment.
Thanks for pointing it out — I’ll update the implementation for the current PHP versions.
VincentLanglet
left a comment
There was a problem hiding this comment.
Seems good otherwise
| return null; | ||
| } | ||
|
|
||
| switch ($enumCase->getEnumCaseName()) { |
There was a problem hiding this comment.
Why this mapping ?
This loose some case.
assertType('float', round(9.5, 0, \RoundingMode::TowardsZero));
assertType('float', round(9.5, 0, \RoundingMode::AwayFromZero));
assertType('float', round(9.5, 0, \RoundingMode::NegativeInfinity));
assertType('float', round(9.5, 0, \RoundingMode::PositiveInfinity));
You could keep the original value when the Enum exists no ?
There was a problem hiding this comment.
I intentionally limited the mapping to the four RoundingMode cases that have direct equivalents in the legacy PHP_ROUND_HALF_* constants. The intent was to avoid making constant evaluation depend on the runtime availability of the RoundingMode enum.
For the remaining cases, I currently fall back to the existing return-type logic because they do not have a direct legacy constant mapping.
That said, I agree that this is an implementation limitation rather than a limitation of RoundingMode itself. Preserving the enum case internally would allow all cases to be evaluated more precisely, so I think that would be a better direction.
There was a problem hiding this comment.
I am still considering the best approach here. The README states that PHPStan's source code is developed on PHP 8.2, while the distributed package and PHAR are transformed to run on PHP 7.2 and higher. Given that, I would prefer to avoid making constant evaluation depend on the runtime availability of RoundingMode.
Returns a constant type when the
$numargument and the relevant options ofround(),ceil(), orfloor()can be resolved to constant values.Constant numeric strings are also evaluated in non-strict mode.
round()also supports theRoundingModeenum cases corresponding to the legacyPHP_ROUND_HALF_*constants.The default return type is used when constant evaluation is not possible, for example when: