From 84d4ef7cb2b4f8dfbf8b0dbe92b973d75f717369 Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Wed, 9 Apr 2025 22:04:41 +0100 Subject: [PATCH] Remember value of arguments passed to `{min,max}()` --- .../Php/MinMaxFunctionReturnTypeExtension.php | 10 ++++++-- tests/PHPStan/Analyser/nsrt/bug-12731.php | 24 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 tests/PHPStan/Analyser/nsrt/bug-12731.php diff --git a/src/Type/Php/MinMaxFunctionReturnTypeExtension.php b/src/Type/Php/MinMaxFunctionReturnTypeExtension.php index 5beabcbcf3..9faa3563c7 100644 --- a/src/Type/Php/MinMaxFunctionReturnTypeExtension.php +++ b/src/Type/Php/MinMaxFunctionReturnTypeExtension.php @@ -6,6 +6,7 @@ use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Expr\Ternary; use PHPStan\Analyser\Scope; +use PHPStan\Node\Expr\AlwaysRememberedExpr; use PHPStan\Php\PhpVersion; use PHPStan\Reflection\FunctionReflection; use PHPStan\Type\Constant\ConstantArrayType; @@ -60,15 +61,20 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $argType1 = $scope->getType($args[1]->value); if ($argType0->isArray()->no() && $argType1->isArray()->no()) { + $comparisonExpr = new Smaller( + new AlwaysRememberedExpr($args[0]->value, $argType0, $scope->getNativeType($args[0]->value)), + new AlwaysRememberedExpr($args[1]->value, $argType1, $scope->getNativeType($args[1]->value)), + ); + if ($functionName === 'min') { return $scope->getType(new Ternary( - new Smaller($args[0]->value, $args[1]->value), + $comparisonExpr, $args[0]->value, $args[1]->value, )); } elseif ($functionName === 'max') { return $scope->getType(new Ternary( - new Smaller($args[0]->value, $args[1]->value), + $comparisonExpr, $args[1]->value, $args[0]->value, )); diff --git a/tests/PHPStan/Analyser/nsrt/bug-12731.php b/tests/PHPStan/Analyser/nsrt/bug-12731.php new file mode 100644 index 0000000000..79c8160461 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-12731.php @@ -0,0 +1,24 @@ +', max(4, pure_int())); + +$_ = impure_int(); +assertType('int<4, max>', max(4, $_)); + +assertType('int<4, max>', max(4, impure_int())); +assertType('int<4, max>', max(impure_int(), 4)); +assertType('int', impure_int());