From 9ef0fc8403a009143b56479027538c0d9026e3fb Mon Sep 17 00:00:00 2001 From: Dorian Villet Date: Sat, 7 Nov 2026 11:09:14 +0100 Subject: [PATCH] Resolve the callee's own templates in a closure type gathered against the raw parameter A closure argument is gathered with the raw callable(T): T parameter pushed, so a closure returning its parameter reads back the callee's own T (string&T with a native string type). That type then took part in the inference of T, which kept the self-reference: the closure parameter was 'a'|'b'|(string&T), and an exhaustive match on it was reported as unhandled. The callee's own templates in the gathered type are now resolved from the other arguments gathered so far, falling back to the template's default or bound when they say nothing about it or pass no value of it (an empty array). The gather is unchanged when the closure type does not reference them. Mirrored in the native ArgumentsHandler. Co-Authored-By: Claude Opus 5.5 --- src/Analyser/ArgumentsHandler.php | 95 +++++++- tests/PHPStan/Analyser/nsrt/bug-15654.php | 105 +++++++++ .../Comparison/MatchExpressionRuleTest.php | 12 + .../Rules/Comparison/data/bug-15654.php | 22 ++ turbo-ext/src/ArgumentsHandler.cpp | 223 ++++++++++++++---- turbo-ext/src/generated/ArgumentsHandler.h | 189 ++++++++------- 6 files changed, 519 insertions(+), 127 deletions(-) create mode 100644 tests/PHPStan/Analyser/nsrt/bug-15654.php create mode 100644 tests/PHPStan/Rules/Comparison/data/bug-15654.php diff --git a/src/Analyser/ArgumentsHandler.php b/src/Analyser/ArgumentsHandler.php index 12c8c49a665..5b38d47d033 100644 --- a/src/Analyser/ArgumentsHandler.php +++ b/src/Analyser/ArgumentsHandler.php @@ -44,6 +44,7 @@ use PHPStan\Type\FunctionParameterClosureThisExtension; use PHPStan\Type\FunctionParameterClosureTypeExtension; use PHPStan\Type\FunctionParameterOutTypeExtension; +use PHPStan\Type\Generic\TemplateType; use PHPStan\Type\Generic\TemplateTypeHelper; use PHPStan\Type\Generic\TemplateTypeMap; use PHPStan\Type\Generic\TemplateTypeVariance; @@ -51,6 +52,7 @@ use PHPStan\Type\MethodParameterClosureTypeExtension; use PHPStan\Type\MethodParameterOutTypeExtension; use PHPStan\Type\MixedType; +use PHPStan\Type\NeverType; use PHPStan\Type\ObjectWithoutClassType; use PHPStan\Type\ResourceType; use PHPStan\Type\StaticMethodParameterClosureThisExtension; @@ -59,6 +61,7 @@ use PHPStan\Type\ThisType; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; +use PHPStan\Type\TypeTraverser; use PHPStan\Type\TypeUtils; use function array_keys; use function array_last; @@ -234,7 +237,7 @@ public function processArgs( // resolution (see gatherClosureArgType()). $originalArgForGather = $arg->getAttribute(ArgumentsNormalizer::ORIGINAL_ARG_ATTRIBUTE) ?? $arg; $gatheredArgTypeByIndex[$i] = $typeDrivenAcceptorSelection - ? $this->gatherClosureArgType($parametersAcceptors, $i, $arg->value, $scope) + ? $this->gatherClosureArgType($nodeScopeResolver, $args, $parametersAcceptors, $namedArgumentsVariants, $gatheredArgTypeByIndex, $i, $arg->value, $scope) : $this->closureTypeResolver->getClosureType($scope, $arg->value, true, $storage); $this->addGatheredArgType($gatheredTypes, $gatheredUnpack, $gatheredHasName, $originalArgForGather, $i, $gatheredArgTypeByIndex[$i]); } @@ -957,9 +960,26 @@ private function argConsumesResolvedParameterType(Expr $value): bool * resolved from sibling args. That keeps the inferred return type (the U in * callable(T): U) faithful to the closure's own declaration. * + * A template of the callee that the raw parameter leaks into the closure + * type (the T in callable(T): T, read back from a closure returning its + * parameter) would infer T from T itself, so it is resolved from the other + * arguments gathered so far instead (see resolveCalleeTemplateTypes()). + * + * @param Node\Arg[] $args * @param ParametersAcceptor[] $parametersAcceptors + * @param ParametersAcceptor[]|null $namedArgumentsVariants + * @param array $gatheredArgTypeByIndex */ - private function gatherClosureArgType(array $parametersAcceptors, int $i, Expr $closureExpr, MutatingScope $scope): Type + private function gatherClosureArgType( + NodeScopeResolver $nodeScopeResolver, + array $args, + array $parametersAcceptors, + ?array $namedArgumentsVariants, + array $gatheredArgTypeByIndex, + int $i, + Expr $closureExpr, + MutatingScope $scope, + ): Type { $rawParameter = null; if (count($parametersAcceptors) === 1) { @@ -971,11 +991,76 @@ private function gatherClosureArgType(array $parametersAcceptors, int $i, Expr $ } } - if ($rawParameter !== null) { - $scope = $scope->pushInFunctionCall(null, $rawParameter, false); + if ($rawParameter === null) { + return $this->closureParameterResolver->resolveCallableTypeForScope($closureExpr, $scope); + } + + $closureType = $this->closureParameterResolver->resolveCallableTypeForScope( + $closureExpr, + $scope->pushInFunctionCall(null, $rawParameter, false), + ); + + $calleeTemplateTypeMap = $parametersAcceptors[0]->getTemplateTypeMap(); + if ($calleeTemplateTypeMap->isEmpty() || !self::referencesCalleeTemplateTypes($closureType, $calleeTemplateTypeMap)) { + return $closureType; + } + + $siblingTypes = []; + $siblingUnpack = false; + $siblingHasName = false; + foreach ($args as $j => $siblingArg) { + $siblingOriginalArg = $siblingArg->getAttribute(ArgumentsNormalizer::ORIGINAL_ARG_ATTRIBUTE) ?? $siblingArg; + $this->addGatheredArgType($siblingTypes, $siblingUnpack, $siblingHasName, $siblingOriginalArg, $j, $j !== $i ? ($gatheredArgTypeByIndex[$j] ?? new MixedType()) : new MixedType()); + } + + return self::resolveCalleeTemplateTypes( + $closureType, + $calleeTemplateTypeMap, + $this->selectArgsMetadataAcceptor($nodeScopeResolver, $args, $siblingTypes, $parametersAcceptors, $namedArgumentsVariants, $siblingHasName, $siblingUnpack, $scope)->getResolvedTemplateTypeMap(), + ); + } + + private static function referencesCalleeTemplateTypes(Type $type, TemplateTypeMap $calleeTemplateTypeMap): bool + { + if (!$type->hasTemplateOrLateResolvableType()) { + return false; + } + + foreach ($type->getReferencedTemplateTypes(TemplateTypeVariance::createInvariant()) as $reference) { + if (self::isCalleeTemplateType($reference->getType(), $calleeTemplateTypeMap)) { + return true; + } } - return $this->closureParameterResolver->resolveCallableTypeForScope($closureExpr, $scope); + return false; + } + + /** + * Replaces the callee's own template types with what the other arguments + * resolve them to - their default or bound when they say nothing about them, + * or pass no value of them at all (never, from an empty array). + */ + private static function resolveCalleeTemplateTypes(Type $type, TemplateTypeMap $calleeTemplateTypeMap, TemplateTypeMap $resolvedTemplateTypeMap): Type + { + return TypeTraverser::map($type, static function (Type $type, callable $traverse) use ($calleeTemplateTypeMap, $resolvedTemplateTypeMap): Type { + if (!$type instanceof TemplateType || !self::isCalleeTemplateType($type, $calleeTemplateTypeMap)) { + return $traverse($type); + } + + $resolvedType = $resolvedTemplateTypeMap->getType($type->getName()); + if ($resolvedType === null || $resolvedType instanceof ErrorType || $resolvedType instanceof NeverType) { + return $traverse($type->getDefault() ?? $type->getBound()); + } + + return $resolvedType; + }); + } + + private static function isCalleeTemplateType(TemplateType $type, TemplateTypeMap $calleeTemplateTypeMap): bool + { + $calleeTemplateType = $calleeTemplateTypeMap->getType($type->getName()); + + return $calleeTemplateType instanceof TemplateType && $calleeTemplateType->getScope()->equals($type->getScope()); } /** diff --git a/tests/PHPStan/Analyser/nsrt/bug-15654.php b/tests/PHPStan/Analyser/nsrt/bug-15654.php new file mode 100644 index 00000000000..34dedf6bc3e --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-15654.php @@ -0,0 +1,105 @@ += 8.0 + +declare(strict_types = 1); + +namespace Bug15654; + +use function PHPStan\Testing\assertType; + +/** + * @template T + * @param list $list + * @param callable(T): T $fn + */ +function apply(array $list, callable $fn): void {} + +apply(['a', 'b'], static function (string $s): string { + assertType('\'a\'|\'b\'', $s); + echo match ($s) { 'a' => 1, 'b' => 2 }; + return $s; +}); + +apply(['a', 'b'], static function (string $s): string { + assertType('\'a\'|\'b\'', $s); + echo match ($s) { 'a' => 1, 'b' => 2, default => throw new \LogicException() }; + return $s; +}); + +apply(['a', 'b'], static function ($s) { + assertType('\'a\'|\'b\'', $s); + return $s; +}); + +apply([], static function (string $s): string { + assertType('string', $s); + return $s; +}); + +/** + * @template T + * @param list $list + * @param callable(T): T $fn + * @return list + */ +function map(array $list, callable $fn): array +{ + return $list; +} + +function (): void { + assertType('list<\'a\'|\'b\'>', map(['a', 'b'], static fn (string $s): string => $s)); + assertType('list', map(['a', 'b'], static fn (string $s): string => $s . 'x')); +}; + +/** + * @template T + * @param callable(T): T $fn + * @return T + */ +function only(callable $fn) +{ + return $fn(null); +} + +function (): void { + assertType('string', only(static fn (string $s): string => $s)); + assertType('mixed', only(static fn ($s) => $s)); +}; + +class Collection +{ + + /** + * @template T + * @param list $list + * @param callable(T): T $fn + * @return list + */ + public function map(array $list, callable $fn): array + { + return $list; + } + + /** + * @template T + * @param list $list + * @param callable(T): T $fn + * @return list + */ + public static function staticMap(array $list, callable $fn): array + { + return $list; + } + +} + +function (Collection $c): void { + assertType('list<\'a\'|\'b\'>', $c->map(['a', 'b'], static function (string $s): string { + assertType('\'a\'|\'b\'', $s); + return $s; + })); + assertType('list<\'a\'|\'b\'>', Collection::staticMap(['a', 'b'], static function (string $s): string { + assertType('\'a\'|\'b\'', $s); + return $s; + })); +}; diff --git a/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php b/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php index e216d084f33..4e356d09299 100644 --- a/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php @@ -502,6 +502,18 @@ public function testBug12241(): void $this->analyse([__DIR__ . '/data/bug-12241.php'], []); } + #[RequiresPhp('>= 8.0.0')] + public function testBug15654(): void + { + $this->analyse([__DIR__ . '/data/bug-15654.php'], [ + [ + 'Match arm comparison between \'b\' and \'b\' is always true.', + 20, + 'Remove remaining cases below this one and this error will disappear too.', + ], + ]); + } + #[RequiresPhp('>= 8.0.0')] public function testBug14412(): void { diff --git a/tests/PHPStan/Rules/Comparison/data/bug-15654.php b/tests/PHPStan/Rules/Comparison/data/bug-15654.php new file mode 100644 index 00000000000..3ebc540b29e --- /dev/null +++ b/tests/PHPStan/Rules/Comparison/data/bug-15654.php @@ -0,0 +1,22 @@ += 8.0 + +declare(strict_types = 1); + +namespace Bug15654Match; + +/** + * @template T + * @param list $list + * @param callable(T): T $fn + */ +function apply(array $list, callable $fn): void {} + +apply(['a', 'b'], static function (string $s): string { + echo match ($s) { 'a' => 1, 'b' => 2 }; + return $s; +}); + +apply(['a', 'b'], static function (string $s): string { + echo match ($s) { 'a' => 1, 'b' => 2, default => throw new \LogicException() }; + return $s; +}); diff --git a/turbo-ext/src/ArgumentsHandler.cpp b/turbo-ext/src/ArgumentsHandler.cpp index 6e1e1651e14..95a1b55c23c 100644 --- a/turbo-ext/src/ArgumentsHandler.cpp +++ b/turbo-ext/src/ArgumentsHandler.cpp @@ -829,6 +829,126 @@ zv::Val argResultsDependencies(HashTable *argResults) /* }}} */ +/* {{{ the callee's own template types in a gathered closure type */ + +/* $type->getName() of a template type (a string); UNDEF = pending exception */ +zv::Val templateTypeName(zval *type) +{ + zv::Val name = pt_type_call(Z_OBJ_P(type), PT_LC("getname"), 0, NULL); + if (UNEXPECTED(name.isUndef())) return zv::Val(); + if (UNEXPECTED(!zv::Ref(name.raw()).isString())) { + zend_type_error("phpstan_turbo: getName() must return string"); + return zv::Val(); + } + return name; +} + +/* Mirrors ArgumentsHandler::isCalleeTemplateType() of a template type; false + * = pending exception */ +[[nodiscard]] bool isCalleeTemplateType(zval *type, zval *calleeTemplateTypeMap, bool &out) +{ + out = false; + zv::Val name = templateTypeName(type); + if (UNEXPECTED(name.isUndef())) return false; + zv::Val calleeTemplateType = pt_template_type_map_get_type(calleeTemplateTypeMap, Z_STR_P(name.raw())); + if (UNEXPECTED(calleeTemplateType.isUndef())) return false; + bool calleeIsTemplate; + if (UNEXPECTED(!pt_type_instanceof(calleeTemplateType.raw(), PT_CLASS_TEMPLATE_TYPE, calleeIsTemplate))) return false; + if (!calleeIsTemplate) return true; + zv::Val calleeScope = pt_type_call(Z_OBJ_P(calleeTemplateType.raw()), PT_LC("getscope"), 0, NULL); + if (UNEXPECTED(calleeScope.isUndef())) return false; + zv::Val scope = pt_type_call(Z_OBJ_P(type), PT_LC("getscope"), 0, NULL); + if (UNEXPECTED(scope.isUndef())) return false; + return pt_template_type_scope_equals(calleeScope.raw(), scope.raw(), out); +} + +/* Mirrors ArgumentsHandler::referencesCalleeTemplateTypes(); false = pending + * exception */ +[[nodiscard]] bool referencesCalleeTemplateTypes(zval *type, zval *calleeTemplateTypeMap, bool &out) +{ + out = false; + zv::Val hasTemplate = pt_type_op(Z_OBJ_P(type), PT_OP_HAS_TEMPLATE_OR_LATE_RESOLVABLE_TYPE, 0, NULL); + if (UNEXPECTED(hasTemplate.isUndef())) return false; + if (!zend_is_true(hasTemplate.raw())) return true; + zval *invariant = pt_template_type_variance_singleton(PT_TEMPLATE_TYPE_VARIANCE_INVARIANT); + if (UNEXPECTED(invariant == NULL)) return false; + zv::Val references = pt_type_op(Z_OBJ_P(type), PT_OP_GET_REFERENCED_TEMPLATE_TYPES, 1, invariant); + if (UNEXPECTED(references.isUndef())) return false; + if (UNEXPECTED(!zv::Ref(references.raw()).isArray())) { + zend_type_error("phpstan_turbo: getReferencedTemplateTypes() must return array"); + return false; + } + for (zv::ArrayEntry entry : zv::ArrRef(references.raw())) { + zv::Ref reference = entry.value().deref(); + if (UNEXPECTED(!reference.isObject())) { + zend_type_error("phpstan_turbo: a template type reference must be an object"); + return false; + } + zv::Val referenceType, positionVariance; + if (UNEXPECTED(!pt_template_type_reference_parts(reference.raw(), referenceType, positionVariance))) return false; + bool isCallee; + if (UNEXPECTED(!isCalleeTemplateType(referenceType.raw(), calleeTemplateTypeMap, isCallee))) return false; + if (isCallee) { + out = true; + return true; + } + } + return true; +} + +/* the traversal callback of ArgumentsHandler::resolveCalleeTemplateTypes() - + * state0: the callee's template type map, state1: the resolved one */ +void resolveCalleeTemplateTypesBody(zval *calleeTemplateTypeMap, zval *resolvedTemplateTypeMap, uint32_t argc, zval *argv, zval *return_value) +{ + if (UNEXPECTED(argc < 2 || Z_TYPE(argv[0]) != IS_OBJECT)) { + zend_type_error("ArgumentsHandler::resolveCalleeTemplateTypes() traversal: expected (Type $type, callable $traverse)"); + return; + } + zval *type = &argv[0]; + bool isCallee; + if (UNEXPECTED(!pt_type_instanceof(type, PT_CLASS_TEMPLATE_TYPE, isCallee))) return; + if (isCallee && UNEXPECTED(!isCalleeTemplateType(type, calleeTemplateTypeMap, isCallee))) return; + if (!isCallee) { + (void) pt_type_traverser_traverse(return_value, &argv[1], type); + return; + } + + zv::Val name = templateTypeName(type); + if (UNEXPECTED(name.isUndef())) return; + zv::Val resolvedType = pt_template_type_map_get_type(resolvedTemplateTypeMap, Z_STR_P(name.raw())); + if (UNEXPECTED(resolvedType.isUndef())) return; + bool fallBack = resolvedType.isNull(); + if (!fallBack) { + bool isError, isNever; + (void) pt_type_instanceof_ce(resolvedType.raw(), pt_ce_error_type, isError); + (void) pt_type_instanceof_ce(resolvedType.raw(), pt_ce_never_type, isNever); + fallBack = isError || isNever; + } + if (fallBack) { + /* $type->getDefault() ?? $type->getBound() */ + zv::Val fallback = pt_type_call(Z_OBJ_P(type), PT_LC("getdefault"), 0, NULL); + if (UNEXPECTED(fallback.isUndef())) return; + if (fallback.isNull()) { + fallback = pt_type_call(Z_OBJ_P(type), PT_LC("getbound"), 0, NULL); + if (UNEXPECTED(fallback.isUndef())) return; + } + (void) pt_type_traverser_traverse(return_value, &argv[1], fallback.raw()); + return; + } + + resolvedType.intoReturnValue(return_value); +} + +/* Mirrors ArgumentsHandler::resolveCalleeTemplateTypes() */ +zv::Val resolveCalleeTemplateTypes(zval *type, zval *calleeTemplateTypeMap, zval *resolvedTemplateTypeMap) +{ + zv::Val callback = pt_type_native_callback(resolveCalleeTemplateTypesBody, calleeTemplateTypeMap, resolvedTemplateTypeMap); + if (UNEXPECTED(callback.isUndef())) return zv::Val(); + return pt_type_traverser_map_of(type, callback.raw()); +} + +/* }}} */ + } // namespace namespace phpstanturbo { @@ -976,42 +1096,6 @@ class ArgumentsHandler return true; } - /* Mirrors gatherClosureArgType() */ - zv::Val gatherClosureArgType(HashTable *parametersAcceptors, zend_ulong i, zval *closureExpr, zval *scope) const - { - zv::Val rawParametersHold; - zval *rawParameter = NULL; - if (zend_hash_num_elements(parametersAcceptors) == 1) { - zval *acceptor = readIndex(parametersAcceptors, 0); - if (UNEXPECTED(acceptor == NULL)) return zv::Val(); - rawParametersHold = acceptorGetParameters(acceptor); - if (UNEXPECTED(rawParametersHold.isUndef())) return zv::Val(); - if (UNEXPECTED(!requireArray(rawParametersHold.raw(), "getParameters()"))) return zv::Val(); - HashTable *rawParameters = Z_ARRVAL_P(rawParametersHold.raw()); - rawParameter = issetIndex(rawParameters, i); - if (rawParameter == NULL && zend_hash_num_elements(rawParameters) > 0) { - bool isVariadic = false; - acceptor = readIndex(parametersAcceptors, 0); - if (UNEXPECTED(acceptor == NULL || !acceptorIsVariadic(acceptor, isVariadic))) return zv::Val(); - if (isVariadic) { - rawParameter = arrayLast(rawParameters); - ZVAL_DEREF(rawParameter); - } - } - } - - zv::Val pushedScope; - if (rawParameter != NULL && Z_TYPE_P(rawParameter) != IS_NULL) { - zval null; - ZVAL_NULL(&null); - pushedScope = pt_mutating_scope_push_in_function_call(Z_OBJ_P(scope), &null, rawParameter, false); - if (UNEXPECTED(pushedScope.isUndef())) return zv::Val(); - scope = pushedScope.raw(); - } - - return closureParameterResolverResolveCallableTypeForScope(slot(slots::closureParameterResolver), closureExpr, scope); - } - /* Mirrors selectArgsAcceptor() */ static zv::Val selectArgsAcceptor(zval *types, zval *parametersAcceptors, zval *namedArgumentsVariants, bool hasName, bool unpack) { @@ -1733,8 +1817,9 @@ class ArgumentsHandler } /* the metadata acceptor selected over every argument's gathered type - * (allMixed: over mixed for all of them), padded with mixed */ - zend_never_inline zv::Val paddedMetadataAcceptor(Walk &w, bool allMixed) const + * (allMixed: over mixed for all of them; mixedKey: over mixed for that + * argument), padded with mixed */ + zend_never_inline zv::Val paddedMetadataAcceptor(Walk &w, bool allMixed, const zend_ulong *mixedKey = NULL) const { zv::Arr paddedTypes = zv::Arr::empty(); bool paddedUnpack = false; @@ -1744,7 +1829,7 @@ class ArgumentsHandler zval *paddedOriginalArg = originalArgOf(record.arg); zv::Val mixed; zval *type; - if (!allMixed && Z_TYPE(record.gathered) != IS_UNDEF && Z_TYPE(record.gathered) != IS_NULL) { + if (!allMixed && (mixedKey == NULL || record.key != *mixedKey) && Z_TYPE(record.gathered) != IS_UNDEF && Z_TYPE(record.gathered) != IS_NULL) { type = &record.gathered; } else { mixed = pt_type_new_mixed_type(); @@ -2428,6 +2513,64 @@ class ArgumentsHandler return completeOtherArg(w, record, value, a, a.exprResult.raw(), a.enterExpressionAssignForByRef); } + /* Mirrors gatherClosureArgType() */ + zv::Val gatherClosureArgType(Walk &w, zend_ulong i, zval *closureExpr) const + { + HashTable *parametersAcceptors = Z_ARRVAL_P(w.parametersAcceptors); + zval *scope = w.scope.raw(); + zv::Val rawParametersHold; + zval *rawParameter = NULL; + zval *acceptor = NULL; + if (zend_hash_num_elements(parametersAcceptors) == 1) { + acceptor = readIndex(parametersAcceptors, 0); + if (UNEXPECTED(acceptor == NULL)) return zv::Val(); + rawParametersHold = acceptorGetParameters(acceptor); + if (UNEXPECTED(rawParametersHold.isUndef())) return zv::Val(); + if (UNEXPECTED(!requireArray(rawParametersHold.raw(), "getParameters()"))) return zv::Val(); + HashTable *rawParameters = Z_ARRVAL_P(rawParametersHold.raw()); + rawParameter = issetIndex(rawParameters, i); + if (rawParameter == NULL && zend_hash_num_elements(rawParameters) > 0) { + bool isVariadic = false; + if (UNEXPECTED(!acceptorIsVariadic(acceptor, isVariadic))) return zv::Val(); + if (isVariadic) { + rawParameter = arrayLast(rawParameters); + ZVAL_DEREF(rawParameter); + } + } + } + + if (rawParameter == NULL || Z_TYPE_P(rawParameter) == IS_NULL) { + return closureParameterResolverResolveCallableTypeForScope(slot(slots::closureParameterResolver), closureExpr, scope); + } + + zval null; + ZVAL_NULL(&null); + zv::Val pushedScope = pt_mutating_scope_push_in_function_call(Z_OBJ_P(scope), &null, rawParameter, false); + if (UNEXPECTED(pushedScope.isUndef())) return zv::Val(); + zv::Val closureType = closureParameterResolverResolveCallableTypeForScope(slot(slots::closureParameterResolver), closureExpr, pushedScope.raw()); + if (UNEXPECTED(closureType.isUndef())) return zv::Val(); + + zv::Val calleeTemplateTypeMap = pt_parameters_acceptor_call(acceptor, PT_PA_GET_TEMPLATE_TYPE_MAP); + if (UNEXPECTED(calleeTemplateTypeMap.isUndef())) return zv::Val(); + if (UNEXPECTED(!zv::Ref(calleeTemplateTypeMap.raw()).isObject())) { + zend_type_error("phpstan_turbo: getTemplateTypeMap() must return an object"); + return zv::Val(); + } + zv::Val isEmpty = pt_type_call(Z_OBJ_P(calleeTemplateTypeMap.raw()), PT_LC("isempty"), 0, NULL); + if (UNEXPECTED(isEmpty.isUndef())) return zv::Val(); + if (zend_is_true(isEmpty.raw())) return closureType; + bool references; + if (UNEXPECTED(!referencesCalleeTemplateTypes(closureType.raw(), calleeTemplateTypeMap.raw(), references))) return zv::Val(); + if (!references) return closureType; + + zv::Val siblingAcceptor = paddedMetadataAcceptor(w, false, &i); + if (UNEXPECTED(siblingAcceptor.isUndef())) return zv::Val(); + zv::Val resolvedTemplateTypeMap = pt_parameters_acceptor_call(siblingAcceptor.raw(), PT_PA_GET_RESOLVED_TEMPLATE_TYPE_MAP); + if (UNEXPECTED(resolvedTemplateTypeMap.isUndef())) return zv::Val(); + + return resolveCalleeTemplateTypes(closureType.raw(), calleeTemplateTypeMap.raw(), resolvedTemplateTypeMap.raw()); + } + /* the closure-type gather ahead of a closure / arrow function argument's * metadata; false = pending exception */ zend_never_inline bool gatherClosureArg(Walk &w, ArgRecord &record, zval *value) const @@ -2436,7 +2579,7 @@ class ArgumentsHandler // the evolving scope, before the body is processed zval *originalArgForGather = originalArgOf(record.arg); zv::Val gathered = w.typeDrivenAcceptorSelection - ? gatherClosureArgType(Z_ARRVAL_P(w.parametersAcceptors), record.key, value, w.scope.raw()) + ? gatherClosureArgType(w, record.key, value) : closureTypeResolverGetClosureType(slot(slots::closureTypeResolver), w.scope.raw(), value, true, w.storage); if (UNEXPECTED(gathered.isUndef())) return false; zval_ptr_dtor(&record.gathered); diff --git a/turbo-ext/src/generated/ArgumentsHandler.h b/turbo-ext/src/generated/ArgumentsHandler.h index d8e3af1f82b..b9e44b6aaa3 100644 --- a/turbo-ext/src/generated/ArgumentsHandler.h +++ b/turbo-ext/src/generated/ArgumentsHandler.h @@ -116,41 +116,49 @@ inline constexpr char strings[] = "value\0" /* 1382 */ "PhpParser\\Node\\Expr\0" /* 1388 */ "argConsumesResolvedParameterType\0" /* 1408 */ - "closureExpr\0" /* 1441 */ - "gatherClosureArgType\0" /* 1453 */ - "args\0" /* 1474 */ - "PHPStan\\Reflection\\ParametersAcceptor\0" /* 1479 */ - "selectCountStableMetadataAcceptor\0" /* 1517 */ - "acceptor\0" /* 1551 */ - "arg\0" /* 1560 */ - "PHPStan\\Reflection\\ParameterReflection\0" /* 1564 */ - "matchArgParameter\0" /* 1603 */ - "selectArgsAcceptor\0" /* 1621 */ - "gatheredTypes\0" /* 1640 */ - "selectArgsMetadataAcceptor\0" /* 1654 */ - "originalCall\0" /* 1681 */ - "normalizedCall\0" /* 1694 */ - "processDroppedArgs\0" /* 1709 */ - "parameter\0" /* 1728 */ - "parameterType\0" /* 1738 */ - "callCallbackImmediately\0" /* 1752 */ - "shouldInvalidateCallbackExpressions\0" /* 1776 */ - "getParameterTypeFromParameterClosureTypeExtension\0" /* 1812 */ - "currentParameter\0" /* 1862 */ - "getParameterOutExtensionsType\0" /* 1879 */ - "call\0" /* 1909 */ - "resolveClosureThisType\0" /* 1914 */ - "position\0" /* 1937 */ - "unpackedType\0" /* 1946 */ - "isPure\0" /* 1959 */ - "observeUnpackedArgument\0" /* 1966 */ - "valueType\0" /* 1990 */ - "observeArgumentValue\0" /* 2000 */ - "findOriginalParameterType\0" /* 2021 */ - "argResults\0" /* 2047 */ - "argValue\0" /* 2058 */ - "PHPStan\\Analyser\\ExpressionResult\0" /* 2067 */ - "readArgResult"; /* 2101 */ + "args\0" /* 1441 */ + "gatheredArgTypeByIndex\0" /* 1446 */ + "closureExpr\0" /* 1469 */ + "gatherClosureArgType\0" /* 1481 */ + "calleeTemplateTypeMap\0" /* 1502 */ + "PHPStan\\Type\\Generic\\TemplateTypeMap\0" /* 1524 */ + "referencesCalleeTemplateTypes\0" /* 1561 */ + "resolvedTemplateTypeMap\0" /* 1591 */ + "resolveCalleeTemplateTypes\0" /* 1615 */ + "PHPStan\\Type\\Generic\\TemplateType\0" /* 1642 */ + "isCalleeTemplateType\0" /* 1676 */ + "PHPStan\\Reflection\\ParametersAcceptor\0" /* 1697 */ + "selectCountStableMetadataAcceptor\0" /* 1735 */ + "acceptor\0" /* 1769 */ + "arg\0" /* 1778 */ + "PHPStan\\Reflection\\ParameterReflection\0" /* 1782 */ + "matchArgParameter\0" /* 1821 */ + "selectArgsAcceptor\0" /* 1839 */ + "gatheredTypes\0" /* 1858 */ + "selectArgsMetadataAcceptor\0" /* 1872 */ + "originalCall\0" /* 1899 */ + "normalizedCall\0" /* 1912 */ + "processDroppedArgs\0" /* 1927 */ + "parameter\0" /* 1946 */ + "parameterType\0" /* 1956 */ + "callCallbackImmediately\0" /* 1970 */ + "shouldInvalidateCallbackExpressions\0" /* 1994 */ + "getParameterTypeFromParameterClosureTypeExtension\0" /* 2030 */ + "currentParameter\0" /* 2080 */ + "getParameterOutExtensionsType\0" /* 2097 */ + "call\0" /* 2127 */ + "resolveClosureThisType\0" /* 2132 */ + "position\0" /* 2155 */ + "unpackedType\0" /* 2164 */ + "isPure\0" /* 2177 */ + "observeUnpackedArgument\0" /* 2184 */ + "valueType\0" /* 2208 */ + "observeArgumentValue\0" /* 2218 */ + "findOriginalParameterType\0" /* 2239 */ + "argResults\0" /* 2265 */ + "argValue\0" /* 2276 */ + "PHPStan\\Analyser\\ExpressionResult\0" /* 2285 */ + "readArgResult"; /* 2319 */ inline constexpr reg::PackedArg args[] = { reg::packed(0, 0, 25), /* __construct $templateArgumentObserver */ reg::packed(76, 0, 100), /* __construct $expressionResultFactory */ @@ -190,83 +198,97 @@ inline constexpr reg::PackedArg args[] = { reg::packed(1245, MAY_BE_VOID), /* addGatheredArgType return */ reg::packed(1382, 0, 1388), /* argConsumesResolvedParameterType $value */ reg::packed(1245, MAY_BE_BOOL), /* argConsumesResolvedParameterType return */ + reg::packed(832, 0, 850), /* gatherClosureArgType $nodeScopeResolver */ + reg::packed(1441, MAY_BE_ARRAY), /* gatherClosureArgType $args */ reg::packed(993, MAY_BE_ARRAY), /* gatherClosureArgType $parametersAcceptors */ + reg::packed(1013, MAY_BE_NULL | MAY_BE_ARRAY), /* gatherClosureArgType $namedArgumentsVariants */ + reg::packed(1446, MAY_BE_ARRAY), /* gatherClosureArgType $gatheredArgTypeByIndex */ reg::packed(1338, MAY_BE_LONG), /* gatherClosureArgType $i */ - reg::packed(1441, 0, 1388), /* gatherClosureArgType $closureExpr */ + reg::packed(1469, 0, 1388), /* gatherClosureArgType $closureExpr */ reg::packed(1074, 0, 1080), /* gatherClosureArgType $scope */ reg::packed(1245, 0, 1345), /* gatherClosureArgType return */ + reg::packed(1340, 0, 1345), /* referencesCalleeTemplateTypes $type */ + reg::packed(1502, 0, 1524), /* referencesCalleeTemplateTypes $calleeTemplateTypeMap */ + reg::packed(1245, MAY_BE_BOOL), /* referencesCalleeTemplateTypes return */ + reg::packed(1340, 0, 1345), /* resolveCalleeTemplateTypes $type */ + reg::packed(1502, 0, 1524), /* resolveCalleeTemplateTypes $calleeTemplateTypeMap */ + reg::packed(1591, 0, 1524), /* resolveCalleeTemplateTypes $resolvedTemplateTypeMap */ + reg::packed(1245, 0, 1345), /* resolveCalleeTemplateTypes return */ + reg::packed(1340, 0, 1642), /* isCalleeTemplateType $type */ + reg::packed(1502, 0, 1524), /* isCalleeTemplateType $calleeTemplateTypeMap */ + reg::packed(1245, MAY_BE_BOOL), /* isCalleeTemplateType return */ reg::packed(832, 0, 850), /* selectCountStableMetadataAcceptor $nodeScopeResolver */ - reg::packed(1474, MAY_BE_ARRAY), /* selectCountStableMetadataAcceptor $args */ + reg::packed(1441, MAY_BE_ARRAY), /* selectCountStableMetadataAcceptor $args */ reg::packed(993, MAY_BE_ARRAY), /* selectCountStableMetadataAcceptor $parametersAcceptors */ reg::packed(1013, MAY_BE_NULL | MAY_BE_ARRAY), /* selectCountStableMetadataAcceptor $namedArgumentsVariants */ reg::packed(1074, 0, 1080), /* selectCountStableMetadataAcceptor $scope */ - reg::packed(1245, 0, 1479), /* selectCountStableMetadataAcceptor return */ - reg::packed(1551, 0, 1479), /* matchArgParameter $acceptor */ - reg::packed(1560, 0, 1319), /* matchArgParameter $arg */ + reg::packed(1245, 0, 1697), /* selectCountStableMetadataAcceptor return */ + reg::packed(1769, 0, 1697), /* matchArgParameter $acceptor */ + reg::packed(1778, 0, 1319), /* matchArgParameter $arg */ reg::packed(1338, MAY_BE_LONG), /* matchArgParameter $i */ - reg::packed(1245, MAY_BE_NULL, 1564), /* matchArgParameter return */ + reg::packed(1245, MAY_BE_NULL, 1782), /* matchArgParameter return */ reg::packed(1286, MAY_BE_ARRAY), /* selectArgsAcceptor $types */ reg::packed(993, MAY_BE_ARRAY), /* selectArgsAcceptor $parametersAcceptors */ reg::packed(1013, MAY_BE_NULL | MAY_BE_ARRAY), /* selectArgsAcceptor $namedArgumentsVariants */ reg::packed(1299, MAY_BE_BOOL), /* selectArgsAcceptor $hasName */ reg::packed(1292, MAY_BE_BOOL), /* selectArgsAcceptor $unpack */ - reg::packed(1245, 0, 1479), /* selectArgsAcceptor return */ + reg::packed(1245, 0, 1697), /* selectArgsAcceptor return */ reg::packed(832, 0, 850), /* selectArgsMetadataAcceptor $nodeScopeResolver */ - reg::packed(1474, MAY_BE_ARRAY), /* selectArgsMetadataAcceptor $args */ - reg::packed(1640, MAY_BE_ARRAY), /* selectArgsMetadataAcceptor $gatheredTypes */ + reg::packed(1441, MAY_BE_ARRAY), /* selectArgsMetadataAcceptor $args */ + reg::packed(1858, MAY_BE_ARRAY), /* selectArgsMetadataAcceptor $gatheredTypes */ reg::packed(993, MAY_BE_ARRAY), /* selectArgsMetadataAcceptor $parametersAcceptors */ reg::packed(1013, MAY_BE_NULL | MAY_BE_ARRAY), /* selectArgsMetadataAcceptor $namedArgumentsVariants */ reg::packed(1299, MAY_BE_BOOL), /* selectArgsMetadataAcceptor $hasName */ reg::packed(1292, MAY_BE_BOOL), /* selectArgsMetadataAcceptor $unpack */ reg::packed(1074, 0, 1080), /* selectArgsMetadataAcceptor $scope */ - reg::packed(1245, 0, 1479), /* selectArgsMetadataAcceptor return */ + reg::packed(1245, 0, 1697), /* selectArgsMetadataAcceptor return */ reg::packed(832, 0, 850), /* processDroppedArgs $nodeScopeResolver */ reg::packed(885, 0, 890), /* processDroppedArgs $stmt */ - reg::packed(1681, 0, 1045), /* processDroppedArgs $originalCall */ - reg::packed(1694, 0, 1045), /* processDroppedArgs $normalizedCall */ + reg::packed(1899, 0, 1045), /* processDroppedArgs $originalCall */ + reg::packed(1912, 0, 1045), /* processDroppedArgs $normalizedCall */ reg::packed(1074, 0, 1080), /* processDroppedArgs $scope */ reg::packed(1111, 0, 1119), /* processDroppedArgs $storage */ reg::packed(1173, 0, 1181), /* processDroppedArgs $context */ reg::packed(1245, MAY_BE_VOID), /* processDroppedArgs return */ - reg::packed(1728, MAY_BE_NULL, 1564), /* callCallbackImmediately $parameter */ - reg::packed(1738, MAY_BE_NULL, 1345), /* callCallbackImmediately $parameterType */ + reg::packed(1946, MAY_BE_NULL, 1782), /* callCallbackImmediately $parameter */ + reg::packed(1956, MAY_BE_NULL, 1345), /* callCallbackImmediately $parameterType */ reg::packed(910, 0), /* callCallbackImmediately $calleeReflection */ reg::packed(1245, MAY_BE_BOOL), /* callCallbackImmediately return */ - reg::packed(1728, MAY_BE_NULL, 1564), /* shouldInvalidateCallbackExpressions $parameter */ + reg::packed(1946, MAY_BE_NULL, 1782), /* shouldInvalidateCallbackExpressions $parameter */ reg::packed(1245, MAY_BE_BOOL), /* shouldInvalidateCallbackExpressions return */ reg::packed(1036, 0, 1045), /* getParameterTypeFromParameterClosureTypeExtension $callLike */ reg::packed(910, 0), /* getParameterTypeFromParameterClosureTypeExtension $calleeReflection */ - reg::packed(1728, 0, 1564), /* getParameterTypeFromParameterClosureTypeExtension $parameter */ + reg::packed(1946, 0, 1782), /* getParameterTypeFromParameterClosureTypeExtension $parameter */ reg::packed(1074, 0, 1080), /* getParameterTypeFromParameterClosureTypeExtension $scope */ reg::packed(1245, MAY_BE_NULL, 1345), /* getParameterTypeFromParameterClosureTypeExtension return */ reg::packed(1036, 0, 1045), /* getParameterOutExtensionsType $callLike */ reg::packed(910, 0), /* getParameterOutExtensionsType $calleeReflection */ - reg::packed(1862, 0, 1564), /* getParameterOutExtensionsType $currentParameter */ + reg::packed(2080, 0, 1782), /* getParameterOutExtensionsType $currentParameter */ reg::packed(1074, 0, 1080), /* getParameterOutExtensionsType $scope */ reg::packed(1245, MAY_BE_NULL, 1345), /* getParameterOutExtensionsType return */ - reg::packed(1909, MAY_BE_NULL, 1045), /* resolveClosureThisType $call */ + reg::packed(2127, MAY_BE_NULL, 1045), /* resolveClosureThisType $call */ reg::packed(910, 0), /* resolveClosureThisType $calleeReflection */ - reg::packed(1728, 0, 1564), /* resolveClosureThisType $parameter */ + reg::packed(1946, 0, 1782), /* resolveClosureThisType $parameter */ reg::packed(1074, 0, 1080), /* resolveClosureThisType $scope */ reg::packed(1245, MAY_BE_NULL, 1345), /* resolveClosureThisType return */ reg::packed(1074, 0, 1080), /* observeUnpackedArgument $scope */ - reg::packed(1551, 0, 1479), /* observeUnpackedArgument $acceptor */ - reg::packed(1937, MAY_BE_LONG), /* observeUnpackedArgument $position */ - reg::packed(1946, 0, 1345), /* observeUnpackedArgument $unpackedType */ - reg::packed(1959, MAY_BE_BOOL), /* observeUnpackedArgument $isPure */ + reg::packed(1769, 0, 1697), /* observeUnpackedArgument $acceptor */ + reg::packed(2155, MAY_BE_LONG), /* observeUnpackedArgument $position */ + reg::packed(2164, 0, 1345), /* observeUnpackedArgument $unpackedType */ + reg::packed(2177, MAY_BE_BOOL), /* observeUnpackedArgument $isPure */ reg::packed(1245, 0, 1080), /* observeUnpackedArgument return */ reg::packed(1074, 0, 1080), /* observeArgumentValue $scope */ - reg::packed(1551, 0, 1479), /* observeArgumentValue $acceptor */ - reg::packed(1728, 0, 1564), /* observeArgumentValue $parameter */ - reg::packed(1990, 0, 1345), /* observeArgumentValue $valueType */ - reg::packed(1959, MAY_BE_BOOL), /* observeArgumentValue $isPure */ + reg::packed(1769, 0, 1697), /* observeArgumentValue $acceptor */ + reg::packed(1946, 0, 1782), /* observeArgumentValue $parameter */ + reg::packed(2208, 0, 1345), /* observeArgumentValue $valueType */ + reg::packed(2177, MAY_BE_BOOL), /* observeArgumentValue $isPure */ reg::packed(1245, 0, 1080), /* observeArgumentValue return */ - reg::packed(1551, 0, 1479), /* findOriginalParameterType $acceptor */ - reg::packed(1728, 0, 1564), /* findOriginalParameterType $parameter */ + reg::packed(1769, 0, 1697), /* findOriginalParameterType $acceptor */ + reg::packed(1946, 0, 1782), /* findOriginalParameterType $parameter */ reg::packed(1245, MAY_BE_NULL, 1345), /* findOriginalParameterType return */ - reg::packed(2047, MAY_BE_ARRAY), /* readArgResult $argResults */ - reg::packed(2058, 0, 1388), /* readArgResult $argValue */ - reg::packed(1245, 0, 2067), /* readArgResult return */ + reg::packed(2265, MAY_BE_ARRAY), /* readArgResult $argResults */ + reg::packed(2276, 0, 1388), /* readArgResult $argValue */ + reg::packed(1245, 0, 2285), /* readArgResult return */ }; using Sig = reg::Sig; } // namespace sigtab @@ -277,21 +299,24 @@ inline constexpr sigtab::Sig __construct = { { 820 /* __construct */, 16, 0, 16, inline constexpr sigtab::Sig processArgs = { { 1274 /* processArgs */, 11, 16, 12, 28, ZEND_ACC_PUBLIC } }; inline constexpr sigtab::Sig addGatheredArgType = { { 1363 /* addGatheredArgType */, 6, 29, 6, 35, ZEND_ACC_PRIVATE } }; inline constexpr sigtab::Sig argConsumesResolvedParameterType = { { 1408 /* argConsumesResolvedParameterType */, 1, 36, 1, 37, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig gatherClosureArgType = { { 1453 /* gatherClosureArgType */, 4, 38, 4, 42, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig selectCountStableMetadataAcceptor = { { 1517 /* selectCountStableMetadataAcceptor */, 5, 43, 5, 48, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig matchArgParameter = { { 1603 /* matchArgParameter */, 3, 49, 3, 52, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig selectArgsAcceptor = { { 1621 /* selectArgsAcceptor */, 5, 53, 5, 58, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig selectArgsMetadataAcceptor = { { 1654 /* selectArgsMetadataAcceptor */, 8, 59, 8, 67, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processDroppedArgs = { { 1709 /* processDroppedArgs */, 7, 68, 7, 75, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig callCallbackImmediately = { { 1752 /* callCallbackImmediately */, 3, 76, 3, 79, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig shouldInvalidateCallbackExpressions = { { 1776 /* shouldInvalidateCallbackExpressions */, 1, 80, 1, 81, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig getParameterTypeFromParameterClosureTypeExtension = { { 1812 /* getParameterTypeFromParameterClosureTypeExtension */, 4, 82, 4, 86, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig getParameterOutExtensionsType = { { 1879 /* getParameterOutExtensionsType */, 4, 87, 4, 91, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig resolveClosureThisType = { { 1914 /* resolveClosureThisType */, 4, 92, 4, 96, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig observeUnpackedArgument = { { 1966 /* observeUnpackedArgument */, 5, 97, 5, 102, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig observeArgumentValue = { { 2000 /* observeArgumentValue */, 5, 103, 5, 108, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig findOriginalParameterType = { { 2021 /* findOriginalParameterType */, 2, 109, 2, 111, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig readArgResult = { { 2101 /* readArgResult */, 2, 112, 2, 114, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig gatherClosureArgType = { { 1481 /* gatherClosureArgType */, 8, 38, 8, 46, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig referencesCalleeTemplateTypes = { { 1561 /* referencesCalleeTemplateTypes */, 2, 47, 2, 49, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig resolveCalleeTemplateTypes = { { 1615 /* resolveCalleeTemplateTypes */, 3, 50, 3, 53, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig isCalleeTemplateType = { { 1676 /* isCalleeTemplateType */, 2, 54, 2, 56, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig selectCountStableMetadataAcceptor = { { 1735 /* selectCountStableMetadataAcceptor */, 5, 57, 5, 62, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig matchArgParameter = { { 1821 /* matchArgParameter */, 3, 63, 3, 66, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig selectArgsAcceptor = { { 1839 /* selectArgsAcceptor */, 5, 67, 5, 72, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig selectArgsMetadataAcceptor = { { 1872 /* selectArgsMetadataAcceptor */, 8, 73, 8, 81, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processDroppedArgs = { { 1927 /* processDroppedArgs */, 7, 82, 7, 89, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig callCallbackImmediately = { { 1970 /* callCallbackImmediately */, 3, 90, 3, 93, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig shouldInvalidateCallbackExpressions = { { 1994 /* shouldInvalidateCallbackExpressions */, 1, 94, 1, 95, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig getParameterTypeFromParameterClosureTypeExtension = { { 2030 /* getParameterTypeFromParameterClosureTypeExtension */, 4, 96, 4, 100, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig getParameterOutExtensionsType = { { 2097 /* getParameterOutExtensionsType */, 4, 101, 4, 105, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig resolveClosureThisType = { { 2132 /* resolveClosureThisType */, 4, 106, 4, 110, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig observeUnpackedArgument = { { 2184 /* observeUnpackedArgument */, 5, 111, 5, 116, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig observeArgumentValue = { { 2218 /* observeArgumentValue */, 5, 117, 5, 122, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig findOriginalParameterType = { { 2239 /* findOriginalParameterType */, 2, 123, 2, 125, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig readArgResult = { { 2319 /* readArgResult */, 2, 126, 2, 128, ZEND_ACC_PRIVATE } }; } // namespace sig } // namespace ptdecl::ArgumentsHandler