diff --git a/src/Analyser/ArgumentsHandler.php b/src/Analyser/ArgumentsHandler.php index 38da1a427cb..12c8c49a665 100644 --- a/src/Analyser/ArgumentsHandler.php +++ b/src/Analyser/ArgumentsHandler.php @@ -28,7 +28,6 @@ use PHPStan\Node\Expr\NativeTypeExpr; use PHPStan\Node\InvalidateExprNode; use PHPStan\Reflection\Callables\SimpleImpurePoint; -use PHPStan\Reflection\Callables\SimpleThrowPoint; use PHPStan\Reflection\ExtendedMethodReflection; use PHPStan\Reflection\ExtendedParameterReflection; use PHPStan\Reflection\FunctionReflection; @@ -61,7 +60,6 @@ use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; use PHPStan\Type\TypeUtils; -use function array_filter; use function array_keys; use function array_last; use function array_map; @@ -654,11 +652,17 @@ public function processArgs( $deferredInvalidateExpressions[] = [$acceptors[0]->getInvalidateExpressions(), $acceptors[0]->getUsedVariables()]; } if ($callCallbackImmediately) { - $callableThrowPoints = array_map(static fn (SimpleThrowPoint $throwPoint) => $throwPoint->isExplicit() ? InternalThrowPoint::createExplicit($scope, $throwPoint->getType(), $arg->value, $throwPoint->canContainAnyThrowable()) : InternalThrowPoint::createImplicit($scope, $arg->value), $acceptors[0]->getThrowPoints()); - if (!$this->implicitThrows) { - $callableThrowPoints = array_values(array_filter($callableThrowPoints, static fn (InternalThrowPoint $throwPoint) => $throwPoint->isExplicit())); + foreach ($acceptors[0]->getThrowPoints() as $throwPoint) { + $isExplicit = $throwPoint->isExplicit(); + if (!$this->implicitThrows && !$isExplicit) { + continue; + } + if ($isExplicit) { + $throwPoints[] = InternalThrowPoint::createExplicit($scope, $throwPoint->getType(), $arg->value, $throwPoint->canContainAnyThrowable()); + } else { + $throwPoints[] = InternalThrowPoint::createImplicit($scope, $arg->value); + } } - $throwPoints = array_merge($throwPoints, $callableThrowPoints); $impurePoints = array_merge($impurePoints, array_map(static fn (SimpleImpurePoint $impurePoint) => new ImpurePoint($scope, $arg->value, $impurePoint->getIdentifier(), $impurePoint->getDescription(), $impurePoint->isCertain()), $acceptors[0]->getImpurePoints())); } } diff --git a/src/Analyser/ExprHandler/FuncCallHandler.php b/src/Analyser/ExprHandler/FuncCallHandler.php index 4ff33f80889..e7a0bfa5f1b 100644 --- a/src/Analyser/ExprHandler/FuncCallHandler.php +++ b/src/Analyser/ExprHandler/FuncCallHandler.php @@ -52,7 +52,6 @@ use PHPStan\Parser\ImmediatelyInvokedClosureVisitor; use PHPStan\Reflection\Callables\CallableParametersAcceptor; use PHPStan\Reflection\Callables\SimpleImpurePoint; -use PHPStan\Reflection\Callables\SimpleThrowPoint; use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\Reflection\FunctionReflection; use PHPStan\Reflection\Native\NativeParameterReflection; @@ -85,12 +84,10 @@ use PHPStan\Type\UnionType; use Throwable; use WeakReference; -use function array_filter; use function array_key_first; use function array_keys; use function array_map; use function array_merge; -use function array_values; use function count; use function in_array; use function is_string; @@ -194,11 +191,17 @@ public function processExpr(NodeScopeResolver $nodeScopeResolver, Stmt $stmt, Ex ) { // processed later } elseif ($parametersAcceptor instanceof CallableParametersAcceptor) { - $callableThrowPoints = array_map(static fn (SimpleThrowPoint $throwPoint) => $throwPoint->isExplicit() ? InternalThrowPoint::createExplicit($scope, $throwPoint->getType(), $expr, $throwPoint->canContainAnyThrowable()) : InternalThrowPoint::createImplicit($scope, $expr), $parametersAcceptor->getThrowPoints()); - if (!$this->implicitThrows) { - $callableThrowPoints = array_values(array_filter($callableThrowPoints, static fn (InternalThrowPoint $throwPoint) => $throwPoint->isExplicit())); + foreach ($parametersAcceptor->getThrowPoints() as $throwPoint) { + $isExplicit = $throwPoint->isExplicit(); + if (!$this->implicitThrows && !$isExplicit) { + continue; + } + if ($isExplicit) { + $throwPoints[] = InternalThrowPoint::createExplicit($scope, $throwPoint->getType(), $expr, $throwPoint->canContainAnyThrowable()); + } else { + $throwPoints[] = InternalThrowPoint::createImplicit($scope, $expr); + } } - $throwPoints = array_merge($throwPoints, $callableThrowPoints); // A callable value's impure points are resolved from its // ParametersAcceptor alone, so a conditionally pure function reached // through a first-class callable arrives here as an unconditional diff --git a/turbo-ext/src/ArgumentsHandler.cpp b/turbo-ext/src/ArgumentsHandler.cpp index f0c4958fa85..6e1e1651e14 100644 --- a/turbo-ext/src/ArgumentsHandler.cpp +++ b/turbo-ext/src/ArgumentsHandler.cpp @@ -2148,11 +2148,11 @@ class ArgumentsHandler zv::Val simpleThrowPoints = callOn(throwPointsSite, acceptor, PT_LC("getthrowpoints"), "getThrowPoints", 0, NULL); if (UNEXPECTED(simpleThrowPoints.isUndef() || !requireArray(simpleThrowPoints.raw(), "array_map(): Argument #2 ($array)"))) return false; zval *scope = w.scope.raw(); - zv::Arr callableThrowPoints = zv::Arr::create(zend_hash_num_elements(Z_ARRVAL_P(simpleThrowPoints.raw()))); for (zv::ArrayEntry entry : zv::ArrRef(simpleThrowPoints.raw())) { zval *throwPoint = entry.value().deref().raw(); zv::Val isExplicit = callOn(pt_ah_simple_throw_point_is_explicit_site, throwPoint, PT_LC("isexplicit"), "isExplicit", 0, NULL); if (UNEXPECTED(isExplicit.isUndef())) return false; + if (!zend_is_true(slot(slots::implicitThrows)) && !zend_is_true(isExplicit.raw())) continue; zv::Val mapped; if (zend_is_true(isExplicit.raw())) { zv::Val type = callOn(pt_ah_simple_throw_point_get_type_site, throwPoint, PT_LC("gettype"), "getType", 0, NULL); @@ -2164,20 +2164,8 @@ class ArgumentsHandler mapped = pt_internal_throw_point_create_implicit(scope, value); } if (UNEXPECTED(mapped.isUndef())) return false; - setKey(callableThrowPoints, entry.stringKeyOrNull(), entry.indexKey(), mapped.raw()); - } - if (!zend_is_true(slot(slots::implicitThrows))) { - zv::Arr explicitOnly = zv::Arr::create(zend_hash_num_elements(callableThrowPoints.table())); - for (zv::ArrayEntry entry : zv::TableRef(callableThrowPoints.table())) { - bool isExplicit = false; - if (UNEXPECTED(!pt_internal_throw_point_is_explicit(entry.value().raw(), isExplicit))) return false; - if (isExplicit) { - explicitOnly.push(zv::Ref(entry.value().raw())); - } - } - callableThrowPoints = std::move(explicitOnly); + w.throwPoints.push(std::move(mapped)); } - if (UNEXPECTED(!arrayMerge(w.throwPoints, callableThrowPoints.raw()))) return false; zv::Val simpleImpurePoints = callOn(impurePointsSite, acceptor, PT_LC("getimpurepoints"), "getImpurePoints", 0, NULL); if (UNEXPECTED(simpleImpurePoints.isUndef() || !requireArray(simpleImpurePoints.raw(), "array_map(): Argument #2 ($array)"))) return false; diff --git a/turbo-ext/src/FuncCallHandler.cpp b/turbo-ext/src/FuncCallHandler.cpp index e47625e64ad..1174fed932c 100644 --- a/turbo-ext/src/FuncCallHandler.cpp +++ b/turbo-ext/src/FuncCallHandler.cpp @@ -1469,12 +1469,11 @@ class FuncCallHandler zend_type_error("array_map(): Argument #2 ($array) must be of type array, %s given", zend_zval_value_name(simpleThrowPoints.raw())); return false; } - /* array_map() keeps the keys of its one array */ - zv::Arr callableThrowPoints = zv::Arr::create(zend_hash_num_elements(Z_ARRVAL_P(simpleThrowPoints.raw()))); for (zv::ArrayEntry entry : zv::ArrRef(simpleThrowPoints.raw())) { zval *simpleThrowPoint = entry.value().deref().raw(); zv::Val explicitValue = callNoArgs(pt_fch_throw_point_explicit_site, simpleThrowPoint, PT_LC("isexplicit"), "isExplicit"); if (UNEXPECTED(explicitValue.isUndef())) return false; + if (!flag(slots::implicitThrows) && !zend_is_true(explicitValue.raw())) continue; zv::Val throwPoint; if (zend_is_true(explicitValue.raw())) { zv::Val type = callNoArgs(pt_fch_throw_point_type_site, simpleThrowPoint, PT_LC("gettype"), "getType"); @@ -1486,27 +1485,8 @@ class FuncCallHandler throwPoint = pt_internal_throw_point_create_implicit(scope.raw(), expr); } if (UNEXPECTED(throwPoint.isUndef())) return false; - zend_string *key = entry.stringKeyOrNull(); - if (key != NULL) { - callableThrowPoints.set(key, std::move(throwPoint)); - } else { - callableThrowPoints.separate(); - zval value = throwPoint.take(); - zend_hash_index_update(callableThrowPoints.table(), entry.indexKey(), &value); - } - } - zv::Val callableThrowPointsHold = zv::Val(std::move(callableThrowPoints)); - if (!flag(slots::implicitThrows)) { - /* array_values(array_filter($callableThrowPoints, static fn (InternalThrowPoint $throwPoint) => $throwPoint->isExplicit())) */ - zv::Arr explicitOnly = zv::Arr::create(countOf(callableThrowPointsHold.raw())); - for (zv::ArrayEntry entry : zv::ArrRef(callableThrowPointsHold.raw())) { - bool isExplicit; - if (UNEXPECTED(!pt_internal_throw_point_is_explicit(entry.value().raw(), isExplicit))) return false; - if (isExplicit) explicitOnly.push(entry.value()); - } - callableThrowPointsHold = zv::Val(std::move(explicitOnly)); + zv::ArrRef(throwPoints.raw()).push(zv::Ref(throwPoint.raw())); } - if (UNEXPECTED(!arrayMerge(throwPoints, callableThrowPointsHold.raw()))) return false; zv::Val acceptorImpurePoints = pt_parameters_acceptor_call(parametersAcceptor, PT_PA_GET_IMPURE_POINTS); if (UNEXPECTED(acceptorImpurePoints.isUndef())) return false;