From b23037acbadf35710cec4d1e30cb9f312261afa0 Mon Sep 17 00:00:00 2001 From: phpstan-bot <79867460+phpstan-bot@users.noreply.github.com> Date: Sat, 24 Oct 2026 15:49:54 +0000 Subject: [PATCH] Collect template argument constraints through object shape properties in `TemplateArgumentObserver` - TemplateArgumentObserver::observeSend() now matches a declared `object{...}` shape property by property against the actual object's public non-static properties (new observeObjectShapeSend()). Before, a declared shape names no class, so `(object) ['x' => new Collection([...])]` returned or passed as `object{x: Collection}` never constrained the inner `new` site, and its invariant TKey stayed at the exact `0|1|...` literal. - A declared intersection `object{...}&Foo` sends to each shape member too. - Ported the same logic to the native mirror in turbo-ext/src/TemplateArgumentObserver.cpp and regenerated its declarations header. - Covers every place that sends to a declared type: return, typed property assignment, call argument and `yield` (Generator value type), plus nested shapes, nullable unions and optional shape properties. - Probed and left alone: closures returned as `Closure(): object{...}` do not constrain their body's `new` sites even with plain generic or array shape return types. That limitation is separate from object shapes. --- phpstan-baseline.neon | 12 ++++ .../Generics/TemplateArgumentObserver.php | 47 ++++++++++++++ .../Rules/Generators/YieldTypeRuleTest.php | 5 ++ .../Rules/Generators/data/bug-15417.php | 24 +++++++ .../Methods/CallStaticMethodsRuleTest.php | 6 ++ .../Rules/Methods/ReturnTypeRuleTest.php | 17 +++++ .../Rules/Methods/data/bug-15417-argument.php | 28 +++++++++ .../Rules/Methods/data/bug-15417-shapes.php | 54 ++++++++++++++++ .../PHPStan/Rules/Methods/data/bug-15417.php | 33 ++++++++++ .../TypesAssignedToPropertiesRuleTest.php | 5 ++ .../Rules/Properties/data/bug-15417.php | 26 ++++++++ turbo-ext/src/TemplateArgumentObserver.cpp | 61 ++++++++++++++++++ .../src/generated/TemplateArgumentObserver.h | 62 +++++++++++-------- 13 files changed, 353 insertions(+), 27 deletions(-) create mode 100644 tests/PHPStan/Rules/Generators/data/bug-15417.php create mode 100644 tests/PHPStan/Rules/Methods/data/bug-15417-argument.php create mode 100644 tests/PHPStan/Rules/Methods/data/bug-15417-shapes.php create mode 100644 tests/PHPStan/Rules/Methods/data/bug-15417.php create mode 100644 tests/PHPStan/Rules/Properties/data/bug-15417.php diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 301f9f86803..f231f9ce48b 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -54,6 +54,18 @@ parameters: count: 1 path: src/Analyser/ExprHandler/Helper/IncDecTypeHelper.php + - + rawMessage: Doing instanceof PHPStan\Type\IntersectionType is error-prone and deprecated. + identifier: phpstanApi.instanceofType + count: 1 + path: src/Analyser/Generics/TemplateArgumentObserver.php + + - + rawMessage: 'Doing instanceof PHPStan\Type\ObjectShapeType is error-prone and deprecated. Use Type::isObject() and Type::hasProperty() instead.' + identifier: phpstanApi.instanceofType + count: 2 + path: src/Analyser/Generics/TemplateArgumentObserver.php + - rawMessage: Casting to string something that's already string. identifier: cast.useless diff --git a/src/Analyser/Generics/TemplateArgumentObserver.php b/src/Analyser/Generics/TemplateArgumentObserver.php index 43d9cfa68e4..0e105cd2475 100644 --- a/src/Analyser/Generics/TemplateArgumentObserver.php +++ b/src/Analyser/Generics/TemplateArgumentObserver.php @@ -5,6 +5,7 @@ use PhpParser\Node\Expr; use PHPStan\Analyser\OutOfClassScope; use PHPStan\DependencyInjection\AutowiredService; +use PHPStan\Reflection\MissingPropertyFromReflectionException; use PHPStan\Reflection\ParametersAcceptor; use PHPStan\Reflection\ResolvedFunctionVariant; use PHPStan\Turbo\ShadowedByTurboExtension; @@ -14,8 +15,10 @@ use PHPStan\Type\Generic\TemplateTypeMap; use PHPStan\Type\Generic\TemplateTypeVariance; use PHPStan\Type\Generic\UnresolvedTemplateArgumentType; +use PHPStan\Type\IntersectionType; use PHPStan\Type\MixedType; use PHPStan\Type\NeverType; +use PHPStan\Type\ObjectShapeType; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; use PHPStan\Type\TypeTraverser; @@ -451,6 +454,18 @@ private function observeSend(TemplateArgumentConstraints $constraints, Type $dec // never holds no markers, and is its own iterable key and value type return $constraints; } + if ($declared instanceof ObjectShapeType) { + return $this->observeObjectShapeSend($constraints, $declared, $actual, $isCallArgument); + } + if ($declared instanceof IntersectionType) { + // object{...}&Foo - the shape's properties are bounds next to Foo's arguments + foreach ($declared->getTypes() as $member) { + if (!$member instanceof ObjectShapeType) { + continue; + } + $constraints = $this->observeObjectShapeSend($constraints, $member, $actual, $isCallArgument); + } + } $actualReflections = $actual->getObjectClassReflections(); if (count($actualReflections) === 1) { @@ -506,6 +521,38 @@ private function observeSend(TemplateArgumentConstraints $constraints, Type $dec return $constraints; } + /** + * Each property of the object flows into the declared property of the shape + * (`(object) ['x' => new Foo(1)]` returned as `object{x: Foo}`). + */ + private function observeObjectShapeSend(TemplateArgumentConstraints $constraints, ObjectShapeType $declared, Type $actual, bool $isCallArgument): TemplateArgumentConstraints + { + if (!$actual->isObject()->yes()) { + return $constraints; + } + + $scope = new OutOfClassScope(); + foreach ($declared->getProperties() as $name => $declaredPropertyType) { + $name = (string) $name; + if (!$actual->hasInstanceProperty($name)->yes()) { + continue; + } + + try { + $actualProperty = $actual->getInstanceProperty($name, $scope); + } catch (MissingPropertyFromReflectionException) { + continue; + } + if (!$actualProperty->isPublic() || $actualProperty->isStatic()) { + continue; + } + + $constraints = $this->observeSend($constraints, $declaredPropertyType, $actualProperty->getReadableType(), $isCallArgument); + } + + return $constraints; + } + /** * A template argument of an object sent to the declared argument at the same * position. A union of several sites' markers (Box of zip(of(1), of(2))) diff --git a/tests/PHPStan/Rules/Generators/YieldTypeRuleTest.php b/tests/PHPStan/Rules/Generators/YieldTypeRuleTest.php index 555ae5f5baf..568aa0205bd 100644 --- a/tests/PHPStan/Rules/Generators/YieldTypeRuleTest.php +++ b/tests/PHPStan/Rules/Generators/YieldTypeRuleTest.php @@ -87,4 +87,9 @@ public function testYieldOversizedSelfRejection(): void $this->analyse([__DIR__ . '/data/bug-yield-oversized-self-rejection.php'], []); } + public function testBug15417(): void + { + $this->analyse([__DIR__ . '/data/bug-15417.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Generators/data/bug-15417.php b/tests/PHPStan/Rules/Generators/data/bug-15417.php new file mode 100644 index 00000000000..1062220407c --- /dev/null +++ b/tests/PHPStan/Rules/Generators/data/bug-15417.php @@ -0,0 +1,24 @@ + $a */ + public function __construct($a) { } +} + +final class Repro +{ + + /** @return \Generator}> */ + public static function gen(): \Generator + { + yield (object) ['x' => new Collection(['a', 'b'])]; + } + +} diff --git a/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php b/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php index 33f7859302b..7cb748d0688 100644 --- a/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php @@ -1156,4 +1156,10 @@ public function testBug11421(): void ]); } + public function testBug15417(): void + { + $this->checkThisOnly = false; + $this->analyse([__DIR__ . '/data/bug-15417-argument.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php b/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php index 260fde1475f..d2372556d07 100644 --- a/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php +++ b/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php @@ -1419,4 +1419,21 @@ public function testBug13325(): void $this->analyse([__DIR__ . '/data/bug-13325.php'], []); } + #[RequiresPhp('>= 8.2.0')] + public function testBug15417(): void + { + $this->analyse([__DIR__ . '/data/bug-15417.php'], []); + } + + public function testBug15417Shapes(): void + { + $this->analyse([__DIR__ . '/data/bug-15417-shapes.php'], [ + [ + 'Method Bug15417Shapes\\Repro::stillReported() should return object{x: Bug15417Shapes\\Collection} but returns object{x: Bug15417Shapes\\Collection<0|1, \'a\'|\'b\'>}&stdClass.', + 51, + 'Property ($x) type Bug15417Shapes\\Collection does not accept type Bug15417Shapes\\Collection<0|1, \'a\'|\'b\'>.', + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Methods/data/bug-15417-argument.php b/tests/PHPStan/Rules/Methods/data/bug-15417-argument.php new file mode 100644 index 00000000000..966b3c73b71 --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/bug-15417-argument.php @@ -0,0 +1,28 @@ + $a */ + public function __construct($a) { } +} + +final class Repro +{ + + /** @param object{x: Collection} $o */ + public static function take(object $o): void + { + } + + public static function doFoo(): void + { + self::take((object) ['x' => new Collection(['a', 'b'])]); + } + +} diff --git a/tests/PHPStan/Rules/Methods/data/bug-15417-shapes.php b/tests/PHPStan/Rules/Methods/data/bug-15417-shapes.php new file mode 100644 index 00000000000..7d920bbd4d6 --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/bug-15417-shapes.php @@ -0,0 +1,54 @@ + $a */ + public function __construct($a) { } +} + +final class Repro +{ + + /** @return object{x: Collection} */ + public static function shape(): object + { + return (object) ['x' => new Collection(['a', 'b'])]; + } + + /** @return object{y: object{x: Collection}} */ + public static function nested(): object + { + return (object) ['y' => (object) ['x' => new Collection(['a', 'b'])]]; + } + + /** @return object{x: Collection}|null */ + public static function nullable(bool $b): ?object + { + return $b ? (object) ['x' => new Collection(['a', 'b'])] : null; + } + + /** @return object{x: Collection}&\stdClass */ + public static function intersection(): object + { + return (object) ['x' => new Collection(['a', 'b'])]; + } + + /** @return list, y?: Collection}> */ + public static function optional(): array + { + return [(object) ['x' => new Collection(['a', 'b'])]]; + } + + /** @return object{x: Collection} */ + public static function stillReported(): object + { + return (object) ['x' => new Collection(['a', 'b'])]; + } + +} diff --git a/tests/PHPStan/Rules/Methods/data/bug-15417.php b/tests/PHPStan/Rules/Methods/data/bug-15417.php new file mode 100644 index 00000000000..36e86d3e565 --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/bug-15417.php @@ -0,0 +1,33 @@ += 8.2 + +declare(strict_types = 1); + +namespace Bug15417; + +class Repro +{ + /** @return Collection}> */ + public static function get(string $s): Collection + { + $data = []; + foreach (explode(',', $s) as $char) { + $c = array_map(fn($x) => (object)['t' => $x], ['a', 'b', 'c', 'd']); + if ($s !== 'z') { + $data[] = (object)['ch' => $char, 'x' => new Collection((new \Random\Randomizer)->shuffleArray($c))]; + } + } + + return new Collection($data); + } +} + +/** + * @template TKey of array-key + * @template-covariant TValue (THEA fix by FixLarastanStubs.php) + */ +class Collection +{ + /** @param iterable $a */ + public function __construct($a) { echo gettype($a); } +} + diff --git a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php index 885902a72b7..ddc715cd365 100644 --- a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php @@ -1145,4 +1145,9 @@ public function testIntersectionWithTemplateMixed(): void ]); } + public function testBug15417(): void + { + $this->analyse([__DIR__ . '/data/bug-15417.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Properties/data/bug-15417.php b/tests/PHPStan/Rules/Properties/data/bug-15417.php new file mode 100644 index 00000000000..e579fea91be --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/bug-15417.php @@ -0,0 +1,26 @@ + $a */ + public function __construct($a) { } +} + +final class Repro +{ + + /** @var object{x: Collection} */ + public object $p; + + public function doFoo(): void + { + $this->p = (object) ['x' => new Collection(['a', 'b'])]; + } + +} diff --git a/turbo-ext/src/TemplateArgumentObserver.cpp b/turbo-ext/src/TemplateArgumentObserver.cpp index 265a244c6f9..4841471602b 100644 --- a/turbo-ext/src/TemplateArgumentObserver.cpp +++ b/turbo-ext/src/TemplateArgumentObserver.cpp @@ -750,6 +750,19 @@ class TemplateArgumentObserver } if (isMarker(actual)) return constraints; if (isInstance(actual, pt_ce_never_type)) return constraints; + if (isInstance(declared, pt_ce_object_shape_type)) { + return observeObjectShapeSend(std::move(constraints), declared, actual, isCallArgument); + } + if (isInstance(declared, pt_ce_intersection_type)) { + zv::Val types = pt_type_op(Z_OBJ_P(declared), PT_OP_GET_TYPES, 0, NULL); + if (UNEXPECTED(types.isUndef())) return zv::Val(); + for (auto entry : zv::ArrRef(types.raw())) { + zval *member = entry.value().deref().raw(); + if (!isInstance(member, pt_ce_object_shape_type)) continue; + constraints = observeObjectShapeSend(std::move(constraints), member, actual, isCallArgument); + if (UNEXPECTED(constraints.isUndef())) return zv::Val(); + } + } zv::Val actualReflections = objectClassReflections(actual); if (UNEXPECTED(actualReflections.isUndef())) return zv::Val(); @@ -842,6 +855,54 @@ class TemplateArgumentObserver return observeSend(std::move(constraints), declaredValue.raw(), actualValue.raw(), isCallArgument); } + /* Mirrors observeObjectShapeSend(). */ + static zv::Val observeObjectShapeSend(zv::Val constraints, zval *declared, zval *actual, bool isCallArgument) + { + bool yes; + if (UNEXPECTED(!trinaryYes(actual, PT_LC("isobject"), yes))) return zv::Val(); + if (!yes) return constraints; + + zv::Val scope = pt_type_new(PT_CLASS_OUT_OF_CLASS_SCOPE, 0, NULL); + if (UNEXPECTED(scope.isUndef())) return zv::Val(); + zv::Val properties = call0(declared, PT_LC("getproperties"), "getProperties"); + if (UNEXPECTED(properties.isUndef())) return zv::Val(); + if (UNEXPECTED(Z_TYPE_P(properties.raw()) != IS_ARRAY)) { + zend_type_error("phpstan_turbo: getProperties() must return array"); + return zv::Val(); + } + for (auto entry : zv::ArrRef(properties.raw())) { + /* (string) $name */ + zv::Val name = entry.hasStringKey() + ? zv::Val::string(entry.stringKey()) + : zv::Val::adoptString(zend_long_to_str((zend_long) entry.indexKey())); + zend_long hasProperty = pt_type_call_trinary(Z_OBJ_P(actual), PT_LC("hasinstanceproperty"), 1, name.raw()); + if (UNEXPECTED(hasProperty < 0)) return zv::Val(); + if (hasProperty != PT_TRI_YES) continue; + + zv::Args args{name.raw(), scope.raw()}; + zv::Val actualProperty = pt_type_call(Z_OBJ_P(actual), PT_LC("getinstanceproperty"), 2, args); + if (UNEXPECTED(actualProperty.isUndef())) { + zend_class_entry *missingCe = pt_class(PT_CLASS_MISSING_PROPERTY_FROM_REFLECTION_EXCEPTION); + if (EG(exception) == NULL || missingCe == NULL || !instanceof_function(EG(exception)->ce, missingCe)) return zv::Val(); + zend_clear_exception(); + continue; + } + zv::Val flag = call0(actualProperty.raw(), PT_LC("ispublic"), "isPublic"); + if (UNEXPECTED(flag.isUndef())) return zv::Val(); + if (!zend_is_true(flag.raw())) continue; + flag = call0(actualProperty.raw(), PT_LC("isstatic"), "isStatic"); + if (UNEXPECTED(flag.isUndef())) return zv::Val(); + if (zend_is_true(flag.raw())) continue; + + zv::Val actualPropertyType = call0(actualProperty.raw(), PT_LC("getreadabletype"), "getReadableType"); + if (UNEXPECTED(actualPropertyType.isUndef())) return zv::Val(); + constraints = observeSend(std::move(constraints), entry.value().deref().raw(), actualPropertyType.raw(), isCallArgument); + if (UNEXPECTED(constraints.isUndef())) return zv::Val(); + } + + return constraints; + } + /* Mirrors observeArgumentSend(). */ static zv::Val observeArgumentSend(zv::Val constraints, zval *declaredArgument, zval *argument, zval *variance, bool isCallArgument) { diff --git a/turbo-ext/src/generated/TemplateArgumentObserver.h b/turbo-ext/src/generated/TemplateArgumentObserver.h index 8fd71ca386a..aea2efe5a32 100644 --- a/turbo-ext/src/generated/TemplateArgumentObserver.h +++ b/turbo-ext/src/generated/TemplateArgumentObserver.h @@ -63,19 +63,21 @@ inline constexpr char strings[] = "replaceInferableTemplates\0" /* 634 */ "isCallArgument\0" /* 660 */ "observeSend\0" /* 675 */ - "declaredArgument\0" /* 687 */ - "argument\0" /* 704 */ - "variance\0" /* 713 */ - "PHPStan\\Type\\Generic\\TemplateTypeVariance\0" /* 722 */ - "observeArgumentSend\0" /* 764 */ - "marker\0" /* 784 */ - "PHPStan\\Type\\Generic\\UnresolvedTemplateArgumentType\0" /* 791 */ - "observeMarkerSend\0" /* 843 */ - "isInertSendTarget\0" /* 861 */ - "observeArgument\0" /* 879 */ - "observeLowerBound\0" /* 895 */ - "isUninformativeSendTarget\0" /* 913 */ - "hasOnlyInferableTemplates"; /* 939 */ + "PHPStan\\Type\\ObjectShapeType\0" /* 687 */ + "observeObjectShapeSend\0" /* 716 */ + "declaredArgument\0" /* 739 */ + "argument\0" /* 756 */ + "variance\0" /* 765 */ + "PHPStan\\Type\\Generic\\TemplateTypeVariance\0" /* 774 */ + "observeArgumentSend\0" /* 816 */ + "marker\0" /* 836 */ + "PHPStan\\Type\\Generic\\UnresolvedTemplateArgumentType\0" /* 843 */ + "observeMarkerSend\0" /* 895 */ + "isInertSendTarget\0" /* 913 */ + "observeArgument\0" /* 931 */ + "observeLowerBound\0" /* 947 */ + "isUninformativeSendTarget\0" /* 965 */ + "hasOnlyInferableTemplates"; /* 991 */ inline constexpr reg::PackedArg args[] = { reg::packed(0, 0, 5), /* collectSites $type */ reg::packed(23, 0, 24), /* collectSites return */ @@ -131,16 +133,21 @@ inline constexpr reg::PackedArg args[] = { reg::packed(143, 0, 5), /* observeSend $actual */ reg::packed(660, MAY_BE_BOOL, reg::NoString, false, false, 113), /* observeSend $isCallArgument */ reg::packed(23, 0, 24), /* observeSend return */ + reg::packed(386, 0, 24), /* observeObjectShapeSend $constraints */ + reg::packed(134, 0, 687), /* observeObjectShapeSend $declared */ + reg::packed(143, 0, 5), /* observeObjectShapeSend $actual */ + reg::packed(660, MAY_BE_BOOL), /* observeObjectShapeSend $isCallArgument */ + reg::packed(23, 0, 24), /* observeObjectShapeSend return */ reg::packed(386, 0, 24), /* observeArgumentSend $constraints */ - reg::packed(687, 0, 5), /* observeArgumentSend $declaredArgument */ - reg::packed(704, 0, 5), /* observeArgumentSend $argument */ - reg::packed(713, 0, 722), /* observeArgumentSend $variance */ + reg::packed(739, 0, 5), /* observeArgumentSend $declaredArgument */ + reg::packed(756, 0, 5), /* observeArgumentSend $argument */ + reg::packed(765, 0, 774), /* observeArgumentSend $variance */ reg::packed(660, MAY_BE_BOOL), /* observeArgumentSend $isCallArgument */ reg::packed(23, 0, 24), /* observeArgumentSend return */ reg::packed(386, 0, 24), /* observeMarkerSend $constraints */ - reg::packed(687, 0, 5), /* observeMarkerSend $declaredArgument */ - reg::packed(784, 0, 791), /* observeMarkerSend $marker */ - reg::packed(713, 0, 722), /* observeMarkerSend $variance */ + reg::packed(739, 0, 5), /* observeMarkerSend $declaredArgument */ + reg::packed(836, 0, 843), /* observeMarkerSend $marker */ + reg::packed(765, 0, 774), /* observeMarkerSend $variance */ reg::packed(660, MAY_BE_BOOL), /* observeMarkerSend $isCallArgument */ reg::packed(23, 0, 24), /* observeMarkerSend return */ reg::packed(134, 0, 5), /* isInertSendTarget $declared */ @@ -154,7 +161,7 @@ inline constexpr reg::PackedArg args[] = { reg::packed(162, 0, 5), /* observeLowerBound $parameterType */ reg::packed(176, 0, 5), /* observeLowerBound $argumentType */ reg::packed(23, 0, 24), /* observeLowerBound return */ - reg::packed(687, 0, 5), /* isUninformativeSendTarget $declaredArgument */ + reg::packed(739, 0, 5), /* isUninformativeSendTarget $declaredArgument */ reg::packed(23, MAY_BE_BOOL), /* isUninformativeSendTarget return */ reg::packed(0, 0, 5), /* hasOnlyInferableTemplates $type */ reg::packed(23, MAY_BE_BOOL), /* hasOnlyInferableTemplates return */ @@ -180,13 +187,14 @@ inline constexpr sigtab::Sig collectArgument = { { 514 /* collectArgument */, 2, inline constexpr sigtab::Sig collectCall = { { 612 /* collectCall */, 3, 39, 4, 43, ZEND_ACC_PUBLIC } }; inline constexpr sigtab::Sig replaceInferableTemplates = { { 634 /* replaceInferableTemplates */, 4, 44, 4, 48, ZEND_ACC_PRIVATE } }; inline constexpr sigtab::Sig observeSend = { { 675 /* observeSend */, 3, 49, 4, 53, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig observeArgumentSend = { { 764 /* observeArgumentSend */, 5, 54, 5, 59, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig observeMarkerSend = { { 843 /* observeMarkerSend */, 5, 60, 5, 65, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig isInertSendTarget = { { 861 /* isInertSendTarget */, 2, 66, 2, 68, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; -inline constexpr sigtab::Sig observeArgument = { { 879 /* observeArgument */, 3, 69, 3, 72, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig observeLowerBound = { { 895 /* observeLowerBound */, 3, 73, 3, 76, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig isUninformativeSendTarget = { { 913 /* isUninformativeSendTarget */, 1, 77, 1, 78, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; -inline constexpr sigtab::Sig hasOnlyInferableTemplates = { { 939 /* hasOnlyInferableTemplates */, 1, 79, 1, 80, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig observeObjectShapeSend = { { 716 /* observeObjectShapeSend */, 4, 54, 4, 58, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig observeArgumentSend = { { 816 /* observeArgumentSend */, 5, 59, 5, 64, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig observeMarkerSend = { { 895 /* observeMarkerSend */, 5, 65, 5, 70, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig isInertSendTarget = { { 913 /* isInertSendTarget */, 2, 71, 2, 73, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig observeArgument = { { 931 /* observeArgument */, 3, 74, 3, 77, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig observeLowerBound = { { 947 /* observeLowerBound */, 3, 78, 3, 81, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig isUninformativeSendTarget = { { 965 /* isUninformativeSendTarget */, 1, 82, 1, 83, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig hasOnlyInferableTemplates = { { 991 /* hasOnlyInferableTemplates */, 1, 84, 1, 85, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; } // namespace sig } // namespace ptdecl::TemplateArgumentObserver