diff --git a/src/Analyser/ArgumentsHandler.php b/src/Analyser/ArgumentsHandler.php index 12c8c49a665..24b022beb1d 100644 --- a/src/Analyser/ArgumentsHandler.php +++ b/src/Analyser/ArgumentsHandler.php @@ -35,6 +35,8 @@ use PHPStan\Reflection\ParameterReflection; use PHPStan\Reflection\ParametersAcceptor; use PHPStan\Reflection\ParametersAcceptorSelector; +use PHPStan\Reflection\Php\DummyParameter; +use PHPStan\Reflection\Php\ExtendedDummyParameter; use PHPStan\Reflection\ResolvedFunctionVariant; use PHPStan\ShouldNotHappenException; use PHPStan\TrinaryLogic; @@ -44,13 +46,16 @@ 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; +use PHPStan\Type\Generic\TemplateTypeVarianceMap; use PHPStan\Type\MethodParameterClosureThisExtension; 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,7 +64,9 @@ use PHPStan\Type\ThisType; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; +use PHPStan\Type\TypeTraverser; use PHPStan\Type\TypeUtils; +use PHPStan\Type\UnionType; use function array_keys; use function array_last; use function array_map; @@ -234,7 +241,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]); } @@ -951,15 +958,35 @@ private function argConsumesResolvedParameterType(Expr $value): bool /** * Resolves the type of a closure/arrow function argument for the generic * gather, mirroring ParametersAcceptorSelector::selectFromArgs(): the closure - * type is read with the RAW (un-generic-resolved) acceptor parameter pushed - * onto the in-function-call stack, so its body sees the template parameter - * (effectively mixed for an untyped param) rather than a parameter already - * resolved from sibling args. That keeps the inferred return type (the U in - * callable(T): U) faithful to the closure's own declaration. + * type is read with the acceptor parameter pushed onto the in-function-call + * stack before its templates are resolved, so the inferred return type (the + * U in callable(T): U) stays faithful to the closure's own declaration. * + * The templates the closure only receives (the T in callable(T): U) are + * resolved from the other arguments gathered so far before the push: left + * as T, an offset or a property read off the closure's parameter is mixed, + * and U would be inferred from that mixed (see resolveReceivedTemplateTypes()). + * + * 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 +998,205 @@ 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); + } + + $siblingTemplateTypeMap = null; + $pushedParameter = $rawParameter; + $receivedTemplateNames = self::getReceivedTemplateNames($rawParameter->getType(), $scope); + if ($receivedTemplateNames !== []) { + $siblingTemplateTypeMap = $this->selectSiblingTemplateTypeMap($nodeScopeResolver, $args, $parametersAcceptors, $namedArgumentsVariants, $gatheredArgTypeByIndex, $i, $scope); + $pushedParameter = self::resolveReceivedTemplateTypes($rawParameter, $receivedTemplateNames, $siblingTemplateTypeMap); + } + + $closureType = $this->closureParameterResolver->resolveCallableTypeForScope( + $closureExpr, + $scope->pushInFunctionCall(null, $pushedParameter, false), + ); + + $calleeTemplateTypeMap = $parametersAcceptors[0]->getTemplateTypeMap(); + if ($calleeTemplateTypeMap->isEmpty() || !self::referencesCalleeTemplateTypes($closureType, $calleeTemplateTypeMap)) { + return $closureType; + } + + return self::resolveCalleeTemplateTypes( + $closureType, + $calleeTemplateTypeMap, + $siblingTemplateTypeMap ?? $this->selectSiblingTemplateTypeMap($nodeScopeResolver, $args, $parametersAcceptors, $namedArgumentsVariants, $gatheredArgTypeByIndex, $i, $scope), + ); + } + + /** + * The template types resolved from every argument gathered so far except + * the i-th one, which counts as mixed. + * + * @param Node\Arg[] $args + * @param ParametersAcceptor[] $parametersAcceptors + * @param ParametersAcceptor[]|null $namedArgumentsVariants + * @param array $gatheredArgTypeByIndex + */ + private function selectSiblingTemplateTypeMap( + NodeScopeResolver $nodeScopeResolver, + array $args, + array $parametersAcceptors, + ?array $namedArgumentsVariants, + array $gatheredArgTypeByIndex, + int $i, + MutatingScope $scope, + ): TemplateTypeMap + { + $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 $this->selectArgsMetadataAcceptor($nodeScopeResolver, $args, $siblingTypes, $parametersAcceptors, $namedArgumentsVariants, $siblingHasName, $siblingUnpack, $scope)->getResolvedTemplateTypeMap(); + } + + /** + * The names of the template types a callable parameter type passes to the + * callable without expecting them back: those its parameters reference and + * its return type does not. A template in the return type is left alone, as + * the closure's own return takes part in its inference. + * + * @return list + */ + private static function getReceivedTemplateNames(Type $parameterType, MutatingScope $scope): array + { + if (!$parameterType->hasTemplateOrLateResolvableType() || $parameterType->isCallable()->no()) { + return []; + } + + $callableType = $parameterType; + if ($callableType instanceof UnionType) { + $callableType = $callableType->filterTypes(static fn (Type $innerType): bool => $innerType->isCallable()->yes()); + } + if (!$callableType->isCallable()->yes()) { + return []; + } + + $returnedTemplateNames = []; + foreach ($callableType->getCallableParametersAcceptors($scope) as $acceptor) { + foreach ($acceptor->getReturnType()->getReferencedTemplateTypes(TemplateTypeVariance::createCovariant()) as $reference) { + $returnedTemplateNames[$reference->getType()->getName()] = true; + } } - return $this->closureParameterResolver->resolveCallableTypeForScope($closureExpr, $scope); + $receivedTemplateNames = []; + foreach ($callableType->getReferencedTemplateTypes(TemplateTypeVariance::createInvariant()) as $reference) { + $name = $reference->getType()->getName(); + if (isset($returnedTemplateNames[$name])) { + continue; + } + $receivedTemplateNames[$name] = true; + } + + return array_keys($receivedTemplateNames); + } + + /** + * The parameter with the received template types replaced by what the other + * arguments resolve them to - left alone when they say nothing about them, + * or pass no value of them (never, from an empty array). + * + * @param list $receivedTemplateNames + */ + private static function resolveReceivedTemplateTypes(ParameterReflection $parameter, array $receivedTemplateNames, TemplateTypeMap $siblingTemplateTypeMap): ParameterReflection + { + $receivedTypes = []; + foreach ($receivedTemplateNames as $name) { + $resolvedType = $siblingTemplateTypeMap->getType($name); + if ($resolvedType === null || $resolvedType instanceof ErrorType || $resolvedType instanceof NeverType) { + continue; + } + $receivedTypes[$name] = $resolvedType; + } + if ($receivedTypes === []) { + return $parameter; + } + + $type = TemplateTypeHelper::resolveTemplateTypes( + $parameter->getType(), + new TemplateTypeMap($receivedTypes), + TemplateTypeVarianceMap::createEmpty(), + TemplateTypeVariance::createInvariant(), + ); + + if (!$parameter instanceof ExtendedParameterReflection) { + return new DummyParameter( + $parameter->getName(), + $type, + $parameter->isOptional(), + $parameter->passedByReference(), + $parameter->isVariadic(), + $parameter->getDefaultValue(), + ); + } + + return new ExtendedDummyParameter( + $parameter->getName(), + $type, + $parameter->isOptional(), + $parameter->passedByReference(), + $parameter->isVariadic(), + $parameter->getDefaultValue(), + $parameter->getNativeType(), + $type, + $parameter->getOutType(), + $parameter->isImmediatelyInvokedCallable(), + $parameter->getClosureThisType(), + $parameter->getAttributes(), + $parameter->getAllowedConstants(), + $parameter->isPureUnlessCallableIsImpureParameter(), + $parameter->isPureUnlessParameterPassedParameter(), + ); + } + + 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 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-11861.php b/tests/PHPStan/Analyser/nsrt/bug-11861.php index a3e4addc62d..dd311255b26 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-11861.php +++ b/tests/PHPStan/Analyser/nsrt/bug-11861.php @@ -55,5 +55,5 @@ function filterArrayNotNull(array $source): array filterArrayNotNull(...) ); -assertType('array, array>', $mappedA); +assertType('array, array>', $mappedA); assertType('array, array>', $mappedAWithFirstClassSyntax); diff --git a/tests/PHPStan/Analyser/nsrt/bug-14885.php b/tests/PHPStan/Analyser/nsrt/bug-14885.php new file mode 100644 index 00000000000..6ae21e1748b --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-14885.php @@ -0,0 +1,190 @@ += 8.0 + +declare(strict_types = 1); + +namespace Bug14885; + +use Closure; +use function PHPStan\Testing\assertType; + +/** + * @template Tv + * @template T + * + * @param iterable $iterable + * @param (Closure(Tv): T) $function + * + * @return list + */ +function map(iterable $iterable, Closure $function): array +{ + $result = []; + foreach ($iterable as $value) { + $result[] = $function($value); + } + + return $result; +} + +function issue(): void +{ + assertType( + "list}>", + map(['a', 'b', 'c'], fn ($a) => [$a, ord($a)]), + ); + + assertType( + "list", + map([['a', 'b'], ['c', 'd']], fn ($x) => [$x[0], $x[1]]), + ); +} + +/** + * @template K of array-key + * @template T + * @template L of array-key + * @template U + * + * @param array $array + * @param callable(T, K): iterable $fn + * + * @return array + */ +function mapWithKeys(array $array, callable $fn): array +{ + return []; +} + +/** + * @template T + * @template U + * + * @param callable(T): U $fn + * @param array $array + * + * @return list + */ +function mapCallableFirst(callable $fn, array $array): array +{ + return []; +} + +/** + * @template T + * @template U + * + * @param array $array + * @param (callable(T): U)|null $fn + * + * @return list + */ +function mapNullable(array $array, ?callable $fn): array +{ + return []; +} + +/** + * @template T + * @template TAcc + * + * @param array $array + * @param callable(TAcc, T): TAcc $fn + * @param TAcc $initial + * + * @return TAcc + */ +function reduce(array $array, callable $fn, mixed $initial): mixed +{ + return $initial; +} + +final class Mapper +{ + + /** + * @template T + * @template U + * + * @param array $array + * @param callable(T): U $fn + * + * @return list + */ + public function map(array $array, callable $fn): array + { + return []; + } + + /** + * @template T + * @template U + * + * @param array $array + * @param callable(T): U $fn + * + * @return list + */ + public static function staticMap(array $array, callable $fn): array + { + return []; + } + +} + +/** + * @template T + * @template U + */ +final class Mapped +{ + + /** + * @param array $array + * @param callable(T): U $fn + */ + public function __construct(public array $array, public $fn) + { + } + + /** @return U */ + public function first(): mixed + { + throw new \LogicException(); + } + +} + +/** + * @param list $rows + * @param list> $nested + * @param list<\stdClass&object{name: string}> $objects + */ +function natively(array $rows, array $nested, array $objects, Mapper $mapper): void +{ + assertType('array<1, string>', mapWithKeys($rows, static fn (array $row): iterable => yield 1 => $row['name'])); + assertType('array', mapWithKeys($rows, static fn (array $row): iterable => yield $row['id'] => $row['name'])); + assertType('array', mapWithKeys($rows, static function (array $row): iterable { + $id = $row['id']; + yield $id => $row['name']; + })); + assertType('list', map($objects, static fn (object $o) => $o->name)); + + assertType('list', mapCallableFirst(static fn (array $row) => $row['name'], $rows)); + assertType('list', mapNullable($rows, static fn (array $row) => $row['name'])); + assertType('list', map(function: static fn (array $row) => $row['name'], iterable: $rows)); + assertType('list>', map($nested, static fn (array $list) => map($list, static fn (array $row) => $row['id']))); + assertType('int', reduce($rows, static fn (int $carry, array $row) => $carry + $row['id'], 0)); + + assertType('list', $mapper->map($rows, static fn (array $row) => $row['name'])); + assertType('list', Mapper::staticMap($rows, static fn (array $row) => $row['name'])); + assertType('string', (new Mapped($rows, static fn (array $row) => $row['name']))->first()); +} + +/** + * @template X of array{id: int} + * @param list $rows + */ +function callerTemplate(array $rows): void +{ + assertType('list', map($rows, static fn (array $row) => $row['id'])); +} 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/Analyser/nsrt/generics.php b/tests/PHPStan/Analyser/nsrt/generics.php index 6e150f33349..68f2908140c 100644 --- a/tests/PHPStan/Analyser/nsrt/generics.php +++ b/tests/PHPStan/Analyser/nsrt/generics.php @@ -156,7 +156,7 @@ function testF($arrayOfInt, $callableOrNull) assertType('Closure(mixed): string', function ($a): string { return (string)$a; }); - assertType('array', f($arrayOfInt, function ($a): string { + assertType('array', f($arrayOfInt, function ($a): string { return (string)$a; })); assertType('array', f($arrayOfInt, function ($a) { 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..bd59698bc9b 100644 --- a/turbo-ext/src/ArgumentsHandler.cpp +++ b/turbo-ext/src/ArgumentsHandler.cpp @@ -829,6 +829,322 @@ 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()); +} + +/* }}} */ + +/* {{{ the template types a closure only receives */ + +/* static fn (Type $innerType): bool => $innerType->isCallable()->yes() */ +void receivedTemplateNamesCallableFilterBody(zval *captures, uint32_t argc, zval *argv, zval *return_value) +{ + (void) captures; + if (UNEXPECTED(argc < 1 || Z_TYPE(argv[0]) != IS_OBJECT)) { + zend_type_error("ArgumentsHandler::getReceivedTemplateNames() filter: expected (Type $innerType)"); + return; + } + zend_long isCallable = pt_type_op_trinary(Z_OBJ(argv[0]), PT_OP_IS_CALLABLE, 0, NULL); + if (UNEXPECTED(isCallable < 0)) return; + ZVAL_BOOL(return_value, isCallable == PT_TRI_YES); +} + +/* the names of the template types $type->getReferencedTemplateTypes($variance) + * references, as keys of out (insertion order kept, value true); false = + * pending exception */ +[[nodiscard]] bool collectReferencedTemplateNames(zval *type, zend_long variance, zv::Arr &out) +{ + zval *positionVariance = pt_template_type_variance_singleton(variance); + if (UNEXPECTED(positionVariance == NULL)) return false; + zv::Val references = pt_type_op(Z_OBJ_P(type), PT_OP_GET_REFERENCED_TEMPLATE_TYPES, 1, positionVariance); + 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, referenceVariance; + if (UNEXPECTED(!pt_template_type_reference_parts(reference.raw(), referenceType, referenceVariance))) return false; + zv::Val name = templateTypeName(referenceType.raw()); + if (UNEXPECTED(name.isUndef())) return false; + out.set(Z_STR_P(name.raw()), zv::Val::boolean(true)); + } + return true; +} + +/* Mirrors ArgumentsHandler::getReceivedTemplateNames(): the names as the + * values of a list; UNDEF = pending exception */ +zv::Val getReceivedTemplateNames(zval *parameterType, zval *scope) +{ + zv::Val hasTemplate = pt_type_op(Z_OBJ_P(parameterType), PT_OP_HAS_TEMPLATE_OR_LATE_RESOLVABLE_TYPE, 0, NULL); + if (UNEXPECTED(hasTemplate.isUndef())) return zv::Val(); + if (!zend_is_true(hasTemplate.raw())) return zv::Val(zv::Arr::empty()); + zend_long isCallable = pt_type_op_trinary(Z_OBJ_P(parameterType), PT_OP_IS_CALLABLE, 0, NULL); + if (UNEXPECTED(isCallable < 0)) return zv::Val(); + if (isCallable == PT_TRI_NO) return zv::Val(zv::Arr::empty()); + + zval *callableType = parameterType; + zv::Val filtered; + if (instanceof_function(Z_OBJCE_P(callableType), pt_ce_union_type)) { + zv::Val filter = pt_native_closure(&receivedTemplateNamesCallableFilterBody); + if (UNEXPECTED(filter.isUndef())) return zv::Val(); + filtered = pt_type_call(Z_OBJ_P(callableType), PT_LC("filtertypes"), 1, filter.raw()); + if (UNEXPECTED(filtered.isUndef())) return zv::Val(); + if (UNEXPECTED(!filtered.ref().isObject())) { + zend_throw_error(NULL, "Call to a member function isCallable() on %s", zend_zval_value_name(filtered.raw())); + return zv::Val(); + } + callableType = filtered.raw(); + } + isCallable = pt_type_op_trinary(Z_OBJ_P(callableType), PT_OP_IS_CALLABLE, 0, NULL); + if (UNEXPECTED(isCallable < 0)) return zv::Val(); + if (isCallable != PT_TRI_YES) return zv::Val(zv::Arr::empty()); + + zv::Val acceptors = pt_type_call(Z_OBJ_P(callableType), PT_LC("getcallableparametersacceptors"), 1, scope); + if (UNEXPECTED(acceptors.isUndef())) return zv::Val(); + if (UNEXPECTED(!acceptors.ref().isArray())) { + zend_type_error("phpstan_turbo: getCallableParametersAcceptors() must return array"); + return zv::Val(); + } + zv::Arr returnedTemplateNames = zv::Arr::empty(); + for (zv::ArrayEntry entry : zv::ArrRef(acceptors.raw())) { + zval *acceptor = entry.value().deref().raw(); + if (UNEXPECTED(Z_TYPE_P(acceptor) != IS_OBJECT)) { + zend_throw_error(NULL, "Call to a member function getReturnType() on %s", zend_zval_value_name(acceptor)); + return zv::Val(); + } + zv::Val returnType = pt_parameters_acceptor_call(acceptor, PT_PA_GET_RETURN_TYPE); + if (UNEXPECTED(returnType.isUndef())) return zv::Val(); + if (UNEXPECTED(!returnType.ref().isObject())) { + zend_type_error("phpstan_turbo: getReturnType() must return an object"); + return zv::Val(); + } + if (UNEXPECTED(!collectReferencedTemplateNames(returnType.raw(), PT_TEMPLATE_TYPE_VARIANCE_COVARIANT, returnedTemplateNames))) return zv::Val(); + } + + zv::Arr referencedTemplateNames = zv::Arr::empty(); + if (UNEXPECTED(!collectReferencedTemplateNames(callableType, PT_TEMPLATE_TYPE_VARIANCE_INVARIANT, referencedTemplateNames))) return zv::Val(); + zv::Arr receivedTemplateNames = zv::Arr::empty(); + for (zv::ArrayEntry entry : zv::ArrRef(referencedTemplateNames.raw())) { + zend_string *name = entry.stringKeyOrNull(); + if (UNEXPECTED(name == NULL)) continue; + if (zend_symtable_find(Z_ARRVAL_P(returnedTemplateNames.raw()), name) != NULL) continue; + receivedTemplateNames.push(zv::Val::adoptString(zend_string_copy(name))); + } + return zv::Val(std::move(receivedTemplateNames)); +} + +/* Mirrors ArgumentsHandler::resolveReceivedTemplateTypes(); UNDEF = pending + * exception */ +zv::Val resolveReceivedTemplateTypes(zval *parameter, zval *receivedTemplateNames, zval *siblingTemplateTypeMap) +{ + zv::Arr receivedTypes = zv::Arr::empty(); + bool anyReceived = false; + for (zv::ArrayEntry entry : zv::ArrRef(receivedTemplateNames)) { + zval *name = entry.value().deref().raw(); + zv::Val resolvedType = pt_template_type_map_get_type(siblingTemplateTypeMap, Z_STR_P(name)); + if (UNEXPECTED(resolvedType.isUndef())) return zv::Val(); + if (resolvedType.isNull()) continue; + 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); + if (isError || isNever) continue; + receivedTypes.set(Z_STR_P(name), std::move(resolvedType)); + anyReceived = true; + } + if (!anyReceived) return zv::Val::copyOf(zv::Ref(parameter)); + + zval receivedMap; + if (UNEXPECTED(!pt_template_type_map_new(&receivedMap, receivedTypes.raw()))) return zv::Val(); + zv::Val receivedMapHold = zv::Val::adopt(receivedMap); + zval emptyVarianceMap; + if (UNEXPECTED(!pt_template_type_variance_map_empty(&emptyVarianceMap))) return zv::Val(); + zv::Val emptyVarianceMapHold = zv::Val::adopt(emptyVarianceMap); + zval *invariant = pt_template_type_variance_singleton(PT_TEMPLATE_TYPE_VARIANCE_INVARIANT); + if (UNEXPECTED(invariant == NULL)) return zv::Val(); + zv::Val parameterType = pt_parameter_reflection_call(parameter, PT_PR_GET_TYPE); + if (UNEXPECTED(parameterType.isUndef())) return zv::Val(); + zv::Val type = pt_type_template_type_helper_resolve_template_types(parameterType.raw(), receivedMapHold.raw(), emptyVarianceMapHold.raw(), invariant, false); + if (UNEXPECTED(type.isUndef())) return zv::Val(); + + bool isExtended = false; + if (UNEXPECTED(!isA(parameter, PT_CLASS_EXTENDED_PARAMETER_REFLECTION, isExtended))) return zv::Val(); + if (!isExtended) { + /* new DummyParameter($parameter->getName(), $type, ...) */ + zv::Val name = pt_parameter_reflection_call(parameter, PT_PR_GET_NAME); + if (UNEXPECTED(name.isUndef())) return zv::Val(); + if (UNEXPECTED(!name.ref().isString())) { + zend_type_error("phpstan_turbo: getName() must return string"); + return zv::Val(); + } + zv::Val optional = pt_parameter_reflection_call(parameter, PT_PR_IS_OPTIONAL); + if (UNEXPECTED(optional.isUndef())) return zv::Val(); + zv::Val passedByReference = pt_parameter_reflection_call(parameter, PT_PR_PASSED_BY_REFERENCE); + if (UNEXPECTED(passedByReference.isUndef())) return zv::Val(); + zv::Val variadic = pt_parameter_reflection_call(parameter, PT_PR_IS_VARIADIC); + if (UNEXPECTED(variadic.isUndef())) return zv::Val(); + zv::Val defaultValue = pt_parameter_reflection_call(parameter, PT_PR_GET_DEFAULT_VALUE); + if (UNEXPECTED(defaultValue.isUndef())) return zv::Val(); + return pt_dummy_parameter_new( + Z_STR_P(name.raw()), + type.raw(), + zend_is_true(optional.raw()), + passedByReference.isNull() ? NULL : passedByReference.raw(), + zend_is_true(variadic.raw()), + defaultValue.isNull() ? NULL : defaultValue.raw() + ); + } + + /* new ExtendedDummyParameter($parameter->getName(), $type, ...) - the + * getters in argument order, $type also standing for the PHPDoc type */ + static constexpr pt_parameter_reflection_member getters[13] = { + PT_PR_GET_NAME, PT_PR_IS_OPTIONAL, PT_PR_PASSED_BY_REFERENCE, PT_PR_IS_VARIADIC, PT_PR_GET_DEFAULT_VALUE, + PT_PR_GET_NATIVE_TYPE, PT_PR_GET_OUT_TYPE, PT_PR_IS_IMMEDIATELY_INVOKED_CALLABLE, PT_PR_GET_CLOSURE_THIS_TYPE, + PT_PR_GET_ATTRIBUTES, PT_PR_GET_ALLOWED_CONSTANTS, PT_PR_IS_PURE_UNLESS_CALLABLE_IS_IMPURE_PARAMETER, + PT_PR_IS_PURE_UNLESS_PARAMETER_PASSED_PARAMETER, + }; + zv::Val values[13]; + for (int k = 0; k < 13; k++) { + values[k] = pt_parameter_reflection_call(parameter, getters[k]); + if (UNEXPECTED(values[k].isUndef())) return zv::Val(); + } + zval args[15]; + ZVAL_COPY_VALUE(&args[0], values[0].raw()); + ZVAL_COPY_VALUE(&args[1], type.raw()); + ZVAL_COPY_VALUE(&args[2], values[1].raw()); + ZVAL_COPY_VALUE(&args[3], values[2].raw()); + ZVAL_COPY_VALUE(&args[4], values[3].raw()); + ZVAL_COPY_VALUE(&args[5], values[4].raw()); + ZVAL_COPY_VALUE(&args[6], values[5].raw()); + ZVAL_COPY_VALUE(&args[7], type.raw()); + for (int k = 6; k < 13; k++) { + ZVAL_COPY_VALUE(&args[k + 2], values[k].raw()); + } + return pt_extended_dummy_parameter_new(15, args); +} + +/* }}} */ + } // namespace namespace phpstanturbo { @@ -976,42 +1292,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 +2013,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 +2025,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 +2709,91 @@ 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); + } + + zv::Val siblingTemplateTypeMap; + zv::Val pushedParameterHold; + zval *pushedParameter = rawParameter; + zv::Val rawParameterType = pt_parameter_reflection_call(rawParameter, PT_PR_GET_TYPE); + if (UNEXPECTED(rawParameterType.isUndef())) return zv::Val(); + if (UNEXPECTED(!rawParameterType.ref().isObject())) { + zend_type_error("phpstan_turbo: getType() must return an object"); + return zv::Val(); + } + zv::Val receivedTemplateNames = getReceivedTemplateNames(rawParameterType.raw(), scope); + if (UNEXPECTED(receivedTemplateNames.isUndef())) return zv::Val(); + if (zend_hash_num_elements(Z_ARRVAL_P(receivedTemplateNames.raw())) > 0) { + siblingTemplateTypeMap = siblingTemplateTypeMapOf(w, i); + if (UNEXPECTED(siblingTemplateTypeMap.isUndef())) return zv::Val(); + pushedParameterHold = resolveReceivedTemplateTypes(rawParameter, receivedTemplateNames.raw(), siblingTemplateTypeMap.raw()); + if (UNEXPECTED(pushedParameterHold.isUndef())) return zv::Val(); + pushedParameter = pushedParameterHold.raw(); + } + + zval null; + ZVAL_NULL(&null); + zv::Val pushedScope = pt_mutating_scope_push_in_function_call(Z_OBJ_P(scope), &null, pushedParameter, 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; + + if (siblingTemplateTypeMap.isUndef()) { + siblingTemplateTypeMap = siblingTemplateTypeMapOf(w, i); + if (UNEXPECTED(siblingTemplateTypeMap.isUndef())) return zv::Val(); + } + + return resolveCalleeTemplateTypes(closureType.raw(), calleeTemplateTypeMap.raw(), siblingTemplateTypeMap.raw()); + } + + /* Mirrors selectSiblingTemplateTypeMap() */ + zv::Val siblingTemplateTypeMapOf(Walk &w, zend_ulong i) const + { + zv::Val siblingAcceptor = paddedMetadataAcceptor(w, false, &i); + if (UNEXPECTED(siblingAcceptor.isUndef())) return zv::Val(); + return pt_parameters_acceptor_call(siblingAcceptor.raw(), PT_PA_GET_RESOLVED_TEMPLATE_TYPE_MAP); + } + /* 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 +2802,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..192974a736c 100644 --- a/turbo-ext/src/generated/ArgumentsHandler.h +++ b/turbo-ext/src/generated/ArgumentsHandler.h @@ -116,41 +116,54 @@ 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 */ + "PHPStan\\Type\\Generic\\TemplateTypeMap\0" /* 1502 */ + "selectSiblingTemplateTypeMap\0" /* 1539 */ + "parameterType\0" /* 1568 */ + "getReceivedTemplateNames\0" /* 1582 */ + "parameter\0" /* 1607 */ + "PHPStan\\Reflection\\ParameterReflection\0" /* 1617 */ + "receivedTemplateNames\0" /* 1656 */ + "siblingTemplateTypeMap\0" /* 1678 */ + "resolveReceivedTemplateTypes\0" /* 1701 */ + "calleeTemplateTypeMap\0" /* 1730 */ + "referencesCalleeTemplateTypes\0" /* 1752 */ + "resolvedTemplateTypeMap\0" /* 1782 */ + "resolveCalleeTemplateTypes\0" /* 1806 */ + "PHPStan\\Type\\Generic\\TemplateType\0" /* 1833 */ + "isCalleeTemplateType\0" /* 1867 */ + "PHPStan\\Reflection\\ParametersAcceptor\0" /* 1888 */ + "selectCountStableMetadataAcceptor\0" /* 1926 */ + "acceptor\0" /* 1960 */ + "arg\0" /* 1969 */ + "matchArgParameter\0" /* 1973 */ + "selectArgsAcceptor\0" /* 1991 */ + "gatheredTypes\0" /* 2010 */ + "selectArgsMetadataAcceptor\0" /* 2024 */ + "originalCall\0" /* 2051 */ + "normalizedCall\0" /* 2064 */ + "processDroppedArgs\0" /* 2079 */ + "callCallbackImmediately\0" /* 2098 */ + "shouldInvalidateCallbackExpressions\0" /* 2122 */ + "getParameterTypeFromParameterClosureTypeExtension\0" /* 2158 */ + "currentParameter\0" /* 2208 */ + "getParameterOutExtensionsType\0" /* 2225 */ + "call\0" /* 2255 */ + "resolveClosureThisType\0" /* 2260 */ + "position\0" /* 2283 */ + "unpackedType\0" /* 2292 */ + "isPure\0" /* 2305 */ + "observeUnpackedArgument\0" /* 2312 */ + "valueType\0" /* 2336 */ + "observeArgumentValue\0" /* 2346 */ + "findOriginalParameterType\0" /* 2367 */ + "argResults\0" /* 2393 */ + "argValue\0" /* 2404 */ + "PHPStan\\Analyser\\ExpressionResult\0" /* 2413 */ + "readArgResult"; /* 2447 */ inline constexpr reg::PackedArg args[] = { reg::packed(0, 0, 25), /* __construct $templateArgumentObserver */ reg::packed(76, 0, 100), /* __construct $expressionResultFactory */ @@ -190,83 +203,112 @@ 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(832, 0, 850), /* selectSiblingTemplateTypeMap $nodeScopeResolver */ + reg::packed(1441, MAY_BE_ARRAY), /* selectSiblingTemplateTypeMap $args */ + reg::packed(993, MAY_BE_ARRAY), /* selectSiblingTemplateTypeMap $parametersAcceptors */ + reg::packed(1013, MAY_BE_NULL | MAY_BE_ARRAY), /* selectSiblingTemplateTypeMap $namedArgumentsVariants */ + reg::packed(1446, MAY_BE_ARRAY), /* selectSiblingTemplateTypeMap $gatheredArgTypeByIndex */ + reg::packed(1338, MAY_BE_LONG), /* selectSiblingTemplateTypeMap $i */ + reg::packed(1074, 0, 1080), /* selectSiblingTemplateTypeMap $scope */ + reg::packed(1245, 0, 1502), /* selectSiblingTemplateTypeMap return */ + reg::packed(1568, 0, 1345), /* getReceivedTemplateNames $parameterType */ + reg::packed(1074, 0, 1080), /* getReceivedTemplateNames $scope */ + reg::packed(1245, MAY_BE_ARRAY), /* getReceivedTemplateNames return */ + reg::packed(1607, 0, 1617), /* resolveReceivedTemplateTypes $parameter */ + reg::packed(1656, MAY_BE_ARRAY), /* resolveReceivedTemplateTypes $receivedTemplateNames */ + reg::packed(1678, 0, 1502), /* resolveReceivedTemplateTypes $siblingTemplateTypeMap */ + reg::packed(1245, 0, 1617), /* resolveReceivedTemplateTypes return */ + reg::packed(1340, 0, 1345), /* referencesCalleeTemplateTypes $type */ + reg::packed(1730, 0, 1502), /* referencesCalleeTemplateTypes $calleeTemplateTypeMap */ + reg::packed(1245, MAY_BE_BOOL), /* referencesCalleeTemplateTypes return */ + reg::packed(1340, 0, 1345), /* resolveCalleeTemplateTypes $type */ + reg::packed(1730, 0, 1502), /* resolveCalleeTemplateTypes $calleeTemplateTypeMap */ + reg::packed(1782, 0, 1502), /* resolveCalleeTemplateTypes $resolvedTemplateTypeMap */ + reg::packed(1245, 0, 1345), /* resolveCalleeTemplateTypes return */ + reg::packed(1340, 0, 1833), /* isCalleeTemplateType $type */ + reg::packed(1730, 0, 1502), /* 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, 1888), /* selectCountStableMetadataAcceptor return */ + reg::packed(1960, 0, 1888), /* matchArgParameter $acceptor */ + reg::packed(1969, 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, 1617), /* 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, 1888), /* 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(2010, 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, 1888), /* 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(2051, 0, 1045), /* processDroppedArgs $originalCall */ + reg::packed(2064, 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(1607, MAY_BE_NULL, 1617), /* callCallbackImmediately $parameter */ + reg::packed(1568, 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(1607, MAY_BE_NULL, 1617), /* 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(1607, 0, 1617), /* 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(2208, 0, 1617), /* 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(2255, MAY_BE_NULL, 1045), /* resolveClosureThisType $call */ reg::packed(910, 0), /* resolveClosureThisType $calleeReflection */ - reg::packed(1728, 0, 1564), /* resolveClosureThisType $parameter */ + reg::packed(1607, 0, 1617), /* 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(1960, 0, 1888), /* observeUnpackedArgument $acceptor */ + reg::packed(2283, MAY_BE_LONG), /* observeUnpackedArgument $position */ + reg::packed(2292, 0, 1345), /* observeUnpackedArgument $unpackedType */ + reg::packed(2305, 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(1960, 0, 1888), /* observeArgumentValue $acceptor */ + reg::packed(1607, 0, 1617), /* observeArgumentValue $parameter */ + reg::packed(2336, 0, 1345), /* observeArgumentValue $valueType */ + reg::packed(2305, 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(1960, 0, 1888), /* findOriginalParameterType $acceptor */ + reg::packed(1607, 0, 1617), /* 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(2393, MAY_BE_ARRAY), /* readArgResult $argResults */ + reg::packed(2404, 0, 1388), /* readArgResult $argValue */ + reg::packed(1245, 0, 2413), /* readArgResult return */ }; using Sig = reg::Sig; } // namespace sigtab @@ -277,21 +319,27 @@ 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 selectSiblingTemplateTypeMap = { { 1539 /* selectSiblingTemplateTypeMap */, 7, 47, 7, 54, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig getReceivedTemplateNames = { { 1582 /* getReceivedTemplateNames */, 2, 55, 2, 57, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig resolveReceivedTemplateTypes = { { 1701 /* resolveReceivedTemplateTypes */, 3, 58, 3, 61, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig referencesCalleeTemplateTypes = { { 1752 /* referencesCalleeTemplateTypes */, 2, 62, 2, 64, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig resolveCalleeTemplateTypes = { { 1806 /* resolveCalleeTemplateTypes */, 3, 65, 3, 68, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig isCalleeTemplateType = { { 1867 /* isCalleeTemplateType */, 2, 69, 2, 71, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig selectCountStableMetadataAcceptor = { { 1926 /* selectCountStableMetadataAcceptor */, 5, 72, 5, 77, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig matchArgParameter = { { 1973 /* matchArgParameter */, 3, 78, 3, 81, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig selectArgsAcceptor = { { 1991 /* selectArgsAcceptor */, 5, 82, 5, 87, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig selectArgsMetadataAcceptor = { { 2024 /* selectArgsMetadataAcceptor */, 8, 88, 8, 96, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processDroppedArgs = { { 2079 /* processDroppedArgs */, 7, 97, 7, 104, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig callCallbackImmediately = { { 2098 /* callCallbackImmediately */, 3, 105, 3, 108, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig shouldInvalidateCallbackExpressions = { { 2122 /* shouldInvalidateCallbackExpressions */, 1, 109, 1, 110, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig getParameterTypeFromParameterClosureTypeExtension = { { 2158 /* getParameterTypeFromParameterClosureTypeExtension */, 4, 111, 4, 115, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig getParameterOutExtensionsType = { { 2225 /* getParameterOutExtensionsType */, 4, 116, 4, 120, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig resolveClosureThisType = { { 2260 /* resolveClosureThisType */, 4, 121, 4, 125, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig observeUnpackedArgument = { { 2312 /* observeUnpackedArgument */, 5, 126, 5, 131, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig observeArgumentValue = { { 2346 /* observeArgumentValue */, 5, 132, 5, 137, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig findOriginalParameterType = { { 2367 /* findOriginalParameterType */, 2, 138, 2, 140, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig readArgResult = { { 2447 /* readArgResult */, 2, 141, 2, 143, ZEND_ACC_PRIVATE } }; } // namespace sig } // namespace ptdecl::ArgumentsHandler