From b3058f4df0139e87f7521d8edfd8f68e33e99f52 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Sat, 5 Sep 2026 10:24:04 +0200 Subject: [PATCH 1/4] Record definedness of short-circuit operand assignments as conditional on the assigned boolean When a boolean && / || RHS contains an assignment inside an operand, a truthy && (or falsey ||) result guarantees every short-circuit operand was evaluated. Diff the RHS walk's truthy/falsey continuation scope against the merged after-RHS scope for variables whose certainty is Yes there but only Maybe after the merge, and record conditional expression holders so that narrowing the assigned variable later restores the certainty and type. Co-authored-by: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01CGhnJQpUWRRpg6H5LuWJkA Amp-Thread-ID: https://ampcode.com/threads/T-01a19219-7dd4-76fa-9374-bbfeff99ea56 --- src/Analyser/ExprHandler/AssignHandler.php | 99 +++++++ tests/PHPStan/Analyser/nsrt/bug-11109.php | 40 +++ .../Variables/DefinedVariableRuleTest.php | 7 + .../Rules/Variables/data/bug-11109.php | 16 ++ turbo-ext/src/AssignHandler.cpp | 87 ++++++ turbo-ext/src/generated/AssignHandler.h | 250 ++++++++++-------- 6 files changed, 382 insertions(+), 117 deletions(-) create mode 100644 tests/PHPStan/Analyser/nsrt/bug-11109.php create mode 100644 tests/PHPStan/Rules/Variables/data/bug-11109.php diff --git a/src/Analyser/ExprHandler/AssignHandler.php b/src/Analyser/ExprHandler/AssignHandler.php index 62ee67ed27b..00f195e426e 100644 --- a/src/Analyser/ExprHandler/AssignHandler.php +++ b/src/Analyser/ExprHandler/AssignHandler.php @@ -8,7 +8,12 @@ use PhpParser\Node\Expr; use PhpParser\Node\Expr\ArrayDimFetch; use PhpParser\Node\Expr\Assign; +use PhpParser\Node\Expr\AssignOp; use PhpParser\Node\Expr\AssignRef; +use PhpParser\Node\Expr\BinaryOp\BooleanAnd; +use PhpParser\Node\Expr\BinaryOp\BooleanOr; +use PhpParser\Node\Expr\BinaryOp\LogicalAnd; +use PhpParser\Node\Expr\BinaryOp\LogicalOr; use PhpParser\Node\Expr\ConstFetch; use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Expr\List_; @@ -104,6 +109,7 @@ use function array_slice; use function count; use function in_array; +use function is_array; use function is_float; use function is_int; use function is_nan; @@ -1326,6 +1332,29 @@ public function applyWrite( : $this->defaultNarrowingHelper->specifyTypesForNode($scope, $assignedExpr, TypeSpecifierContext::createFalsey()); $conditionalExpressions = $this->processSureTypesForConditionalExpressionsAfterAssign($nodeScopeResolver, $scope, $storage, $var->name, $conditionalExpressions, $falseySpecifiedTypes, $falseyType, $impurePoints, $assignedExpr, $storedAssignedExprResult); $conditionalExpressions = $this->processSureNotTypesForConditionalExpressionsAfterAssign($nodeScopeResolver, $scope, $storage, $var->name, $conditionalExpressions, $falseySpecifiedTypes, $falseyType, $impurePoints, $assignedExpr, $storedAssignedExprResult); + + // An assignment inside a short-circuit operand may or may not have run + // (its variable is only maybe-defined after the RHS walk), but a truthy + // && (or falsey ||) guarantees the right operand was evaluated. The + // operand walk's truthy/falsey scope knows exactly which variables it + // defined - record their certainty as a consequence of the assigned + // boolean, e.g. "$bool = $x && ($var = 'foo'); if ($bool) { … $var … }". + if ( + $storedAssignedExprResult !== null + && ( + $assignedExpr instanceof BooleanAnd + || $assignedExpr instanceof BooleanOr + || $assignedExpr instanceof LogicalAnd + || $assignedExpr instanceof LogicalOr + ) + && self::containsVariableAssignment($assignedExpr) + ) { + if ($assignedExpr instanceof BooleanAnd || $assignedExpr instanceof LogicalAnd) { + $conditionalExpressions = $this->processDefinednessForConditionalExpressionsAfterAssign($conditionalExpressions, $var->name, $truthyType, $storedAssignedExprResult->getTruthyScope(), $scope); + } else { + $conditionalExpressions = $this->processDefinednessForConditionalExpressionsAfterAssign($conditionalExpressions, $var->name, $falseyType, $storedAssignedExprResult->getFalseyScope(), $scope); + } + } } foreach ([null, false, 0, 0.0, '', '0', []] as $falseyScalar) { @@ -2142,6 +2171,76 @@ private function processSureNotTypesForConditionalExpressionsAfterAssign(NodeSco return $conditionalExpressions; } + /** + * Records "if the assigned variable has $variableType, the target variable is + * certainly defined (with its branch-scope type)" holders for variables whose + * certainty is Yes in the given branch continuation scope of the RHS (the + * truthy scope of a `&&`, the falsey scope of a `||` - the scopes where every + * short-circuit operand was guaranteed evaluated) but only Maybe in the + * merged after-RHS scope. + * + * @param array $conditionalExpressions + * @return array + */ + private function processDefinednessForConditionalExpressionsAfterAssign( + array $conditionalExpressions, + string $variableName, + Type $variableType, + MutatingScope $branchScope, + MutatingScope $mergedScope, + ): array + { + foreach ($branchScope->expressionTypes as $exprString => $holder) { + if (!$holder->getCertainty()->yes()) { + continue; + } + $expr = $holder->getExpr(); + if (!$expr instanceof Variable || !is_string($expr->name) || $expr->name === $variableName) { + continue; + } + $mergedHolder = $mergedScope->expressionTypes[$exprString] ?? null; + if ($mergedHolder === null || !$mergedHolder->getCertainty()->maybe()) { + continue; + } + + $conditionalHolder = new ConditionalExpressionHolder([ + '$' . $variableName => ExpressionTypeHolder::createYes(new Variable($variableName), $variableType), + ], $holder); + $conditionalExpressions[(string) $exprString][$conditionalHolder->getKey()] = $conditionalHolder; + } + + return $conditionalExpressions; + } + + /** + * Whether the expression contains an assignment whose execution short-circuit + * evaluation may have skipped - a cheap AST gate so the truthy/falsey scope + * is only derived for boolean RHS expressions that can define a variable. + */ + private static function containsVariableAssignment(Node $node): bool + { + if ($node instanceof Assign || $node instanceof AssignOp || $node instanceof AssignRef) { + return true; + } + + foreach ($node->getSubNodeNames() as $subNodeName) { + $subNode = $node->$subNodeName; + if ($subNode instanceof Node) { + if (self::containsVariableAssignment($subNode)) { + return true; + } + } elseif (is_array($subNode)) { + foreach ($subNode as $subNodeItem) { + if ($subNodeItem instanceof Node && self::containsVariableAssignment($subNodeItem)) { + return true; + } + } + } + } + + return false; + } + /** * Current type of a conditional-holder expression, used to refine the holder's * projected type. Prefers the tracked scope state over the stored result, diff --git a/tests/PHPStan/Analyser/nsrt/bug-11109.php b/tests/PHPStan/Analyser/nsrt/bug-11109.php new file mode 100644 index 00000000000..9693317ec2b --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-11109.php @@ -0,0 +1,40 @@ +cliArgumentsVariablesRegistered = true; + $this->checkMaybeUndefinedVariables = true; + $this->analyse([__DIR__ . '/data/bug-11109.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Variables/data/bug-11109.php b/tests/PHPStan/Rules/Variables/data/bug-11109.php new file mode 100644 index 00000000000..e97dcc67072 --- /dev/null +++ b/tests/PHPStan/Rules/Variables/data/bug-11109.php @@ -0,0 +1,16 @@ +(ctx)->failed = true; + return false; + } + return instanceof_function(node->ce, assignCe) || instanceof_function(node->ce, assignOpCe) || instanceof_function(node->ce, assignRefCe); + } + + /* Whether the expression contains an assignment whose execution short-circuit + * evaluation may have skipped - a cheap AST gate so the truthy/falsey scope + * is only derived for boolean RHS expressions that can define a variable. */ + [[nodiscard]] static bool containsVariableAssignment(zval *node, bool &contains) + { + pt_find_ctx ctx = {}; + contains = pt_find_first_recursive(Z_OBJ_P(node), variableAssignmentMatcher, &ctx) != NULL; + return !ctx.failed; + } + /* (twin 2081) */ static zv::Val currentTypeForConditionalHolder(zval *nsr, zval *scope, zval *storage, zval *expr, zval *assignedExpr, zval *assignedValueResult) { diff --git a/turbo-ext/src/generated/AssignHandler.h b/turbo-ext/src/generated/AssignHandler.h index 5edaadc5cbe..d5809786a69 100644 --- a/turbo-ext/src/generated/AssignHandler.h +++ b/turbo-ext/src/generated/AssignHandler.h @@ -173,61 +173,67 @@ inline constexpr char strings[] = "rhsImpurePoints\0" /* 2531 */ "processSureTypesForConditionalExpressionsAfterAssign\0" /* 2547 */ "processSureNotTypesForConditionalExpressionsAfterAssign\0" /* 2600 */ - "currentTypeForConditionalHolder\0" /* 2656 */ - "armScope\0" /* 2688 */ - "armExpr\0" /* 2697 */ - "remainderType\0" /* 2705 */ - "otherArmType\0" /* 2719 */ - "processTernaryArmValueImpliedTypesAfterAssign\0" /* 2732 */ - "holderExpr\0" /* 2778 */ - "holderExprString\0" /* 2789 */ - "holderType\0" /* 2806 */ - "holderCertainty\0" /* 2817 */ - "PHPStan\\TrinaryLogic\0" /* 2833 */ - "addConditionalExpressionHolder\0" /* 2854 */ - "newConditionalExpressions\0" /* 2885 */ - "mergeConditionalExpressions\0" /* 2911 */ - "PhpParser\\Node\\Expr\\Match_\0" /* 2939 */ - "processMatchForConditionalExpressionsAfterAssign\0" /* 2966 */ - "assignedType\0" /* 3015 */ - "processDerivedConditionalExpressionsAfterAssign\0" /* 3028 */ - "PhpParser\\Node\\Expr\\FuncCall\0" /* 3076 */ - "processInArrayForConditionalExpressionsAfterAssign\0" /* 3105 */ - "isExprSafeToProjectThroughVariable\0" /* 3156 */ - "dimFetchStack\0" /* 3191 */ - "PHPStan\\Analyser\\Scope\0" /* 3205 */ - "isImplicitArrayCreation\0" /* 3228 */ - "rootVarName\0" /* 3252 */ - "arrayExpr\0" /* 3264 */ - "PhpParser\\Node\\Expr\\Array_\0" /* 3274 */ - "parentExpr\0" /* 3301 */ - "processArrayByRefItems\0" /* 3312 */ - "implicitIndex\0" /* 3335 */ - "processArrayByRefItemsWithImplicitIndex\0" /* 3349 */ - "isFlattenableUnpackedArray\0" /* 3389 */ - "index\0" /* 3416 */ - "advanceImplicitIndex\0" /* 3422 */ - "offsetTypes\0" /* 3443 */ - "offsetValueType\0" /* 3455 */ - "valueToWrite\0" /* 3471 */ - "produceArrayDimFetchAssignValueToWrite\0" /* 3484 */ - "arrayDimFetch\0" /* 3523 */ - "PhpParser\\Node\\Expr\\ArrayDimFetch\0" /* 3537 */ - "shouldKeepList\0" /* 3571 */ - "offsetType\0" /* 3586 */ - "trackedLinkImpliesOffset\0" /* 3597 */ - "a\0" /* 3622 */ - "b\0" /* 3624 */ - "isSameVariable\0" /* 3626 */ - "isSameOffset\0" /* 3641 */ - "getLiteralArrayKeyType\0" /* 3654 */ - "propertyFetch\0" /* 3677 */ - "PhpParser\\Node\\Expr\\PropertyFetch|PhpParser\\Node\\Expr\\StaticPropertyFetch\0" /* 3691 */ - "getOriginalPropertyType\0" /* 3765 */ - "array\0" /* 3789 */ - "hasArrayReference\0" /* 3795 */ - "rhs\0" /* 3813 */ - "redundant"; /* 3817 */ + "branchScope\0" /* 2656 */ + "mergedScope\0" /* 2668 */ + "processDefinednessForConditionalExpressionsAfterAssign\0" /* 2680 */ + "node\0" /* 2735 */ + "PhpParser\\Node\0" /* 2740 */ + "containsVariableAssignment\0" /* 2755 */ + "currentTypeForConditionalHolder\0" /* 2782 */ + "armScope\0" /* 2814 */ + "armExpr\0" /* 2823 */ + "remainderType\0" /* 2831 */ + "otherArmType\0" /* 2845 */ + "processTernaryArmValueImpliedTypesAfterAssign\0" /* 2858 */ + "holderExpr\0" /* 2904 */ + "holderExprString\0" /* 2915 */ + "holderType\0" /* 2932 */ + "holderCertainty\0" /* 2943 */ + "PHPStan\\TrinaryLogic\0" /* 2959 */ + "addConditionalExpressionHolder\0" /* 2980 */ + "newConditionalExpressions\0" /* 3011 */ + "mergeConditionalExpressions\0" /* 3037 */ + "PhpParser\\Node\\Expr\\Match_\0" /* 3065 */ + "processMatchForConditionalExpressionsAfterAssign\0" /* 3092 */ + "assignedType\0" /* 3141 */ + "processDerivedConditionalExpressionsAfterAssign\0" /* 3154 */ + "PhpParser\\Node\\Expr\\FuncCall\0" /* 3202 */ + "processInArrayForConditionalExpressionsAfterAssign\0" /* 3231 */ + "isExprSafeToProjectThroughVariable\0" /* 3282 */ + "dimFetchStack\0" /* 3317 */ + "PHPStan\\Analyser\\Scope\0" /* 3331 */ + "isImplicitArrayCreation\0" /* 3354 */ + "rootVarName\0" /* 3378 */ + "arrayExpr\0" /* 3390 */ + "PhpParser\\Node\\Expr\\Array_\0" /* 3400 */ + "parentExpr\0" /* 3427 */ + "processArrayByRefItems\0" /* 3438 */ + "implicitIndex\0" /* 3461 */ + "processArrayByRefItemsWithImplicitIndex\0" /* 3475 */ + "isFlattenableUnpackedArray\0" /* 3515 */ + "index\0" /* 3542 */ + "advanceImplicitIndex\0" /* 3548 */ + "offsetTypes\0" /* 3569 */ + "offsetValueType\0" /* 3581 */ + "valueToWrite\0" /* 3597 */ + "produceArrayDimFetchAssignValueToWrite\0" /* 3610 */ + "arrayDimFetch\0" /* 3649 */ + "PhpParser\\Node\\Expr\\ArrayDimFetch\0" /* 3663 */ + "shouldKeepList\0" /* 3697 */ + "offsetType\0" /* 3712 */ + "trackedLinkImpliesOffset\0" /* 3723 */ + "a\0" /* 3748 */ + "b\0" /* 3750 */ + "isSameVariable\0" /* 3752 */ + "isSameOffset\0" /* 3767 */ + "getLiteralArrayKeyType\0" /* 3780 */ + "propertyFetch\0" /* 3803 */ + "PhpParser\\Node\\Expr\\PropertyFetch|PhpParser\\Node\\Expr\\StaticPropertyFetch\0" /* 3817 */ + "getOriginalPropertyType\0" /* 3891 */ + "array\0" /* 3915 */ + "hasArrayReference\0" /* 3921 */ + "rhs\0" /* 3939 */ + "redundant"; /* 3943 */ inline constexpr reg::PackedArg args[] = { reg::packed(0, 0, 25), /* __construct $templateArgumentObserver */ reg::packed(76, 0, 99), /* __construct $varAnnotationProcessor */ @@ -361,6 +367,14 @@ inline constexpr reg::PackedArg args[] = { reg::packed(1672, 0, 1376), /* processSureNotTypesForConditionalExpressionsAfterAssign $assignedExpr */ reg::packed(1994, MAY_BE_NULL, 1626), /* processSureNotTypesForConditionalExpressionsAfterAssign $assignedValueResult */ reg::packed(1396, MAY_BE_ARRAY), /* processSureNotTypesForConditionalExpressionsAfterAssign return */ + reg::packed(2480, MAY_BE_ARRAY), /* processDefinednessForConditionalExpressionsAfterAssign $conditionalExpressions */ + reg::packed(2467, MAY_BE_STRING), /* processDefinednessForConditionalExpressionsAfterAssign $variableName */ + reg::packed(2518, 0, 2038), /* processDefinednessForConditionalExpressionsAfterAssign $variableType */ + reg::packed(2656, 0, 1490), /* processDefinednessForConditionalExpressionsAfterAssign $branchScope */ + reg::packed(2668, 0, 1490), /* processDefinednessForConditionalExpressionsAfterAssign $mergedScope */ + reg::packed(1396, MAY_BE_ARRAY), /* processDefinednessForConditionalExpressionsAfterAssign return */ + reg::packed(2735, 0, 2740), /* containsVariableAssignment $node */ + reg::packed(1396, MAY_BE_BOOL), /* containsVariableAssignment return */ reg::packed(1406, 0, 1424), /* currentTypeForConditionalHolder $nodeScopeResolver */ reg::packed(1484, 0, 1490), /* currentTypeForConditionalHolder $scope */ reg::packed(1521, 0, 1529), /* currentTypeForConditionalHolder $storage */ @@ -369,13 +383,13 @@ inline constexpr reg::PackedArg args[] = { reg::packed(1994, MAY_BE_NULL, 1626), /* currentTypeForConditionalHolder $assignedValueResult */ reg::packed(1396, 0, 2038), /* currentTypeForConditionalHolder return */ reg::packed(1406, 0, 1424), /* processTernaryArmValueImpliedTypesAfterAssign $nodeScopeResolver */ - reg::packed(2688, 0, 1490), /* processTernaryArmValueImpliedTypesAfterAssign $armScope */ + reg::packed(2814, 0, 1490), /* processTernaryArmValueImpliedTypesAfterAssign $armScope */ reg::packed(1521, 0, 1529), /* processTernaryArmValueImpliedTypesAfterAssign $storage */ reg::packed(2467, MAY_BE_STRING), /* processTernaryArmValueImpliedTypesAfterAssign $variableName */ reg::packed(2480, MAY_BE_ARRAY), /* processTernaryArmValueImpliedTypesAfterAssign $conditionalExpressions */ - reg::packed(2697, 0, 1376), /* processTernaryArmValueImpliedTypesAfterAssign $armExpr */ - reg::packed(2705, 0, 2038), /* processTernaryArmValueImpliedTypesAfterAssign $remainderType */ - reg::packed(2719, 0, 2038), /* processTernaryArmValueImpliedTypesAfterAssign $otherArmType */ + reg::packed(2823, 0, 1376), /* processTernaryArmValueImpliedTypesAfterAssign $armExpr */ + reg::packed(2831, 0, 2038), /* processTernaryArmValueImpliedTypesAfterAssign $remainderType */ + reg::packed(2845, 0, 2038), /* processTernaryArmValueImpliedTypesAfterAssign $otherArmType */ reg::packed(2531, MAY_BE_ARRAY), /* processTernaryArmValueImpliedTypesAfterAssign $rhsImpurePoints */ reg::packed(1672, 0, 1376), /* processTernaryArmValueImpliedTypesAfterAssign $assignedExpr */ reg::packed(1994, MAY_BE_NULL, 1626), /* processTernaryArmValueImpliedTypesAfterAssign $assignedValueResult */ @@ -383,32 +397,32 @@ inline constexpr reg::PackedArg args[] = { reg::packed(2480, MAY_BE_ARRAY), /* addConditionalExpressionHolder $conditionalExpressions */ reg::packed(2467, MAY_BE_STRING), /* addConditionalExpressionHolder $variableName */ reg::packed(2518, 0, 2038), /* addConditionalExpressionHolder $variableType */ - reg::packed(2778, 0, 1376), /* addConditionalExpressionHolder $holderExpr */ - reg::packed(2789, MAY_BE_STRING), /* addConditionalExpressionHolder $holderExprString */ - reg::packed(2806, 0, 2038), /* addConditionalExpressionHolder $holderType */ - reg::packed(2817, 0, 2833), /* addConditionalExpressionHolder $holderCertainty */ + reg::packed(2904, 0, 1376), /* addConditionalExpressionHolder $holderExpr */ + reg::packed(2915, MAY_BE_STRING), /* addConditionalExpressionHolder $holderExprString */ + reg::packed(2932, 0, 2038), /* addConditionalExpressionHolder $holderType */ + reg::packed(2943, 0, 2959), /* addConditionalExpressionHolder $holderCertainty */ reg::packed(1396, MAY_BE_ARRAY), /* addConditionalExpressionHolder return */ reg::packed(2480, MAY_BE_ARRAY), /* mergeConditionalExpressions $conditionalExpressions */ - reg::packed(2885, MAY_BE_ARRAY), /* mergeConditionalExpressions $newConditionalExpressions */ + reg::packed(3011, MAY_BE_ARRAY), /* mergeConditionalExpressions $newConditionalExpressions */ reg::packed(1396, MAY_BE_ARRAY), /* mergeConditionalExpressions return */ reg::packed(1484, 0, 1490), /* processMatchForConditionalExpressionsAfterAssign $scope */ reg::packed(2467, MAY_BE_STRING), /* processMatchForConditionalExpressionsAfterAssign $variableName */ - reg::packed(1371, 0, 2939), /* processMatchForConditionalExpressionsAfterAssign $expr */ + reg::packed(1371, 0, 3065), /* processMatchForConditionalExpressionsAfterAssign $expr */ reg::packed(1396, MAY_BE_ARRAY), /* processMatchForConditionalExpressionsAfterAssign return */ reg::packed(1406, 0, 1424), /* processDerivedConditionalExpressionsAfterAssign $nodeScopeResolver */ reg::packed(1484, 0, 1490), /* processDerivedConditionalExpressionsAfterAssign $scope */ reg::packed(2467, MAY_BE_STRING), /* processDerivedConditionalExpressionsAfterAssign $variableName */ reg::packed(2480, MAY_BE_ARRAY), /* processDerivedConditionalExpressionsAfterAssign $conditionalExpressions */ reg::packed(1672, 0, 1376), /* processDerivedConditionalExpressionsAfterAssign $assignedExpr */ - reg::packed(3015, 0, 2038), /* processDerivedConditionalExpressionsAfterAssign $assignedType */ + reg::packed(3141, 0, 2038), /* processDerivedConditionalExpressionsAfterAssign $assignedType */ reg::packed(2531, MAY_BE_ARRAY), /* processDerivedConditionalExpressionsAfterAssign $rhsImpurePoints */ reg::packed(1396, MAY_BE_ARRAY), /* processDerivedConditionalExpressionsAfterAssign return */ reg::packed(1406, 0, 1424), /* processInArrayForConditionalExpressionsAfterAssign $nodeScopeResolver */ reg::packed(1484, 0, 1490), /* processInArrayForConditionalExpressionsAfterAssign $scope */ reg::packed(2467, MAY_BE_STRING), /* processInArrayForConditionalExpressionsAfterAssign $variableName */ reg::packed(2480, MAY_BE_ARRAY), /* processInArrayForConditionalExpressionsAfterAssign $conditionalExpressions */ - reg::packed(1672, 0, 3076), /* processInArrayForConditionalExpressionsAfterAssign $assignedExpr */ - reg::packed(3015, 0, 2038), /* processInArrayForConditionalExpressionsAfterAssign $assignedType */ + reg::packed(1672, 0, 3202), /* processInArrayForConditionalExpressionsAfterAssign $assignedExpr */ + reg::packed(3141, 0, 2038), /* processInArrayForConditionalExpressionsAfterAssign $assignedType */ reg::packed(2531, MAY_BE_ARRAY), /* processInArrayForConditionalExpressionsAfterAssign $rhsImpurePoints */ reg::packed(1396, MAY_BE_ARRAY), /* processInArrayForConditionalExpressionsAfterAssign return */ reg::packed(1371, 0, 1376), /* isExprSafeToProjectThroughVariable $expr */ @@ -416,60 +430,60 @@ inline constexpr reg::PackedArg args[] = { reg::packed(2531, MAY_BE_ARRAY), /* isExprSafeToProjectThroughVariable $rhsImpurePoints */ reg::packed(1672, 0, 1376), /* isExprSafeToProjectThroughVariable $assignedExpr */ reg::packed(1396, MAY_BE_BOOL), /* isExprSafeToProjectThroughVariable return */ - reg::packed(3191, MAY_BE_ARRAY), /* isImplicitArrayCreation $dimFetchStack */ - reg::packed(1484, 0, 3205), /* isImplicitArrayCreation $scope */ - reg::packed(1396, 0, 2833), /* isImplicitArrayCreation return */ + reg::packed(3317, MAY_BE_ARRAY), /* isImplicitArrayCreation $dimFetchStack */ + reg::packed(1484, 0, 3331), /* isImplicitArrayCreation $scope */ + reg::packed(1396, 0, 2959), /* isImplicitArrayCreation return */ reg::packed(1406, 0, 1424), /* processArrayByRefItems $nodeScopeResolver */ reg::packed(1484, 0, 1490), /* processArrayByRefItems $scope */ reg::packed(1521, 0, 1529), /* processArrayByRefItems $storage */ - reg::packed(3252, MAY_BE_STRING), /* processArrayByRefItems $rootVarName */ - reg::packed(3264, 0, 3274), /* processArrayByRefItems $arrayExpr */ - reg::packed(3301, 0, 1376), /* processArrayByRefItems $parentExpr */ + reg::packed(3378, MAY_BE_STRING), /* processArrayByRefItems $rootVarName */ + reg::packed(3390, 0, 3400), /* processArrayByRefItems $arrayExpr */ + reg::packed(3427, 0, 1376), /* processArrayByRefItems $parentExpr */ reg::packed(1396, 0, 1490), /* processArrayByRefItems return */ reg::packed(1406, 0, 1424), /* processArrayByRefItemsWithImplicitIndex $nodeScopeResolver */ reg::packed(1484, 0, 1490), /* processArrayByRefItemsWithImplicitIndex $scope */ reg::packed(1521, 0, 1529), /* processArrayByRefItemsWithImplicitIndex $storage */ - reg::packed(3252, MAY_BE_STRING), /* processArrayByRefItemsWithImplicitIndex $rootVarName */ - reg::packed(3264, 0, 3274), /* processArrayByRefItemsWithImplicitIndex $arrayExpr */ - reg::packed(3301, 0, 1376), /* processArrayByRefItemsWithImplicitIndex $parentExpr */ - reg::packed(3335, MAY_BE_NULL | MAY_BE_LONG), /* processArrayByRefItemsWithImplicitIndex $implicitIndex */ + reg::packed(3378, MAY_BE_STRING), /* processArrayByRefItemsWithImplicitIndex $rootVarName */ + reg::packed(3390, 0, 3400), /* processArrayByRefItemsWithImplicitIndex $arrayExpr */ + reg::packed(3427, 0, 1376), /* processArrayByRefItemsWithImplicitIndex $parentExpr */ + reg::packed(3461, MAY_BE_NULL | MAY_BE_LONG), /* processArrayByRefItemsWithImplicitIndex $implicitIndex */ reg::packed(1396, MAY_BE_ARRAY), /* processArrayByRefItemsWithImplicitIndex return */ - reg::packed(3264, 0, 3274), /* isFlattenableUnpackedArray $arrayExpr */ + reg::packed(3390, 0, 3400), /* isFlattenableUnpackedArray $arrayExpr */ reg::packed(1396, MAY_BE_BOOL), /* isFlattenableUnpackedArray return */ - reg::packed(3416, MAY_BE_LONG), /* advanceImplicitIndex $index */ + reg::packed(3542, MAY_BE_LONG), /* advanceImplicitIndex $index */ reg::packed(1396, MAY_BE_NULL | MAY_BE_LONG), /* advanceImplicitIndex return */ reg::packed(1406, 0, 1424), /* produceArrayDimFetchAssignValueToWrite $nodeScopeResolver */ - reg::packed(3191, MAY_BE_ARRAY), /* produceArrayDimFetchAssignValueToWrite $dimFetchStack */ - reg::packed(3443, MAY_BE_ARRAY), /* produceArrayDimFetchAssignValueToWrite $offsetTypes */ - reg::packed(3455, 0, 2038), /* produceArrayDimFetchAssignValueToWrite $offsetValueType */ - reg::packed(3471, 0, 2038), /* produceArrayDimFetchAssignValueToWrite $valueToWrite */ + reg::packed(3317, MAY_BE_ARRAY), /* produceArrayDimFetchAssignValueToWrite $dimFetchStack */ + reg::packed(3569, MAY_BE_ARRAY), /* produceArrayDimFetchAssignValueToWrite $offsetTypes */ + reg::packed(3581, 0, 2038), /* produceArrayDimFetchAssignValueToWrite $offsetValueType */ + reg::packed(3597, 0, 2038), /* produceArrayDimFetchAssignValueToWrite $valueToWrite */ reg::packed(1484, 0, 1490), /* produceArrayDimFetchAssignValueToWrite $scope */ reg::packed(1521, 0, 1529), /* produceArrayDimFetchAssignValueToWrite $storage */ reg::packed(1396, MAY_BE_ARRAY), /* produceArrayDimFetchAssignValueToWrite return */ reg::packed(1406, 0, 1424), /* shouldKeepList $nodeScopeResolver */ - reg::packed(3523, 0, 3537), /* shouldKeepList $arrayDimFetch */ + reg::packed(3649, 0, 3663), /* shouldKeepList $arrayDimFetch */ reg::packed(1484, 0, 1490), /* shouldKeepList $scope */ reg::packed(1521, 0, 1529), /* shouldKeepList $storage */ - reg::packed(3455, 0, 2038), /* shouldKeepList $offsetValueType */ + reg::packed(3581, 0, 2038), /* shouldKeepList $offsetValueType */ reg::packed(1396, MAY_BE_BOOL), /* shouldKeepList return */ - reg::packed(3455, 0, 2038), /* trackedLinkImpliesOffset $offsetValueType */ - reg::packed(3586, 0, 2038), /* trackedLinkImpliesOffset $offsetType */ + reg::packed(3581, 0, 2038), /* trackedLinkImpliesOffset $offsetValueType */ + reg::packed(3712, 0, 2038), /* trackedLinkImpliesOffset $offsetType */ reg::packed(1396, MAY_BE_BOOL), /* trackedLinkImpliesOffset return */ - reg::packed(3622, 0, 1376), /* isSameVariable $a */ - reg::packed(3624, 0, 1376), /* isSameVariable $b */ + reg::packed(3748, 0, 1376), /* isSameVariable $a */ + reg::packed(3750, 0, 1376), /* isSameVariable $b */ reg::packed(1396, MAY_BE_BOOL), /* isSameVariable return */ - reg::packed(3622, 0, 1376), /* isSameOffset $a */ - reg::packed(3624, 0, 1376), /* isSameOffset $b */ + reg::packed(3748, 0, 1376), /* isSameOffset $a */ + reg::packed(3750, 0, 1376), /* isSameOffset $b */ reg::packed(1396, MAY_BE_BOOL), /* isSameOffset return */ reg::packed(1371, 0, 1376), /* getLiteralArrayKeyType $expr */ reg::packed(1396, MAY_BE_NULL, 2038), /* getLiteralArrayKeyType return */ reg::packed(1406, 0, 1424), /* getOriginalPropertyType $nodeScopeResolver */ - reg::packed(3677, 0, 3691), /* getOriginalPropertyType $propertyFetch */ + reg::packed(3803, 0, 3817), /* getOriginalPropertyType $propertyFetch */ reg::packed(1484, 0, 1490), /* getOriginalPropertyType $scope */ reg::packed(1396, 0, 2038), /* getOriginalPropertyType return */ - reg::packed(3789, 0, 3274), /* hasArrayReference $array */ + reg::packed(3915, 0, 3400), /* hasArrayReference $array */ reg::packed(1396, MAY_BE_BOOL), /* hasArrayReference return */ - reg::packed(3813, 0, 1626), /* redundant $rhs */ + reg::packed(3939, 0, 1626), /* redundant $rhs */ reg::packed(1975, 0, 1376), /* redundant $target */ reg::packed(1521, 0, 1529), /* redundant $storage */ reg::packed(1396, MAY_BE_NULL, 2038), /* redundant return */ @@ -497,28 +511,30 @@ inline constexpr sigtab::Sig assignDynamicVariable = { { 2432 /* assignDynamicVa inline constexpr sigtab::Sig unwrapAssign = { { 2454 /* unwrapAssign */, 1, 108, 1, 109, ZEND_ACC_PRIVATE } }; inline constexpr sigtab::Sig processSureTypesForConditionalExpressionsAfterAssign = { { 2547 /* processSureTypesForConditionalExpressionsAfterAssign */, 10, 110, 10, 120, ZEND_ACC_PRIVATE } }; inline constexpr sigtab::Sig processSureNotTypesForConditionalExpressionsAfterAssign = { { 2600 /* processSureNotTypesForConditionalExpressionsAfterAssign */, 10, 121, 10, 131, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig currentTypeForConditionalHolder = { { 2656 /* currentTypeForConditionalHolder */, 6, 132, 6, 138, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processTernaryArmValueImpliedTypesAfterAssign = { { 2732 /* processTernaryArmValueImpliedTypesAfterAssign */, 11, 139, 11, 150, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig addConditionalExpressionHolder = { { 2854 /* addConditionalExpressionHolder */, 7, 151, 7, 158, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig mergeConditionalExpressions = { { 2911 /* mergeConditionalExpressions */, 2, 159, 2, 161, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processMatchForConditionalExpressionsAfterAssign = { { 2966 /* processMatchForConditionalExpressionsAfterAssign */, 3, 162, 3, 165, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processDerivedConditionalExpressionsAfterAssign = { { 3028 /* processDerivedConditionalExpressionsAfterAssign */, 7, 166, 7, 173, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processInArrayForConditionalExpressionsAfterAssign = { { 3105 /* processInArrayForConditionalExpressionsAfterAssign */, 7, 174, 7, 181, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig isExprSafeToProjectThroughVariable = { { 3156 /* isExprSafeToProjectThroughVariable */, 4, 182, 4, 186, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig isImplicitArrayCreation = { { 3228 /* isImplicitArrayCreation */, 2, 187, 2, 189, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processArrayByRefItems = { { 3312 /* processArrayByRefItems */, 6, 190, 6, 196, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processArrayByRefItemsWithImplicitIndex = { { 3349 /* processArrayByRefItemsWithImplicitIndex */, 7, 197, 7, 204, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig isFlattenableUnpackedArray = { { 3389 /* isFlattenableUnpackedArray */, 1, 205, 1, 206, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig advanceImplicitIndex = { { 3422 /* advanceImplicitIndex */, 1, 207, 1, 208, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig produceArrayDimFetchAssignValueToWrite = { { 3484 /* produceArrayDimFetchAssignValueToWrite */, 7, 209, 7, 216, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig shouldKeepList = { { 3571 /* shouldKeepList */, 5, 217, 5, 222, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig trackedLinkImpliesOffset = { { 3597 /* trackedLinkImpliesOffset */, 2, 223, 2, 225, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig isSameVariable = { { 3626 /* isSameVariable */, 2, 226, 2, 228, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig isSameOffset = { { 3641 /* isSameOffset */, 2, 229, 2, 231, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig getLiteralArrayKeyType = { { 3654 /* getLiteralArrayKeyType */, 1, 232, 1, 233, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig getOriginalPropertyType = { { 3765 /* getOriginalPropertyType */, 3, 234, 3, 237, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig hasArrayReference = { { 3795 /* hasArrayReference */, 1, 238, 1, 239, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; -inline constexpr sigtab::Sig redundant = { { 3817 /* redundant */, 3, 240, 3, 243, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig processDefinednessForConditionalExpressionsAfterAssign = { { 2680 /* processDefinednessForConditionalExpressionsAfterAssign */, 5, 132, 5, 137, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig containsVariableAssignment = { { 2755 /* containsVariableAssignment */, 1, 138, 1, 139, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig currentTypeForConditionalHolder = { { 2782 /* currentTypeForConditionalHolder */, 6, 140, 6, 146, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processTernaryArmValueImpliedTypesAfterAssign = { { 2858 /* processTernaryArmValueImpliedTypesAfterAssign */, 11, 147, 11, 158, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig addConditionalExpressionHolder = { { 2980 /* addConditionalExpressionHolder */, 7, 159, 7, 166, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig mergeConditionalExpressions = { { 3037 /* mergeConditionalExpressions */, 2, 167, 2, 169, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processMatchForConditionalExpressionsAfterAssign = { { 3092 /* processMatchForConditionalExpressionsAfterAssign */, 3, 170, 3, 173, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processDerivedConditionalExpressionsAfterAssign = { { 3154 /* processDerivedConditionalExpressionsAfterAssign */, 7, 174, 7, 181, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processInArrayForConditionalExpressionsAfterAssign = { { 3231 /* processInArrayForConditionalExpressionsAfterAssign */, 7, 182, 7, 189, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig isExprSafeToProjectThroughVariable = { { 3282 /* isExprSafeToProjectThroughVariable */, 4, 190, 4, 194, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig isImplicitArrayCreation = { { 3354 /* isImplicitArrayCreation */, 2, 195, 2, 197, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processArrayByRefItems = { { 3438 /* processArrayByRefItems */, 6, 198, 6, 204, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processArrayByRefItemsWithImplicitIndex = { { 3475 /* processArrayByRefItemsWithImplicitIndex */, 7, 205, 7, 212, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig isFlattenableUnpackedArray = { { 3515 /* isFlattenableUnpackedArray */, 1, 213, 1, 214, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig advanceImplicitIndex = { { 3548 /* advanceImplicitIndex */, 1, 215, 1, 216, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig produceArrayDimFetchAssignValueToWrite = { { 3610 /* produceArrayDimFetchAssignValueToWrite */, 7, 217, 7, 224, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig shouldKeepList = { { 3697 /* shouldKeepList */, 5, 225, 5, 230, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig trackedLinkImpliesOffset = { { 3723 /* trackedLinkImpliesOffset */, 2, 231, 2, 233, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig isSameVariable = { { 3752 /* isSameVariable */, 2, 234, 2, 236, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig isSameOffset = { { 3767 /* isSameOffset */, 2, 237, 2, 239, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig getLiteralArrayKeyType = { { 3780 /* getLiteralArrayKeyType */, 1, 240, 1, 241, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig getOriginalPropertyType = { { 3891 /* getOriginalPropertyType */, 3, 242, 3, 245, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig hasArrayReference = { { 3921 /* hasArrayReference */, 1, 246, 1, 247, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig redundant = { { 3943 /* redundant */, 3, 248, 3, 251, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; } // namespace sig } // namespace ptdecl::AssignHandler From b99041fdc077f32c2078352fc0df870695fe6bba Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Sat, 5 Sep 2026 10:30:41 +0200 Subject: [PATCH 2/4] Record try-path definedness as conditional on the catch variable being undefined At a try/catch join where the catch variable is untracked on the non-catch path and certainly defined at the end of the catch body, its later definedness tells the joined paths apart. Record conditional expression holders with a certainty-No (and, for scopes where any variable can exist, a maybe-defined-null) condition on the catch variable, restoring the non-catch certainty and type of variables the join demoted to maybe-defined. To let such holders fire, the isset()-style falsey specification in MutatingScope::applySpecifiedTypes() now publishes the certainty change into the specified-expressions batch - rescuing the waiting holders around unsetExpression()'s invalidation, which would otherwise drop them at the very specification they wait for. A second catch clause merging into the join drops the holders via the conditional-expressions intersection, so multi-catch stays conservative. Co-authored-by: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01CGhnJQpUWRRpg6H5LuWJkA Amp-Thread-ID: https://ampcode.com/threads/T-01a19219-7dd4-76fa-9374-bbfeff99ea56 --- src/Analyser/MutatingScope.php | 25 ++++ src/Analyser/StmtHandler/TryCatchHandler.php | 80 ++++++++++- tests/PHPStan/Analyser/nsrt/bug-6608.php | 23 ++++ .../Variables/DefinedVariableRuleTest.php | 7 + .../PHPStan/Rules/Variables/data/bug-6608.php | 8 ++ turbo-ext/src/MutatingScope.cpp | 86 +++++++++++- turbo-ext/src/TryCatchHandler.cpp | 124 ++++++++++++++++++ turbo-ext/src/generated/TryCatchHandler.h | 13 +- 8 files changed, 363 insertions(+), 3 deletions(-) create mode 100644 tests/PHPStan/Analyser/nsrt/bug-6608.php create mode 100644 tests/PHPStan/Rules/Variables/data/bug-6608.php diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 85867200a20..e344a01f711 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -4040,12 +4040,37 @@ public function applySpecifiedTypes(SpecifiedTypes $specifiedTypes): self $expr = $issetExpr->getExpr(); if ($typeSpecification['sure']) { + $innerExprString = $scope->getNodeKey($expr); $scope = $scope->setExpressionCertaintyKeepingType( $expr, TrinaryLogic::createMaybe(), ); + $specifiedExpressions[$innerExprString] = ExpressionTypeHolder::createMaybe( + $expr, + $scope->expressionTypes[$innerExprString]->getType(), + ); } else { + $innerExprString = $scope->getNodeKey($expr); + // Holders conditioned on this expression being undefined (a + // certainty-No condition) wait for exactly the specification + // applied here, but unsetExpression()'s invalidation would drop + // them before the conditional-expressions matcher below could + // fire them - carve them out and re-add them afterwards. + $rescuedHolders = []; + foreach ($scope->conditionalExpressions as $targetExprString => $targetHolders) { + foreach ($targetHolders as $holderKey => $conditionalHolder) { + $conditionHolder = $conditionalHolder->getConditionExpressionTypeHolders()[$innerExprString] ?? null; + if ($conditionHolder === null || !$conditionHolder->getCertainty()->no()) { + continue; + } + $rescuedHolders[$targetExprString][$holderKey] = $conditionalHolder; + } + } $scope = $scope->unsetExpression($expr); + foreach ($rescuedHolders as $targetExprString => $targetHolders) { + $scope = $scope->addConditionalExpressions((string) $targetExprString, $targetHolders); + } + $specifiedExpressions[$innerExprString] = new ExpressionTypeHolder($expr, new ErrorType(), TrinaryLogic::createNo()); } $scopeIsWorkingCopy = false; diff --git a/src/Analyser/StmtHandler/TryCatchHandler.php b/src/Analyser/StmtHandler/TryCatchHandler.php index c41c2168982..e0729fe11b9 100644 --- a/src/Analyser/StmtHandler/TryCatchHandler.php +++ b/src/Analyser/StmtHandler/TryCatchHandler.php @@ -8,7 +8,10 @@ use PhpParser\Node\Expr; use PhpParser\Node\Stmt; use PhpParser\Node\Stmt\TryCatch; +use PhpParser\Node\Expr\Variable; +use PHPStan\Analyser\ConditionalExpressionHolder; use PHPStan\Analyser\ExpressionResultStorage; +use PHPStan\Analyser\ExpressionTypeHolder; use PHPStan\Analyser\InternalStatementExitPoint; use PHPStan\Analyser\InternalStatementResult; use PHPStan\Analyser\InternalThrowPoint; @@ -28,8 +31,11 @@ use PHPStan\Node\Variable\VariableWrite; use PHPStan\Node\VariableAssignNode; use PHPStan\ShouldNotHappenException; +use PHPStan\TrinaryLogic; use PHPStan\Turbo\ShadowedByTurboExtension; +use PHPStan\Type\ErrorType; use PHPStan\Type\NeverType; +use PHPStan\Type\NullType; use PHPStan\Type\ObjectType; use PHPStan\Type\TypeCombinator; use Throwable; @@ -272,7 +278,13 @@ public function processStmt( $blockScopes[] = $catchScopeForFinally; $catchFlows[] = [$originalCatchType, VariableFlow::sequence($catchNode->var !== null ? VariableFlowBuilder::targetWrite($catchNode->var, VariableWrite::KIND_CATCH, $catchScopeForFinally, $storage) : null, $catchScopeResult->getVariableFlow())]; - $finalScope = $catchScopeResult->isAlwaysTerminating() ? $finalScope : $catchScopeResult->getScope()->mergeWith($finalScope); + if (!$catchScopeResult->isAlwaysTerminating()) { + $mergedScope = $catchScopeResult->getScope()->mergeWith($finalScope); + if ($variableName !== null && $finalScope !== null) { + $mergedScope = $this->addCatchVariableDefinednessConditionals($mergedScope, $finalScope, $catchScopeResult->getScope(), $variableName); + } + $finalScope = $mergedScope; + } $alwaysTerminating = $alwaysTerminating && $catchScopeResult->isAlwaysTerminating(); $hasYield = $hasYield || $catchScopeResult->hasYield(); $catchThrowPoints = $catchScopeResult->getThrowPoints(); @@ -362,4 +374,70 @@ public function processStmt( return new InternalStatementResult($finalScope, hasYield: $hasYield, isAlwaysTerminating: $alwaysTerminating, exitPoints: $exitPoints, throwPoints: array_merge($throwPoints, $throwPointsForLater), impurePoints: $impurePoints, variableFlow: VariableFlow::tryCatch($branchScopeResult->getVariableFlow(), $catchFlows, $finallyFlow), dependencies: Dependencies::merge(...$dependencies)); } + /** + * The catch variable's definedness after the try/catch tells the two joined + * paths apart: when it is untracked on the non-catch path and certainly + * defined at the end of the catch body, "the catch variable is undefined" + * later implies the non-catch path ran. Record that as conditional + * expression holders with a certainty-No condition on the catch variable, + * restoring the non-catch certainty (and type) of variables the join + * demoted to maybe-defined - e.g. `isset($e) || $var instanceof \DateTime` + * evaluates `$var` only where `$e` is narrowed away. + */ + private function addCatchVariableDefinednessConditionals( + MutatingScope $mergedScope, + MutatingScope $nonCatchScope, + MutatingScope $catchEndScope, + string $variableName, + ): MutatingScope + { + $variableExprString = '$' . $variableName; + if (isset($nonCatchScope->expressionTypes[$variableExprString])) { + return $mergedScope; + } + + $catchVariableHolder = $catchEndScope->expressionTypes[$variableExprString] ?? null; + if ($catchVariableHolder === null || !$catchVariableHolder->getCertainty()->yes()) { + return $mergedScope; + } + + $conditions = [ + [ + $variableExprString => new ExpressionTypeHolder(new Variable($variableName), new ErrorType(), TrinaryLogic::createNo()), + ], + ]; + if ($catchVariableHolder->getType()->isNull()->no()) { + // In a scope where any variable can exist (e.g. the top level), the + // isset() machinery models "!isset($e)" on a maybe-defined variable as + // "maybe defined, null when defined" instead of unsetting it. That + // state excludes the catch path just the same - it guarantees a + // defined, non-null catch variable. + $conditions[] = [ + $variableExprString => ExpressionTypeHolder::createMaybe(new Variable($variableName), new NullType()), + ]; + } + foreach ($nonCatchScope->expressionTypes as $exprString => $holder) { + if (!$holder->getCertainty()->yes()) { + continue; + } + $expr = $holder->getExpr(); + if (!$expr instanceof Variable || !is_string($expr->name)) { + continue; + } + $mergedHolder = $mergedScope->expressionTypes[$exprString] ?? null; + if ($mergedHolder === null || !$mergedHolder->getCertainty()->maybe()) { + continue; + } + + $conditionalHolders = []; + foreach ($conditions as $condition) { + $conditionalHolder = new ConditionalExpressionHolder($condition, $holder); + $conditionalHolders[$conditionalHolder->getKey()] = $conditionalHolder; + } + $mergedScope = $mergedScope->addConditionalExpressions((string) $exprString, $conditionalHolders); + } + + return $mergedScope; + } + } diff --git a/tests/PHPStan/Analyser/nsrt/bug-6608.php b/tests/PHPStan/Analyser/nsrt/bug-6608.php new file mode 100644 index 00000000000..d213f1b5633 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-6608.php @@ -0,0 +1,23 @@ +analyse([__DIR__ . '/data/bug-11109.php'], []); } + public function testBug6608(): void + { + $this->cliArgumentsVariablesRegistered = true; + $this->checkMaybeUndefinedVariables = true; + $this->analyse([__DIR__ . '/data/bug-6608.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Variables/data/bug-6608.php b/tests/PHPStan/Rules/Variables/data/bug-6608.php new file mode 100644 index 00000000000..e1e82e75908 --- /dev/null +++ b/tests/PHPStan/Rules/Variables/data/bug-6608.php @@ -0,0 +1,8 @@ +toString() */ zv::Val nameToString(zval *name) { @@ -617,7 +737,11 @@ class TryCatchHandler zv::Val hold; zval *resultScope = pt_internal_statement_result_scope(catchResult, hold); if (UNEXPECTED(resultScope == NULL)) return zv::Val(); + zv::Val nonCatchScope = zv::Val::copyOf(finalScope.ref()); if (UNEXPECTED(!ptlh::otherMergeWith(resultScope, finalScope))) return zv::Val(); + if (variableName != NULL && !nonCatchScope.isNull()) { + if (UNEXPECTED(!addCatchVariableDefinednessConditionals(finalScope, nonCatchScope.raw(), resultScope, Z_STR_P(variableNameHold.raw())))) return zv::Val(); + } } alwaysTerminating = alwaysTerminating && catchAlwaysTerminating; if (!hasYield) { diff --git a/turbo-ext/src/generated/TryCatchHandler.h b/turbo-ext/src/generated/TryCatchHandler.h index 911332d7f79..af137f165b9 100644 --- a/turbo-ext/src/generated/TryCatchHandler.h +++ b/turbo-ext/src/generated/TryCatchHandler.h @@ -45,7 +45,12 @@ inline constexpr char strings[] = "context\0" /* 252 */ "PHPStan\\Analyser\\StatementContext\0" /* 260 */ "PHPStan\\Analyser\\InternalStatementResult\0" /* 294 */ - "processStmt"; /* 335 */ + "processStmt\0" /* 335 */ + "mergedScope\0" /* 347 */ + "nonCatchScope\0" /* 359 */ + "catchEndScope\0" /* 373 */ + "variableName\0" /* 387 */ + "addCatchVariableDefinednessConditionals"; /* 400 */ inline constexpr reg::PackedArg args[] = { reg::packed(0, 0, 18), /* __construct $statementsHandler */ reg::packed(65, 0, 70), /* supports $stmt */ @@ -57,6 +62,11 @@ inline constexpr reg::PackedArg args[] = { reg::packed(239, MAY_BE_CALLABLE), /* processStmt $nodeCallback */ reg::packed(252, 0, 260), /* processStmt $context */ reg::packed(90, 0, 294), /* processStmt return */ + reg::packed(347, 0, 159), /* addCatchVariableDefinednessConditionals $mergedScope */ + reg::packed(359, 0, 159), /* addCatchVariableDefinednessConditionals $nonCatchScope */ + reg::packed(373, 0, 159), /* addCatchVariableDefinednessConditionals $catchEndScope */ + reg::packed(387, MAY_BE_STRING), /* addCatchVariableDefinednessConditionals $variableName */ + reg::packed(90, 0, 159), /* addCatchVariableDefinednessConditionals return */ }; using Sig = reg::Sig; } // namespace sigtab @@ -66,6 +76,7 @@ namespace sig { inline constexpr sigtab::Sig __construct = { { 53 /* __construct */, 1, 0, 1, reg::NoArg, ZEND_ACC_PUBLIC } }; inline constexpr sigtab::Sig supports = { { 91 /* supports */, 1, 1, 1, 2, ZEND_ACC_PUBLIC } }; inline constexpr sigtab::Sig processStmt = { { 335 /* processStmt */, 6, 3, 6, 9, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig addCatchVariableDefinednessConditionals = { { 400 /* addCatchVariableDefinednessConditionals */, 4, 10, 4, 14, ZEND_ACC_PRIVATE } }; } // namespace sig } // namespace ptdecl::TryCatchHandler From 56008f922748634b942db4eba233a3830742d719 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Sat, 5 Sep 2026 14:46:46 +0200 Subject: [PATCH 3/4] Fix self-analysis and code style after definedness-holder changes The definedness-holder changes added three `(string)` casts on array keys documented as strings - load-bearing under strict_types because numeric-string keys become ints at runtime. Suppress them inline like ScopeOps does instead of growing the baseline counts. Also sort the TryCatchHandler imports. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01CGhnJQpUWRRpg6H5LuWJkA --- src/Analyser/ExprHandler/AssignHandler.php | 2 +- src/Analyser/MutatingScope.php | 2 +- src/Analyser/StmtHandler/TryCatchHandler.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Analyser/ExprHandler/AssignHandler.php b/src/Analyser/ExprHandler/AssignHandler.php index 00f195e426e..414ccb00700 100644 --- a/src/Analyser/ExprHandler/AssignHandler.php +++ b/src/Analyser/ExprHandler/AssignHandler.php @@ -2206,7 +2206,7 @@ private function processDefinednessForConditionalExpressionsAfterAssign( $conditionalHolder = new ConditionalExpressionHolder([ '$' . $variableName => ExpressionTypeHolder::createYes(new Variable($variableName), $variableType), ], $holder); - $conditionalExpressions[(string) $exprString][$conditionalHolder->getKey()] = $conditionalHolder; + $conditionalExpressions[(string) $exprString][$conditionalHolder->getKey()] = $conditionalHolder; // @phpstan-ignore cast.useless } return $conditionalExpressions; diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index e344a01f711..b9277f0f8f3 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -4068,7 +4068,7 @@ public function applySpecifiedTypes(SpecifiedTypes $specifiedTypes): self } $scope = $scope->unsetExpression($expr); foreach ($rescuedHolders as $targetExprString => $targetHolders) { - $scope = $scope->addConditionalExpressions((string) $targetExprString, $targetHolders); + $scope = $scope->addConditionalExpressions((string) $targetExprString, $targetHolders); // @phpstan-ignore cast.useless } $specifiedExpressions[$innerExprString] = new ExpressionTypeHolder($expr, new ErrorType(), TrinaryLogic::createNo()); } diff --git a/src/Analyser/StmtHandler/TryCatchHandler.php b/src/Analyser/StmtHandler/TryCatchHandler.php index e0729fe11b9..b703a1e0015 100644 --- a/src/Analyser/StmtHandler/TryCatchHandler.php +++ b/src/Analyser/StmtHandler/TryCatchHandler.php @@ -6,9 +6,9 @@ use Exception; use PhpParser\Node; use PhpParser\Node\Expr; +use PhpParser\Node\Expr\Variable; use PhpParser\Node\Stmt; use PhpParser\Node\Stmt\TryCatch; -use PhpParser\Node\Expr\Variable; use PHPStan\Analyser\ConditionalExpressionHolder; use PHPStan\Analyser\ExpressionResultStorage; use PHPStan\Analyser\ExpressionTypeHolder; @@ -434,7 +434,7 @@ private function addCatchVariableDefinednessConditionals( $conditionalHolder = new ConditionalExpressionHolder($condition, $holder); $conditionalHolders[$conditionalHolder->getKey()] = $conditionalHolder; } - $mergedScope = $mergedScope->addConditionalExpressions((string) $exprString, $conditionalHolders); + $mergedScope = $mergedScope->addConditionalExpressions((string) $exprString, $conditionalHolders); // @phpstan-ignore cast.useless } return $mergedScope; From 46c4f29a573b2c08ceaefc5ccd4e6b46daadd760 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Sat, 5 Sep 2026 14:48:05 +0200 Subject: [PATCH 4/4] Remap conditional expressions through constant string concat-assigns `$var .= ''` used to invalidate every conditional-expression holder mentioning $var, so a format string built across `if (!empty($target))` lost its correlation with $target and a later `empty($target)` re-check could not select the matching string. Appending a fixed suffix is injective, so holders whose target or condition on $var is a single constant string are remapped through the append instead; everything else still falls back to invalidation. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01CGhnJQpUWRRpg6H5LuWJkA --- src/Analyser/ExprHandler/AssignHandler.php | 118 ++- tests/PHPStan/Analyser/nsrt/bug-9854.php | 22 + .../Functions/PrintfParametersRuleTest.php | 5 + .../PHPStan/Rules/Functions/data/bug-9854.php | 16 + turbo-ext/src/AssignHandler.cpp | 150 +++- turbo-ext/src/generated/AssignHandler.h | 817 +++++++++--------- 6 files changed, 723 insertions(+), 405 deletions(-) create mode 100644 tests/PHPStan/Analyser/nsrt/bug-9854.php create mode 100644 tests/PHPStan/Rules/Functions/data/bug-9854.php diff --git a/src/Analyser/ExprHandler/AssignHandler.php b/src/Analyser/ExprHandler/AssignHandler.php index 414ccb00700..61772c884dc 100644 --- a/src/Analyser/ExprHandler/AssignHandler.php +++ b/src/Analyser/ExprHandler/AssignHandler.php @@ -74,6 +74,7 @@ use PHPStan\Node\VariableAssignNode; use PHPStan\Node\VirtualNode; use PHPStan\Php\PhpVersion; +use PHPStan\Reflection\InitializerExprTypeResolver; use PHPStan\Rules\Properties\PropertyReflectionFinder; use PHPStan\ShouldNotHappenException; use PHPStan\TrinaryLogic; @@ -115,6 +116,7 @@ use function is_nan; use function is_string; use function spl_object_id; +use function str_contains; use const PHP_INT_MAX; /** @@ -166,6 +168,7 @@ public function __construct( private PropertyHookThrowPointsResolver $propertyHookThrowPointsResolver, private StatementsHandler $statementsHandler, private ArrayUnpackingHelper $arrayUnpackingHelper, + private InitializerExprTypeResolver $initializerExprTypeResolver, ) { } @@ -1404,7 +1407,23 @@ public function applyWrite( } $nodeScopeResolver->callNodeCallback($nodeCallback, new VariableAssignNode($var, $assignedExpr), $scopeBeforeAssignEval, $storage); - + $remappedConditionalExpressions = []; + if ( + // only the concat-assign's own write remaps - an enclosing plain + // assignment of the same variable (`$s = $s .= 'x'`) sees the + // already-remapped holders and would remap them a second time + $isAssignOp + && $assignedExpr instanceof AssignOp\Concat + && $assignedExpr->var instanceof Variable + && $assignedExpr->var->name === $var->name + && $scope->getConditionalExpressions() !== [] + ) { + $remappedConditionalExpressions = $this->remapConditionalExpressionsThroughConcatAssign( + $scope->getConditionalExpressions(), + '$' . $var->name, + $valueResult->getType(), + ); + } $nativeType = $this->readAssignedValueType($nodeScopeResolver, $storedAssignedExprResult, $assignedExpr, $scope->doNotTreatPhpDocTypesAsCertain()); $scope = $scope->assignVariable( $var->name, @@ -1413,6 +1432,9 @@ public function applyWrite( TrinaryLogic::createYes(), [], ); + foreach ($remappedConditionalExpressions as $exprString => $holders) { + $scope = $scope->addConditionalExpressions((string) $exprString, $holders); // @phpstan-ignore cast.useless + } foreach ($conditionalExpressions as $exprString => $holders) { $scope = $scope->addConditionalExpressions((string) $exprString, $holders); } @@ -2171,6 +2193,100 @@ private function processSureNotTypesForConditionalExpressionsAfterAssign(NodeSco return $conditionalExpressions; } + /** + * `$var .= ` keeps the conditional-expression + * holders about $var alive by remapping them through the append instead of + * losing them to the write's invalidation. A consequence type about $var is + * concatenated with the appended constant; a condition on $var is remapped + * only when it is itself a single constant string - appending a fixed + * suffix is injective, so the remapped condition selects exactly the states + * the original condition did. Holders mentioning $var inside a composite + * expression, with a non-Yes certainty about $var, or with a non-constant + * condition on $var are left to the regular invalidation. This keeps e.g. a + * format string built across `if (!empty($target))` correlated with + * $target while further pieces are appended. + * + * @param array $conditionalExpressions + * @return array + */ + private function remapConditionalExpressionsThroughConcatAssign( + array $conditionalExpressions, + string $varExprString, + Type $appendedType, + ): array + { + $appendedConstantStrings = $appendedType->getConstantStrings(); + if (count($appendedConstantStrings) !== 1 || !$appendedType->equals($appendedConstantStrings[0])) { + return []; + } + $appendedConstantString = $appendedConstantStrings[0]; + + $remapped = []; + foreach ($conditionalExpressions as $targetExprString => $holders) { + $targetExprString = (string) $targetExprString; // @phpstan-ignore cast.useless + $targetIsVar = $targetExprString === $varExprString; + if (!$targetIsVar && str_contains($targetExprString, $varExprString)) { + // a composite target containing the variable ($var[0], f($var), ...) + continue; + } + + foreach ($holders as $holder) { + $holderTouchesVar = $targetIsVar; + $remappable = true; + $newConditions = []; + foreach ($holder->getConditionExpressionTypeHolders() as $conditionExprString => $conditionHolder) { + $conditionExprString = (string) $conditionExprString; // @phpstan-ignore cast.useless + if ($conditionExprString === $varExprString) { + $holderTouchesVar = true; + $conditionConstantStrings = $conditionHolder->getType()->getConstantStrings(); + if ( + !$conditionHolder->getCertainty()->yes() + || count($conditionConstantStrings) !== 1 + || !$conditionHolder->getType()->equals($conditionConstantStrings[0]) + ) { + $remappable = false; + break; + } + $newConditions[$conditionExprString] = ExpressionTypeHolder::createYes( + $conditionHolder->getExpr(), + $conditionConstantStrings[0]->append($appendedConstantString), + ); + continue; + } + + if (str_contains($conditionExprString, $varExprString)) { + $remappable = false; + break; + } + + $newConditions[$conditionExprString] = $conditionHolder; + } + if (!$remappable || !$holderTouchesVar) { + continue; + } + + $typeHolder = $holder->getTypeHolder(); + if ($targetIsVar) { + if (!$typeHolder->getCertainty()->yes()) { + // the append leaves the variable defined on every path - + // an undefined/maybe consequence cannot be carried over + continue; + } + $concatType = $this->initializerExprTypeResolver->resolveConcatType($typeHolder->getType(), $appendedType); + if ($concatType instanceof ErrorType) { + continue; + } + $typeHolder = ExpressionTypeHolder::createYes($typeHolder->getExpr(), $concatType); + } + + $newHolder = new ConditionalExpressionHolder($newConditions, $typeHolder); + $remapped[$targetExprString][$newHolder->getKey()] = $newHolder; + } + } + + return $remapped; + } + /** * Records "if the assigned variable has $variableType, the target variable is * certainly defined (with its branch-scope type)" holders for variables whose diff --git a/tests/PHPStan/Analyser/nsrt/bug-9854.php b/tests/PHPStan/Analyser/nsrt/bug-9854.php new file mode 100644 index 00000000000..29e9fc65e5c --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-9854.php @@ -0,0 +1,22 @@ +%s'; + +if (empty($target)) { + assertType('\'%s\'', $htmlLinkStructure); + return sprintf($htmlLinkStructure, $url, $linkText); +} + +assertType('\'%s\'', $htmlLinkStructure); +return sprintf($htmlLinkStructure, $url, $target, $linkText); diff --git a/tests/PHPStan/Rules/Functions/PrintfParametersRuleTest.php b/tests/PHPStan/Rules/Functions/PrintfParametersRuleTest.php index f09b273cf9b..bc42cfee18f 100644 --- a/tests/PHPStan/Rules/Functions/PrintfParametersRuleTest.php +++ b/tests/PHPStan/Rules/Functions/PrintfParametersRuleTest.php @@ -194,4 +194,9 @@ public function testFormatParser(): void ]); } + public function testBug9854(): void + { + $this->analyse([__DIR__ . '/data/bug-9854.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Functions/data/bug-9854.php b/tests/PHPStan/Rules/Functions/data/bug-9854.php new file mode 100644 index 00000000000..1f1e308c505 --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/bug-9854.php @@ -0,0 +1,16 @@ +%s'; + +if (empty($target)) { + return sprintf($htmlLinkStructure, $url, $linkText); +} + +return sprintf($htmlLinkStructure, $url, $target, $linkText); diff --git a/turbo-ext/src/AssignHandler.cpp b/turbo-ext/src/AssignHandler.cpp index 6eb80018b4c..1b42c162645 100644 --- a/turbo-ext/src/AssignHandler.cpp +++ b/turbo-ext/src/AssignHandler.cpp @@ -1084,7 +1084,7 @@ class AssignHandler void construct(zval *argv) { zv::ObjRef object(self); - for (uint32_t i = 0; i < 20; i++) { + for (uint32_t i = 0; i < 21; i++) { object.propAtWrite(i, zv::Val::copyOf(zv::Ref(&argv[i]))); } } @@ -2159,10 +2159,35 @@ class AssignHandler AH_VALB(assignNode, newVariableAssignNode(var, assignedExpr.raw())); AH_OKB(nsrCallNodeCallback(nsr, nodeCallback, assignNode.raw(), scopeBeforeAssignEval.raw(), storage)); } + zv::Val remappedConditionalExpressions = ahEmptyArray(); + // only the concat-assign's own write remaps - an enclosing plain + // assignment of the same variable (`$s = $s .= 'x'`) sees the + // already-remapped holders and would remap them a second time + if (Z_TYPE_P(AH_TARGET(target, isAssignOp)) == IS_TRUE && ahIs(assignedExpr.raw(), PT_CLASS_ASSIGN_OP_CONCAT)) { + zend_string *concatVarName = ahStringVariableName(AH_PROP(assignedExpr.raw(), var)); + if (concatVarName != NULL && zend_string_equals(concatVarName, varName)) { + AH_VALB(scopeConditionalExpressions, pt_mutating_scope_get_conditional_expressions(Z_OBJ_P(scope.raw()))); + if (Z_TYPE_P(scopeConditionalExpressions.raw()) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(scopeConditionalExpressions.raw())) > 0) { + AH_VALB(appendedType, pt_expression_result_get_type(valueResult)); + zv::Str varExprString = zv::Str::adopt(zend_string_concat2(PT_LC("$"), ZSTR_VAL(varName), ZSTR_LEN(varName))); + AH_SETB(remappedConditionalExpressions, remapConditionalExpressionsThroughConcatAssign(scopeConditionalExpressions.raw(), varExprString.get(), appendedType.raw())); + } + } + } AH_VALB(nativeScope, pt_mutating_scope_do_not_treat_phpdoc_types_as_certain(Z_OBJ_P(scope.raw()))); AH_VALB(nativeType, readAssignedValueType(nsr, stored, assignedExpr.raw(), nativeScope.raw())); AH_SETB(scope, pt_mutating_scope_assign_variable(Z_OBJ_P(scope.raw()), varName, type.raw(), nativeType.raw(), ahTrinary(PT_TRI_YES))); + for (auto entry : zv::TableRef(Z_ARRVAL_P(remappedConditionalExpressions.raw()))) { + zval *holders = entry.value().raw(); + zend_string *exprString = entry.stringKeyOrNull(); + if (exprString != NULL) { + AH_SETB(scope, pt_mutating_scope_add_conditional_expressions(Z_OBJ_P(scope.raw()), exprString, Z_ARRVAL_P(holders))); + } else { + zv::Str key = zv::Str::adopt(zend_long_to_str((zend_long) entry.indexKey())); + AH_SETB(scope, pt_mutating_scope_add_conditional_expressions(Z_OBJ_P(scope.raw()), key.get(), Z_ARRVAL_P(holders))); + } + } for (auto entry : zv::TableRef(Z_ARRVAL_P(conditionalExpressions.raw()))) { zval *holders = entry.value().raw(); zend_string *exprString = entry.stringKeyOrNull(); @@ -2485,6 +2510,127 @@ class AssignHandler return true; } + static bool strContains(zend_string *haystack, zend_string *needle) + { + return zend_memnstr(ZSTR_VAL(haystack), ZSTR_VAL(needle), ZSTR_LEN(needle), ZSTR_VAL(haystack) + ZSTR_LEN(haystack)) != NULL; + } + + /* the single constant string a type is exactly (count(getConstantStrings()) + * === 1 and equals() it), UNDEF = pending exception, PHP null = none */ + static zv::Val singleConstantString(zval *type) + { + AH_VAL(constantStrings, ahCall(type, PT_LC("getconstantstrings"), 0, NULL)); + if (Z_TYPE_P(constantStrings.raw()) != IS_ARRAY || zend_hash_num_elements(Z_ARRVAL_P(constantStrings.raw())) != 1) return zv::Val::null(); + zval *constantString = zend_hash_index_find(Z_ARRVAL_P(constantStrings.raw()), 0); + if (UNEXPECTED(constantString == NULL)) { + pt_throw_should_not_happen(); + return zv::Val(); + } + ZVAL_DEREF(constantString); + bool equal; + AH_OK(ahEquals(type, constantString, equal)); + if (!equal) return zv::Val::null(); + return zv::Val::copyOf(zv::Ref(constantString)); + } + + /* $holder->getConditionExpressionTypeHolders() / ->getTypeHolder() of a ConditionalExpressionHolder */ + static zv::Val conditionalHolderPart(zval *holder, bool conditions) + { + if (EXPECTED(Z_TYPE_P(holder) == IS_OBJECT && Z_OBJCE_P(holder) == pt_ce_cond_expr_holder)) { + return zv::Val::copyOf(zv::ObjRef(Z_OBJ_P(holder)).propAt(conditions ? PT_CEH_PROP_CONDS : PT_CEH_PROP_TYPEHOLDER).deref()); + } + return conditions ? ahCall(holder, PT_LC("getconditionexpressiontypeholders"), 0, NULL) : ahCall(holder, PT_LC("gettypeholder"), 0, NULL); + } + + /* (twin remapConditionalExpressionsThroughConcatAssign) `$var .= ` keeps the conditional-expression holders about $var + * alive by remapping them through the append instead of losing them to + * the write's invalidation; see the PHP twin for the rules. */ + zv::Val remapConditionalExpressionsThroughConcatAssign(zval *conditionalExpressions, zend_string *varExprString, zval *appendedType) + { + AH_VAL(appendedConstantString, singleConstantString(appendedType)); + if (appendedConstantString.isNull()) return ahEmptyArray(); + + zv::Val remapped = ahEmptyArray(); + for (auto targetEntry : zv::TableRef(Z_ARRVAL_P(conditionalExpressions))) { + zv::Str targetExprString = targetEntry.stringKeyOrNull() != NULL ? zv::Str::copyOf(targetEntry.stringKey()) : zv::Str::adopt(zend_long_to_str((zend_long) targetEntry.indexKey())); + bool targetIsVar = zend_string_equals(targetExprString.get(), varExprString); + if (!targetIsVar && strContains(targetExprString.get(), varExprString)) { + // a composite target containing the variable ($var[0], f($var), ...) + continue; + } + + zval *holders = targetEntry.value().deref().raw(); + if (UNEXPECTED(Z_TYPE_P(holders) != IS_ARRAY)) continue; + for (auto holderEntry : zv::TableRef(Z_ARRVAL_P(holders))) { + zval *holder = holderEntry.value().deref().raw(); + bool holderTouchesVar = targetIsVar; + bool remappable = true; + zv::Val newConditions = ahEmptyArray(); + AH_VAL(conditions, conditionalHolderPart(holder, true)); + if (UNEXPECTED(Z_TYPE_P(conditions.raw()) != IS_ARRAY)) continue; + for (auto conditionEntry : zv::TableRef(Z_ARRVAL_P(conditions.raw()))) { + zv::Str conditionExprString = conditionEntry.stringKeyOrNull() != NULL ? zv::Str::copyOf(conditionEntry.stringKey()) : zv::Str::adopt(zend_long_to_str((zend_long) conditionEntry.indexKey())); + zval *conditionHolder = conditionEntry.value().deref().raw(); + if (zend_string_equals(conditionExprString.get(), varExprString)) { + holderTouchesVar = true; + if (pt_holder_certainty_value(Z_OBJ_P(conditionHolder)) != PT_TRI_YES) { + remappable = false; + break; + } + zval *conditionType = OBJ_PROP_NUM(Z_OBJ_P(conditionHolder), PT_ETH_PROP_TYPE); + ZVAL_DEREF(conditionType); + AH_VAL(conditionConstantString, singleConstantString(conditionType)); + if (conditionConstantString.isNull()) { + remappable = false; + break; + } + zval appendArg; + ZVAL_COPY_VALUE(&appendArg, appendedConstantString.raw()); + AH_VAL(appended, ahCall(conditionConstantString.raw(), PT_LC("append"), 1, &appendArg)); + zval *conditionExpr = OBJ_PROP_NUM(Z_OBJ_P(conditionHolder), PT_ETH_PROP_EXPR); + ZVAL_DEREF(conditionExpr); + AH_VAL(newConditionHolder, newExpressionTypeHolder(conditionExpr, appended.raw(), PT_TRI_YES)); + ahSetKey(newConditions, conditionExprString.get(), newConditionHolder.raw()); + continue; + } + + if (strContains(conditionExprString.get(), varExprString)) { + remappable = false; + break; + } + + ahSetKey(newConditions, conditionExprString.get(), conditionHolder); + } + if (!remappable || !holderTouchesVar) continue; + + AH_VAL(typeHolder, conditionalHolderPart(holder, false)); + if (targetIsVar) { + if (pt_holder_certainty_value(Z_OBJ_P(typeHolder.raw())) != PT_TRI_YES) { + // the append leaves the variable defined on every path - + // an undefined/maybe consequence cannot be carried over + continue; + } + zval *holderType = OBJ_PROP_NUM(Z_OBJ_P(typeHolder.raw()), PT_ETH_PROP_TYPE); + ZVAL_DEREF(holderType); + zv::Args concatArgs{holderType, appendedType}; + AH_VAL(concatType, ahCall(prop(slots::initializerExprTypeResolver), PT_LC("resolveconcattype"), 2, concatArgs)); + if (Z_TYPE_P(concatType.raw()) == IS_OBJECT && instanceof_function(Z_OBJCE_P(concatType.raw()), pt_ce_error_type)) continue; + zval *holderExpr = OBJ_PROP_NUM(Z_OBJ_P(typeHolder.raw()), PT_ETH_PROP_EXPR); + ZVAL_DEREF(holderExpr); + AH_SET(typeHolder, newExpressionTypeHolder(holderExpr, concatType.raw(), PT_TRI_YES)); + } + + AH_VAL(newHolder, newConditionalExpressionHolder(newConditions.raw(), typeHolder.raw())); + zv::Str newHolderKey = zv::Str::adopt(conditionalHolderKey(newHolder.raw())); + AH_OK(!newHolderKey.isNull()); + nestedSet(remapped, targetExprString.get(), newHolderKey.get(), newHolder.raw()); + } + } + + return remapped; + } + /* Records "if the assigned variable has $variableType, the target variable is * certainly defined (with its branch-scope type)" holders for variables whose * certainty is Yes in the given branch continuation scope of the RHS (the @@ -4960,7 +5106,7 @@ PT_MINIT_REGISTRATION(pt_register_assign_handler) cls.method(sigs::__construct, [](INTERNAL_FUNCTION_PARAMETERS) { zval *argv; uint32_t argc; - ZEND_PARSE_PARAMETERS_START(20, 20) + ZEND_PARSE_PARAMETERS_START(21, 21) Z_PARAM_VARIADIC('+', argv, argc) ZEND_PARSE_PARAMETERS_END(); for (uint32_t i = 0; i < argc; i++) { diff --git a/turbo-ext/src/generated/AssignHandler.h b/turbo-ext/src/generated/AssignHandler.h index d5809786a69..4171fa1edfe 100644 --- a/turbo-ext/src/generated/AssignHandler.h +++ b/turbo-ext/src/generated/AssignHandler.h @@ -30,6 +30,7 @@ inline constexpr uint32_t methodThrowPointHelper = 16; inline constexpr uint32_t propertyHookThrowPointsResolver = 17; inline constexpr uint32_t statementsHandler = 18; inline constexpr uint32_t arrayUnpackingHelper = 19; +inline constexpr uint32_t initializerExprTypeResolver = 20; } // namespace slot inline void declareClass(reg::Class &cls) @@ -61,6 +62,7 @@ inline void declareProperties(reg::Class &cls) cls.property("propertyHookThrowPointsResolver", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\Analyser\\PropertyHookThrowPointsResolver"); cls.property("statementsHandler", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\Analyser\\StatementsHandler"); cls.property("arrayUnpackingHelper", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\Type\\ArrayUnpackingHelper"); + cls.property("initializerExprTypeResolver", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\Reflection\\InitializerExprTypeResolver"); } /* the string and parameter tables the signatures below index into (see reg::Sig) */ @@ -106,134 +108,139 @@ inline constexpr char strings[] = "PHPStan\\Analyser\\StatementsHandler\0" /* 1269 */ "arrayUnpackingHelper\0" /* 1304 */ "PHPStan\\Type\\ArrayUnpackingHelper\0" /* 1325 */ - "__construct\0" /* 1359 */ - "expr\0" /* 1371 */ - "PhpParser\\Node\\Expr\0" /* 1376 */ - "\0" /* 1396 */ - "supports\0" /* 1397 */ - "nodeScopeResolver\0" /* 1406 */ - "PHPStan\\Analyser\\NodeScopeResolver\0" /* 1424 */ - "stmt\0" /* 1459 */ - "PhpParser\\Node\\Stmt\0" /* 1464 */ - "scope\0" /* 1484 */ - "PHPStan\\Analyser\\MutatingScope\0" /* 1490 */ - "storage\0" /* 1521 */ - "PHPStan\\Analyser\\ExpressionResultStorage\0" /* 1529 */ - "nodeCallback\0" /* 1570 */ - "context\0" /* 1583 */ - "PHPStan\\Analyser\\ExpressionContext\0" /* 1591 */ - "PHPStan\\Analyser\\ExpressionResult\0" /* 1626 */ - "processExpr\0" /* 1660 */ - "assignedExpr\0" /* 1672 */ - "captureAssignedCallArgResults\0" /* 1685 */ - "PhpParser\\Node\\Expr\\Assign\0" /* 1715 */ - "assignedExprResult\0" /* 1742 */ - "beforeScope\0" /* 1761 */ - "Closure\0" /* 1773 */ - "createCreateTypesCallback\0" /* 1781 */ - "createSpecifyTypesCallback\0" /* 1807 */ - "var\0" /* 1834 */ - "null\0" /* 1838 */ - "processVirtualAssign\0" /* 1843 */ - "mode\0" /* 1864 */ - "PHPStan\\Analyser\\AssignTargetWalkMode\0" /* 1869 */ - "PHPStan\\Analyser\\PreparedAssignTarget\0" /* 1907 */ - "prepareTarget\0" /* 1945 */ - "doPrepareTarget\0" /* 1959 */ - "target\0" /* 1975 */ - "valueResult\0" /* 1982 */ - "assignedValueResult\0" /* 1994 */ - "applyWrite\0" /* 2014 */ - "receiverType\0" /* 2025 */ - "PHPStan\\Type\\Type\0" /* 2038 */ - "keyType\0" /* 2056 */ - "valueType\0" /* 2064 */ - "PHPStan\\Analyser\\Generics\\TemplateArgumentConstraints\0" /* 2074 */ - "collectOffsetSetUsage\0" /* 2128 */ - "keyVar\0" /* 2150 */ - "PhpParser\\Node\\Expr\\Variable\0" /* 2157 */ - "arrayArg\0" /* 2186 */ - "narrowedKeyType\0" /* 2195 */ - "dimFetchType\0" /* 2211 */ - "PHPStan\\Analyser\\SpecifiedTypes\0" /* 2224 */ - "createArrayDimFetchConditionalExpressionHolder\0" /* 2256 */ - "readAssignedValueType\0" /* 2303 */ - "varResult\0" /* 2325 */ - "postEvalScope\0" /* 2335 */ - "preEvalScope\0" /* 2349 */ - "resolveContainerTypesAfterAssignedExprEval\0" /* 2362 */ - "nameResult\0" /* 2405 */ - "nativeValueType\0" /* 2416 */ - "assignDynamicVariable\0" /* 2432 */ - "unwrapAssign\0" /* 2454 */ - "variableName\0" /* 2467 */ - "conditionalExpressions\0" /* 2480 */ - "specifiedTypes\0" /* 2503 */ - "variableType\0" /* 2518 */ - "rhsImpurePoints\0" /* 2531 */ - "processSureTypesForConditionalExpressionsAfterAssign\0" /* 2547 */ - "processSureNotTypesForConditionalExpressionsAfterAssign\0" /* 2600 */ - "branchScope\0" /* 2656 */ - "mergedScope\0" /* 2668 */ - "processDefinednessForConditionalExpressionsAfterAssign\0" /* 2680 */ - "node\0" /* 2735 */ - "PhpParser\\Node\0" /* 2740 */ - "containsVariableAssignment\0" /* 2755 */ - "currentTypeForConditionalHolder\0" /* 2782 */ - "armScope\0" /* 2814 */ - "armExpr\0" /* 2823 */ - "remainderType\0" /* 2831 */ - "otherArmType\0" /* 2845 */ - "processTernaryArmValueImpliedTypesAfterAssign\0" /* 2858 */ - "holderExpr\0" /* 2904 */ - "holderExprString\0" /* 2915 */ - "holderType\0" /* 2932 */ - "holderCertainty\0" /* 2943 */ - "PHPStan\\TrinaryLogic\0" /* 2959 */ - "addConditionalExpressionHolder\0" /* 2980 */ - "newConditionalExpressions\0" /* 3011 */ - "mergeConditionalExpressions\0" /* 3037 */ - "PhpParser\\Node\\Expr\\Match_\0" /* 3065 */ - "processMatchForConditionalExpressionsAfterAssign\0" /* 3092 */ - "assignedType\0" /* 3141 */ - "processDerivedConditionalExpressionsAfterAssign\0" /* 3154 */ - "PhpParser\\Node\\Expr\\FuncCall\0" /* 3202 */ - "processInArrayForConditionalExpressionsAfterAssign\0" /* 3231 */ - "isExprSafeToProjectThroughVariable\0" /* 3282 */ - "dimFetchStack\0" /* 3317 */ - "PHPStan\\Analyser\\Scope\0" /* 3331 */ - "isImplicitArrayCreation\0" /* 3354 */ - "rootVarName\0" /* 3378 */ - "arrayExpr\0" /* 3390 */ - "PhpParser\\Node\\Expr\\Array_\0" /* 3400 */ - "parentExpr\0" /* 3427 */ - "processArrayByRefItems\0" /* 3438 */ - "implicitIndex\0" /* 3461 */ - "processArrayByRefItemsWithImplicitIndex\0" /* 3475 */ - "isFlattenableUnpackedArray\0" /* 3515 */ - "index\0" /* 3542 */ - "advanceImplicitIndex\0" /* 3548 */ - "offsetTypes\0" /* 3569 */ - "offsetValueType\0" /* 3581 */ - "valueToWrite\0" /* 3597 */ - "produceArrayDimFetchAssignValueToWrite\0" /* 3610 */ - "arrayDimFetch\0" /* 3649 */ - "PhpParser\\Node\\Expr\\ArrayDimFetch\0" /* 3663 */ - "shouldKeepList\0" /* 3697 */ - "offsetType\0" /* 3712 */ - "trackedLinkImpliesOffset\0" /* 3723 */ - "a\0" /* 3748 */ - "b\0" /* 3750 */ - "isSameVariable\0" /* 3752 */ - "isSameOffset\0" /* 3767 */ - "getLiteralArrayKeyType\0" /* 3780 */ - "propertyFetch\0" /* 3803 */ - "PhpParser\\Node\\Expr\\PropertyFetch|PhpParser\\Node\\Expr\\StaticPropertyFetch\0" /* 3817 */ - "getOriginalPropertyType\0" /* 3891 */ - "array\0" /* 3915 */ - "hasArrayReference\0" /* 3921 */ - "rhs\0" /* 3939 */ - "redundant"; /* 3943 */ + "initializerExprTypeResolver\0" /* 1359 */ + "PHPStan\\Reflection\\InitializerExprTypeResolver\0" /* 1387 */ + "__construct\0" /* 1434 */ + "expr\0" /* 1446 */ + "PhpParser\\Node\\Expr\0" /* 1451 */ + "\0" /* 1471 */ + "supports\0" /* 1472 */ + "nodeScopeResolver\0" /* 1481 */ + "PHPStan\\Analyser\\NodeScopeResolver\0" /* 1499 */ + "stmt\0" /* 1534 */ + "PhpParser\\Node\\Stmt\0" /* 1539 */ + "scope\0" /* 1559 */ + "PHPStan\\Analyser\\MutatingScope\0" /* 1565 */ + "storage\0" /* 1596 */ + "PHPStan\\Analyser\\ExpressionResultStorage\0" /* 1604 */ + "nodeCallback\0" /* 1645 */ + "context\0" /* 1658 */ + "PHPStan\\Analyser\\ExpressionContext\0" /* 1666 */ + "PHPStan\\Analyser\\ExpressionResult\0" /* 1701 */ + "processExpr\0" /* 1735 */ + "assignedExpr\0" /* 1747 */ + "captureAssignedCallArgResults\0" /* 1760 */ + "PhpParser\\Node\\Expr\\Assign\0" /* 1790 */ + "assignedExprResult\0" /* 1817 */ + "beforeScope\0" /* 1836 */ + "Closure\0" /* 1848 */ + "createCreateTypesCallback\0" /* 1856 */ + "createSpecifyTypesCallback\0" /* 1882 */ + "var\0" /* 1909 */ + "null\0" /* 1913 */ + "processVirtualAssign\0" /* 1918 */ + "mode\0" /* 1939 */ + "PHPStan\\Analyser\\AssignTargetWalkMode\0" /* 1944 */ + "PHPStan\\Analyser\\PreparedAssignTarget\0" /* 1982 */ + "prepareTarget\0" /* 2020 */ + "doPrepareTarget\0" /* 2034 */ + "target\0" /* 2050 */ + "valueResult\0" /* 2057 */ + "assignedValueResult\0" /* 2069 */ + "applyWrite\0" /* 2089 */ + "receiverType\0" /* 2100 */ + "PHPStan\\Type\\Type\0" /* 2113 */ + "keyType\0" /* 2131 */ + "valueType\0" /* 2139 */ + "PHPStan\\Analyser\\Generics\\TemplateArgumentConstraints\0" /* 2149 */ + "collectOffsetSetUsage\0" /* 2203 */ + "keyVar\0" /* 2225 */ + "PhpParser\\Node\\Expr\\Variable\0" /* 2232 */ + "arrayArg\0" /* 2261 */ + "narrowedKeyType\0" /* 2270 */ + "dimFetchType\0" /* 2286 */ + "PHPStan\\Analyser\\SpecifiedTypes\0" /* 2299 */ + "createArrayDimFetchConditionalExpressionHolder\0" /* 2331 */ + "readAssignedValueType\0" /* 2378 */ + "varResult\0" /* 2400 */ + "postEvalScope\0" /* 2410 */ + "preEvalScope\0" /* 2424 */ + "resolveContainerTypesAfterAssignedExprEval\0" /* 2437 */ + "nameResult\0" /* 2480 */ + "nativeValueType\0" /* 2491 */ + "assignDynamicVariable\0" /* 2507 */ + "unwrapAssign\0" /* 2529 */ + "variableName\0" /* 2542 */ + "conditionalExpressions\0" /* 2555 */ + "specifiedTypes\0" /* 2578 */ + "variableType\0" /* 2593 */ + "rhsImpurePoints\0" /* 2606 */ + "processSureTypesForConditionalExpressionsAfterAssign\0" /* 2622 */ + "processSureNotTypesForConditionalExpressionsAfterAssign\0" /* 2675 */ + "varExprString\0" /* 2731 */ + "appendedType\0" /* 2745 */ + "remapConditionalExpressionsThroughConcatAssign\0" /* 2758 */ + "branchScope\0" /* 2805 */ + "mergedScope\0" /* 2817 */ + "processDefinednessForConditionalExpressionsAfterAssign\0" /* 2829 */ + "node\0" /* 2884 */ + "PhpParser\\Node\0" /* 2889 */ + "containsVariableAssignment\0" /* 2904 */ + "currentTypeForConditionalHolder\0" /* 2931 */ + "armScope\0" /* 2963 */ + "armExpr\0" /* 2972 */ + "remainderType\0" /* 2980 */ + "otherArmType\0" /* 2994 */ + "processTernaryArmValueImpliedTypesAfterAssign\0" /* 3007 */ + "holderExpr\0" /* 3053 */ + "holderExprString\0" /* 3064 */ + "holderType\0" /* 3081 */ + "holderCertainty\0" /* 3092 */ + "PHPStan\\TrinaryLogic\0" /* 3108 */ + "addConditionalExpressionHolder\0" /* 3129 */ + "newConditionalExpressions\0" /* 3160 */ + "mergeConditionalExpressions\0" /* 3186 */ + "PhpParser\\Node\\Expr\\Match_\0" /* 3214 */ + "processMatchForConditionalExpressionsAfterAssign\0" /* 3241 */ + "assignedType\0" /* 3290 */ + "processDerivedConditionalExpressionsAfterAssign\0" /* 3303 */ + "PhpParser\\Node\\Expr\\FuncCall\0" /* 3351 */ + "processInArrayForConditionalExpressionsAfterAssign\0" /* 3380 */ + "isExprSafeToProjectThroughVariable\0" /* 3431 */ + "dimFetchStack\0" /* 3466 */ + "PHPStan\\Analyser\\Scope\0" /* 3480 */ + "isImplicitArrayCreation\0" /* 3503 */ + "rootVarName\0" /* 3527 */ + "arrayExpr\0" /* 3539 */ + "PhpParser\\Node\\Expr\\Array_\0" /* 3549 */ + "parentExpr\0" /* 3576 */ + "processArrayByRefItems\0" /* 3587 */ + "implicitIndex\0" /* 3610 */ + "processArrayByRefItemsWithImplicitIndex\0" /* 3624 */ + "isFlattenableUnpackedArray\0" /* 3664 */ + "index\0" /* 3691 */ + "advanceImplicitIndex\0" /* 3697 */ + "offsetTypes\0" /* 3718 */ + "offsetValueType\0" /* 3730 */ + "valueToWrite\0" /* 3746 */ + "produceArrayDimFetchAssignValueToWrite\0" /* 3759 */ + "arrayDimFetch\0" /* 3798 */ + "PhpParser\\Node\\Expr\\ArrayDimFetch\0" /* 3812 */ + "shouldKeepList\0" /* 3846 */ + "offsetType\0" /* 3861 */ + "trackedLinkImpliesOffset\0" /* 3872 */ + "a\0" /* 3897 */ + "b\0" /* 3899 */ + "isSameVariable\0" /* 3901 */ + "isSameOffset\0" /* 3916 */ + "getLiteralArrayKeyType\0" /* 3929 */ + "propertyFetch\0" /* 3952 */ + "PhpParser\\Node\\Expr\\PropertyFetch|PhpParser\\Node\\Expr\\StaticPropertyFetch\0" /* 3966 */ + "getOriginalPropertyType\0" /* 4040 */ + "array\0" /* 4064 */ + "hasArrayReference\0" /* 4070 */ + "rhs\0" /* 4088 */ + "redundant"; /* 4092 */ inline constexpr reg::PackedArg args[] = { reg::packed(0, 0, 25), /* __construct $templateArgumentObserver */ reg::packed(76, 0, 99), /* __construct $varAnnotationProcessor */ @@ -255,286 +262,292 @@ inline constexpr reg::PackedArg args[] = { reg::packed(1170, 0, 1202), /* __construct $propertyHookThrowPointsResolver */ reg::packed(1251, 0, 1269), /* __construct $statementsHandler */ reg::packed(1304, 0, 1325), /* __construct $arrayUnpackingHelper */ - reg::packed(1371, 0, 1376), /* supports $expr */ - reg::packed(1396, MAY_BE_BOOL), /* supports return */ - reg::packed(1406, 0, 1424), /* processExpr $nodeScopeResolver */ - reg::packed(1459, 0, 1464), /* processExpr $stmt */ - reg::packed(1371, 0, 1376), /* processExpr $expr */ - reg::packed(1484, 0, 1490), /* processExpr $scope */ - reg::packed(1521, 0, 1529), /* processExpr $storage */ - reg::packed(1570, MAY_BE_CALLABLE), /* processExpr $nodeCallback */ - reg::packed(1583, 0, 1591), /* processExpr $context */ - reg::packed(1396, 0, 1626), /* processExpr return */ - reg::packed(1672, 0, 1376), /* captureAssignedCallArgResults $assignedExpr */ - reg::packed(1521, 0, 1529), /* captureAssignedCallArgResults $storage */ - reg::packed(1396, MAY_BE_ARRAY), /* captureAssignedCallArgResults return */ - reg::packed(1371, 0, 1715), /* createCreateTypesCallback $expr */ - reg::packed(1742, 0, 1626), /* createCreateTypesCallback $assignedExprResult */ - reg::packed(1761, 0, 1490), /* createCreateTypesCallback $beforeScope */ - reg::packed(1396, 0, 1773), /* createCreateTypesCallback return */ - reg::packed(1371, 0, 1715), /* createSpecifyTypesCallback $expr */ - reg::packed(1742, 0, 1626), /* createSpecifyTypesCallback $assignedExprResult */ - reg::packed(1761, 0, 1490), /* createSpecifyTypesCallback $beforeScope */ - reg::packed(1521, 0, 1529), /* createSpecifyTypesCallback $storage */ - reg::packed(1396, 0, 1773), /* createSpecifyTypesCallback return */ - reg::packed(1406, 0, 1424), /* processVirtualAssign $nodeScopeResolver */ - reg::packed(1484, 0, 1490), /* processVirtualAssign $scope */ - reg::packed(1521, 0, 1529), /* processVirtualAssign $storage */ - reg::packed(1459, 0, 1464), /* processVirtualAssign $stmt */ - reg::packed(1834, 0, 1376), /* processVirtualAssign $var */ - reg::packed(1672, 0, 1376), /* processVirtualAssign $assignedExpr */ - reg::packed(1570, MAY_BE_CALLABLE), /* processVirtualAssign $nodeCallback */ - reg::packed(1742, MAY_BE_NULL, 1626, false, false, 1838), /* processVirtualAssign $assignedExprResult */ - reg::packed(1396, 0, 1626), /* processVirtualAssign return */ - reg::packed(1406, 0, 1424), /* prepareTarget $nodeScopeResolver */ - reg::packed(1484, 0, 1490), /* prepareTarget $scope */ - reg::packed(1521, 0, 1529), /* prepareTarget $storage */ - reg::packed(1459, 0, 1464), /* prepareTarget $stmt */ - reg::packed(1834, 0, 1376), /* prepareTarget $var */ - reg::packed(1672, 0, 1376), /* prepareTarget $assignedExpr */ - reg::packed(1570, MAY_BE_CALLABLE), /* prepareTarget $nodeCallback */ - reg::packed(1583, 0, 1591), /* prepareTarget $context */ - reg::packed(1864, 0, 1869), /* prepareTarget $mode */ - reg::packed(1396, 0, 1907), /* prepareTarget return */ - reg::packed(1406, 0, 1424), /* doPrepareTarget $nodeScopeResolver */ - reg::packed(1484, 0, 1490), /* doPrepareTarget $scope */ - reg::packed(1521, 0, 1529), /* doPrepareTarget $storage */ - reg::packed(1459, 0, 1464), /* doPrepareTarget $stmt */ - reg::packed(1834, 0, 1376), /* doPrepareTarget $var */ - reg::packed(1672, 0, 1376), /* doPrepareTarget $assignedExpr */ - reg::packed(1570, MAY_BE_CALLABLE), /* doPrepareTarget $nodeCallback */ - reg::packed(1583, 0, 1591), /* doPrepareTarget $context */ - reg::packed(1864, 0, 1869), /* doPrepareTarget $mode */ - reg::packed(1396, 0, 1907), /* doPrepareTarget return */ - reg::packed(1406, 0, 1424), /* applyWrite $nodeScopeResolver */ - reg::packed(1975, 0, 1907), /* applyWrite $target */ - reg::packed(1982, 0, 1626), /* applyWrite $valueResult */ - reg::packed(1994, MAY_BE_NULL, 1626), /* applyWrite $assignedValueResult */ - reg::packed(1459, 0, 1464), /* applyWrite $stmt */ - reg::packed(1521, 0, 1529), /* applyWrite $storage */ - reg::packed(1570, MAY_BE_CALLABLE), /* applyWrite $nodeCallback */ - reg::packed(1583, 0, 1591), /* applyWrite $context */ - reg::packed(1396, 0, 1626), /* applyWrite return */ - reg::packed(1406, 0, 1424), /* collectOffsetSetUsage $nodeScopeResolver */ - reg::packed(1484, 0, 1490), /* collectOffsetSetUsage $scope */ - reg::packed(2025, 0, 2038), /* collectOffsetSetUsage $receiverType */ - reg::packed(2056, MAY_BE_NULL, 2038), /* collectOffsetSetUsage $keyType */ - reg::packed(2064, 0, 2038), /* collectOffsetSetUsage $valueType */ - reg::packed(1396, 0, 2074), /* collectOffsetSetUsage return */ - reg::packed(2150, 0, 2157), /* createArrayDimFetchConditionalExpressionHolder $keyVar */ - reg::packed(2186, 0, 1376), /* createArrayDimFetchConditionalExpressionHolder $arrayArg */ - reg::packed(2195, 0, 2038), /* createArrayDimFetchConditionalExpressionHolder $narrowedKeyType */ - reg::packed(2211, 0, 2038), /* createArrayDimFetchConditionalExpressionHolder $dimFetchType */ - reg::packed(1396, 0, 2224), /* createArrayDimFetchConditionalExpressionHolder return */ - reg::packed(1406, 0, 1424), /* readAssignedValueType $nodeScopeResolver */ - reg::packed(1994, MAY_BE_NULL, 1626), /* readAssignedValueType $assignedValueResult */ - reg::packed(1672, 0, 1376), /* readAssignedValueType $assignedExpr */ - reg::packed(1484, 0, 1490), /* readAssignedValueType $scope */ - reg::packed(1396, 0, 2038), /* readAssignedValueType return */ - reg::packed(1406, 0, 1424), /* resolveContainerTypesAfterAssignedExprEval $nodeScopeResolver */ - reg::packed(1834, 0, 1376), /* resolveContainerTypesAfterAssignedExprEval $var */ - reg::packed(2325, 0, 1626), /* resolveContainerTypesAfterAssignedExprEval $varResult */ - reg::packed(2335, 0, 1490), /* resolveContainerTypesAfterAssignedExprEval $postEvalScope */ - reg::packed(2349, MAY_BE_NULL, 1490), /* resolveContainerTypesAfterAssignedExprEval $preEvalScope */ - reg::packed(1521, 0, 1529), /* resolveContainerTypesAfterAssignedExprEval $storage */ - reg::packed(1396, MAY_BE_ARRAY), /* resolveContainerTypesAfterAssignedExprEval return */ - reg::packed(1484, 0, 1490), /* assignDynamicVariable $scope */ - reg::packed(2405, 0, 1626), /* assignDynamicVariable $nameResult */ - reg::packed(2064, 0, 2038), /* assignDynamicVariable $valueType */ - reg::packed(2416, 0, 2038), /* assignDynamicVariable $nativeValueType */ - reg::packed(1396, 0, 1490), /* assignDynamicVariable return */ - reg::packed(1371, 0, 1376), /* unwrapAssign $expr */ - reg::packed(1396, 0, 1376), /* unwrapAssign return */ - reg::packed(1406, 0, 1424), /* processSureTypesForConditionalExpressionsAfterAssign $nodeScopeResolver */ - reg::packed(1484, 0, 1490), /* processSureTypesForConditionalExpressionsAfterAssign $scope */ - reg::packed(1521, 0, 1529), /* processSureTypesForConditionalExpressionsAfterAssign $storage */ - reg::packed(2467, MAY_BE_STRING), /* processSureTypesForConditionalExpressionsAfterAssign $variableName */ - reg::packed(2480, MAY_BE_ARRAY), /* processSureTypesForConditionalExpressionsAfterAssign $conditionalExpressions */ - reg::packed(2503, 0, 2224), /* processSureTypesForConditionalExpressionsAfterAssign $specifiedTypes */ - reg::packed(2518, 0, 2038), /* processSureTypesForConditionalExpressionsAfterAssign $variableType */ - reg::packed(2531, MAY_BE_ARRAY), /* processSureTypesForConditionalExpressionsAfterAssign $rhsImpurePoints */ - reg::packed(1672, 0, 1376), /* processSureTypesForConditionalExpressionsAfterAssign $assignedExpr */ - reg::packed(1994, MAY_BE_NULL, 1626), /* processSureTypesForConditionalExpressionsAfterAssign $assignedValueResult */ - reg::packed(1396, MAY_BE_ARRAY), /* processSureTypesForConditionalExpressionsAfterAssign return */ - reg::packed(1406, 0, 1424), /* processSureNotTypesForConditionalExpressionsAfterAssign $nodeScopeResolver */ - reg::packed(1484, 0, 1490), /* processSureNotTypesForConditionalExpressionsAfterAssign $scope */ - reg::packed(1521, 0, 1529), /* processSureNotTypesForConditionalExpressionsAfterAssign $storage */ - reg::packed(2467, MAY_BE_STRING), /* processSureNotTypesForConditionalExpressionsAfterAssign $variableName */ - reg::packed(2480, MAY_BE_ARRAY), /* processSureNotTypesForConditionalExpressionsAfterAssign $conditionalExpressions */ - reg::packed(2503, 0, 2224), /* processSureNotTypesForConditionalExpressionsAfterAssign $specifiedTypes */ - reg::packed(2518, 0, 2038), /* processSureNotTypesForConditionalExpressionsAfterAssign $variableType */ - reg::packed(2531, MAY_BE_ARRAY), /* processSureNotTypesForConditionalExpressionsAfterAssign $rhsImpurePoints */ - reg::packed(1672, 0, 1376), /* processSureNotTypesForConditionalExpressionsAfterAssign $assignedExpr */ - reg::packed(1994, MAY_BE_NULL, 1626), /* processSureNotTypesForConditionalExpressionsAfterAssign $assignedValueResult */ - reg::packed(1396, MAY_BE_ARRAY), /* processSureNotTypesForConditionalExpressionsAfterAssign return */ - reg::packed(2480, MAY_BE_ARRAY), /* processDefinednessForConditionalExpressionsAfterAssign $conditionalExpressions */ - reg::packed(2467, MAY_BE_STRING), /* processDefinednessForConditionalExpressionsAfterAssign $variableName */ - reg::packed(2518, 0, 2038), /* processDefinednessForConditionalExpressionsAfterAssign $variableType */ - reg::packed(2656, 0, 1490), /* processDefinednessForConditionalExpressionsAfterAssign $branchScope */ - reg::packed(2668, 0, 1490), /* processDefinednessForConditionalExpressionsAfterAssign $mergedScope */ - reg::packed(1396, MAY_BE_ARRAY), /* processDefinednessForConditionalExpressionsAfterAssign return */ - reg::packed(2735, 0, 2740), /* containsVariableAssignment $node */ - reg::packed(1396, MAY_BE_BOOL), /* containsVariableAssignment return */ - reg::packed(1406, 0, 1424), /* currentTypeForConditionalHolder $nodeScopeResolver */ - reg::packed(1484, 0, 1490), /* currentTypeForConditionalHolder $scope */ - reg::packed(1521, 0, 1529), /* currentTypeForConditionalHolder $storage */ - reg::packed(1371, 0, 1376), /* currentTypeForConditionalHolder $expr */ - reg::packed(1672, 0, 1376), /* currentTypeForConditionalHolder $assignedExpr */ - reg::packed(1994, MAY_BE_NULL, 1626), /* currentTypeForConditionalHolder $assignedValueResult */ - reg::packed(1396, 0, 2038), /* currentTypeForConditionalHolder return */ - reg::packed(1406, 0, 1424), /* processTernaryArmValueImpliedTypesAfterAssign $nodeScopeResolver */ - reg::packed(2814, 0, 1490), /* processTernaryArmValueImpliedTypesAfterAssign $armScope */ - reg::packed(1521, 0, 1529), /* processTernaryArmValueImpliedTypesAfterAssign $storage */ - reg::packed(2467, MAY_BE_STRING), /* processTernaryArmValueImpliedTypesAfterAssign $variableName */ - reg::packed(2480, MAY_BE_ARRAY), /* processTernaryArmValueImpliedTypesAfterAssign $conditionalExpressions */ - reg::packed(2823, 0, 1376), /* processTernaryArmValueImpliedTypesAfterAssign $armExpr */ - reg::packed(2831, 0, 2038), /* processTernaryArmValueImpliedTypesAfterAssign $remainderType */ - reg::packed(2845, 0, 2038), /* processTernaryArmValueImpliedTypesAfterAssign $otherArmType */ - reg::packed(2531, MAY_BE_ARRAY), /* processTernaryArmValueImpliedTypesAfterAssign $rhsImpurePoints */ - reg::packed(1672, 0, 1376), /* processTernaryArmValueImpliedTypesAfterAssign $assignedExpr */ - reg::packed(1994, MAY_BE_NULL, 1626), /* processTernaryArmValueImpliedTypesAfterAssign $assignedValueResult */ - reg::packed(1396, MAY_BE_ARRAY), /* processTernaryArmValueImpliedTypesAfterAssign return */ - reg::packed(2480, MAY_BE_ARRAY), /* addConditionalExpressionHolder $conditionalExpressions */ - reg::packed(2467, MAY_BE_STRING), /* addConditionalExpressionHolder $variableName */ - reg::packed(2518, 0, 2038), /* addConditionalExpressionHolder $variableType */ - reg::packed(2904, 0, 1376), /* addConditionalExpressionHolder $holderExpr */ - reg::packed(2915, MAY_BE_STRING), /* addConditionalExpressionHolder $holderExprString */ - reg::packed(2932, 0, 2038), /* addConditionalExpressionHolder $holderType */ - reg::packed(2943, 0, 2959), /* addConditionalExpressionHolder $holderCertainty */ - reg::packed(1396, MAY_BE_ARRAY), /* addConditionalExpressionHolder return */ - reg::packed(2480, MAY_BE_ARRAY), /* mergeConditionalExpressions $conditionalExpressions */ - reg::packed(3011, MAY_BE_ARRAY), /* mergeConditionalExpressions $newConditionalExpressions */ - reg::packed(1396, MAY_BE_ARRAY), /* mergeConditionalExpressions return */ - reg::packed(1484, 0, 1490), /* processMatchForConditionalExpressionsAfterAssign $scope */ - reg::packed(2467, MAY_BE_STRING), /* processMatchForConditionalExpressionsAfterAssign $variableName */ - reg::packed(1371, 0, 3065), /* processMatchForConditionalExpressionsAfterAssign $expr */ - reg::packed(1396, MAY_BE_ARRAY), /* processMatchForConditionalExpressionsAfterAssign return */ - reg::packed(1406, 0, 1424), /* processDerivedConditionalExpressionsAfterAssign $nodeScopeResolver */ - reg::packed(1484, 0, 1490), /* processDerivedConditionalExpressionsAfterAssign $scope */ - reg::packed(2467, MAY_BE_STRING), /* processDerivedConditionalExpressionsAfterAssign $variableName */ - reg::packed(2480, MAY_BE_ARRAY), /* processDerivedConditionalExpressionsAfterAssign $conditionalExpressions */ - reg::packed(1672, 0, 1376), /* processDerivedConditionalExpressionsAfterAssign $assignedExpr */ - reg::packed(3141, 0, 2038), /* processDerivedConditionalExpressionsAfterAssign $assignedType */ - reg::packed(2531, MAY_BE_ARRAY), /* processDerivedConditionalExpressionsAfterAssign $rhsImpurePoints */ - reg::packed(1396, MAY_BE_ARRAY), /* processDerivedConditionalExpressionsAfterAssign return */ - reg::packed(1406, 0, 1424), /* processInArrayForConditionalExpressionsAfterAssign $nodeScopeResolver */ - reg::packed(1484, 0, 1490), /* processInArrayForConditionalExpressionsAfterAssign $scope */ - reg::packed(2467, MAY_BE_STRING), /* processInArrayForConditionalExpressionsAfterAssign $variableName */ - reg::packed(2480, MAY_BE_ARRAY), /* processInArrayForConditionalExpressionsAfterAssign $conditionalExpressions */ - reg::packed(1672, 0, 3202), /* processInArrayForConditionalExpressionsAfterAssign $assignedExpr */ - reg::packed(3141, 0, 2038), /* processInArrayForConditionalExpressionsAfterAssign $assignedType */ - reg::packed(2531, MAY_BE_ARRAY), /* processInArrayForConditionalExpressionsAfterAssign $rhsImpurePoints */ - reg::packed(1396, MAY_BE_ARRAY), /* processInArrayForConditionalExpressionsAfterAssign return */ - reg::packed(1371, 0, 1376), /* isExprSafeToProjectThroughVariable $expr */ - reg::packed(2467, MAY_BE_STRING), /* isExprSafeToProjectThroughVariable $variableName */ - reg::packed(2531, MAY_BE_ARRAY), /* isExprSafeToProjectThroughVariable $rhsImpurePoints */ - reg::packed(1672, 0, 1376), /* isExprSafeToProjectThroughVariable $assignedExpr */ - reg::packed(1396, MAY_BE_BOOL), /* isExprSafeToProjectThroughVariable return */ - reg::packed(3317, MAY_BE_ARRAY), /* isImplicitArrayCreation $dimFetchStack */ - reg::packed(1484, 0, 3331), /* isImplicitArrayCreation $scope */ - reg::packed(1396, 0, 2959), /* isImplicitArrayCreation return */ - reg::packed(1406, 0, 1424), /* processArrayByRefItems $nodeScopeResolver */ - reg::packed(1484, 0, 1490), /* processArrayByRefItems $scope */ - reg::packed(1521, 0, 1529), /* processArrayByRefItems $storage */ - reg::packed(3378, MAY_BE_STRING), /* processArrayByRefItems $rootVarName */ - reg::packed(3390, 0, 3400), /* processArrayByRefItems $arrayExpr */ - reg::packed(3427, 0, 1376), /* processArrayByRefItems $parentExpr */ - reg::packed(1396, 0, 1490), /* processArrayByRefItems return */ - reg::packed(1406, 0, 1424), /* processArrayByRefItemsWithImplicitIndex $nodeScopeResolver */ - reg::packed(1484, 0, 1490), /* processArrayByRefItemsWithImplicitIndex $scope */ - reg::packed(1521, 0, 1529), /* processArrayByRefItemsWithImplicitIndex $storage */ - reg::packed(3378, MAY_BE_STRING), /* processArrayByRefItemsWithImplicitIndex $rootVarName */ - reg::packed(3390, 0, 3400), /* processArrayByRefItemsWithImplicitIndex $arrayExpr */ - reg::packed(3427, 0, 1376), /* processArrayByRefItemsWithImplicitIndex $parentExpr */ - reg::packed(3461, MAY_BE_NULL | MAY_BE_LONG), /* processArrayByRefItemsWithImplicitIndex $implicitIndex */ - reg::packed(1396, MAY_BE_ARRAY), /* processArrayByRefItemsWithImplicitIndex return */ - reg::packed(3390, 0, 3400), /* isFlattenableUnpackedArray $arrayExpr */ - reg::packed(1396, MAY_BE_BOOL), /* isFlattenableUnpackedArray return */ - reg::packed(3542, MAY_BE_LONG), /* advanceImplicitIndex $index */ - reg::packed(1396, MAY_BE_NULL | MAY_BE_LONG), /* advanceImplicitIndex return */ - reg::packed(1406, 0, 1424), /* produceArrayDimFetchAssignValueToWrite $nodeScopeResolver */ - reg::packed(3317, MAY_BE_ARRAY), /* produceArrayDimFetchAssignValueToWrite $dimFetchStack */ - reg::packed(3569, MAY_BE_ARRAY), /* produceArrayDimFetchAssignValueToWrite $offsetTypes */ - reg::packed(3581, 0, 2038), /* produceArrayDimFetchAssignValueToWrite $offsetValueType */ - reg::packed(3597, 0, 2038), /* produceArrayDimFetchAssignValueToWrite $valueToWrite */ - reg::packed(1484, 0, 1490), /* produceArrayDimFetchAssignValueToWrite $scope */ - reg::packed(1521, 0, 1529), /* produceArrayDimFetchAssignValueToWrite $storage */ - reg::packed(1396, MAY_BE_ARRAY), /* produceArrayDimFetchAssignValueToWrite return */ - reg::packed(1406, 0, 1424), /* shouldKeepList $nodeScopeResolver */ - reg::packed(3649, 0, 3663), /* shouldKeepList $arrayDimFetch */ - reg::packed(1484, 0, 1490), /* shouldKeepList $scope */ - reg::packed(1521, 0, 1529), /* shouldKeepList $storage */ - reg::packed(3581, 0, 2038), /* shouldKeepList $offsetValueType */ - reg::packed(1396, MAY_BE_BOOL), /* shouldKeepList return */ - reg::packed(3581, 0, 2038), /* trackedLinkImpliesOffset $offsetValueType */ - reg::packed(3712, 0, 2038), /* trackedLinkImpliesOffset $offsetType */ - reg::packed(1396, MAY_BE_BOOL), /* trackedLinkImpliesOffset return */ - reg::packed(3748, 0, 1376), /* isSameVariable $a */ - reg::packed(3750, 0, 1376), /* isSameVariable $b */ - reg::packed(1396, MAY_BE_BOOL), /* isSameVariable return */ - reg::packed(3748, 0, 1376), /* isSameOffset $a */ - reg::packed(3750, 0, 1376), /* isSameOffset $b */ - reg::packed(1396, MAY_BE_BOOL), /* isSameOffset return */ - reg::packed(1371, 0, 1376), /* getLiteralArrayKeyType $expr */ - reg::packed(1396, MAY_BE_NULL, 2038), /* getLiteralArrayKeyType return */ - reg::packed(1406, 0, 1424), /* getOriginalPropertyType $nodeScopeResolver */ - reg::packed(3803, 0, 3817), /* getOriginalPropertyType $propertyFetch */ - reg::packed(1484, 0, 1490), /* getOriginalPropertyType $scope */ - reg::packed(1396, 0, 2038), /* getOriginalPropertyType return */ - reg::packed(3915, 0, 3400), /* hasArrayReference $array */ - reg::packed(1396, MAY_BE_BOOL), /* hasArrayReference return */ - reg::packed(3939, 0, 1626), /* redundant $rhs */ - reg::packed(1975, 0, 1376), /* redundant $target */ - reg::packed(1521, 0, 1529), /* redundant $storage */ - reg::packed(1396, MAY_BE_NULL, 2038), /* redundant return */ + reg::packed(1359, 0, 1387), /* __construct $initializerExprTypeResolver */ + reg::packed(1446, 0, 1451), /* supports $expr */ + reg::packed(1471, MAY_BE_BOOL), /* supports return */ + reg::packed(1481, 0, 1499), /* processExpr $nodeScopeResolver */ + reg::packed(1534, 0, 1539), /* processExpr $stmt */ + reg::packed(1446, 0, 1451), /* processExpr $expr */ + reg::packed(1559, 0, 1565), /* processExpr $scope */ + reg::packed(1596, 0, 1604), /* processExpr $storage */ + reg::packed(1645, MAY_BE_CALLABLE), /* processExpr $nodeCallback */ + reg::packed(1658, 0, 1666), /* processExpr $context */ + reg::packed(1471, 0, 1701), /* processExpr return */ + reg::packed(1747, 0, 1451), /* captureAssignedCallArgResults $assignedExpr */ + reg::packed(1596, 0, 1604), /* captureAssignedCallArgResults $storage */ + reg::packed(1471, MAY_BE_ARRAY), /* captureAssignedCallArgResults return */ + reg::packed(1446, 0, 1790), /* createCreateTypesCallback $expr */ + reg::packed(1817, 0, 1701), /* createCreateTypesCallback $assignedExprResult */ + reg::packed(1836, 0, 1565), /* createCreateTypesCallback $beforeScope */ + reg::packed(1471, 0, 1848), /* createCreateTypesCallback return */ + reg::packed(1446, 0, 1790), /* createSpecifyTypesCallback $expr */ + reg::packed(1817, 0, 1701), /* createSpecifyTypesCallback $assignedExprResult */ + reg::packed(1836, 0, 1565), /* createSpecifyTypesCallback $beforeScope */ + reg::packed(1596, 0, 1604), /* createSpecifyTypesCallback $storage */ + reg::packed(1471, 0, 1848), /* createSpecifyTypesCallback return */ + reg::packed(1481, 0, 1499), /* processVirtualAssign $nodeScopeResolver */ + reg::packed(1559, 0, 1565), /* processVirtualAssign $scope */ + reg::packed(1596, 0, 1604), /* processVirtualAssign $storage */ + reg::packed(1534, 0, 1539), /* processVirtualAssign $stmt */ + reg::packed(1909, 0, 1451), /* processVirtualAssign $var */ + reg::packed(1747, 0, 1451), /* processVirtualAssign $assignedExpr */ + reg::packed(1645, MAY_BE_CALLABLE), /* processVirtualAssign $nodeCallback */ + reg::packed(1817, MAY_BE_NULL, 1701, false, false, 1913), /* processVirtualAssign $assignedExprResult */ + reg::packed(1471, 0, 1701), /* processVirtualAssign return */ + reg::packed(1481, 0, 1499), /* prepareTarget $nodeScopeResolver */ + reg::packed(1559, 0, 1565), /* prepareTarget $scope */ + reg::packed(1596, 0, 1604), /* prepareTarget $storage */ + reg::packed(1534, 0, 1539), /* prepareTarget $stmt */ + reg::packed(1909, 0, 1451), /* prepareTarget $var */ + reg::packed(1747, 0, 1451), /* prepareTarget $assignedExpr */ + reg::packed(1645, MAY_BE_CALLABLE), /* prepareTarget $nodeCallback */ + reg::packed(1658, 0, 1666), /* prepareTarget $context */ + reg::packed(1939, 0, 1944), /* prepareTarget $mode */ + reg::packed(1471, 0, 1982), /* prepareTarget return */ + reg::packed(1481, 0, 1499), /* doPrepareTarget $nodeScopeResolver */ + reg::packed(1559, 0, 1565), /* doPrepareTarget $scope */ + reg::packed(1596, 0, 1604), /* doPrepareTarget $storage */ + reg::packed(1534, 0, 1539), /* doPrepareTarget $stmt */ + reg::packed(1909, 0, 1451), /* doPrepareTarget $var */ + reg::packed(1747, 0, 1451), /* doPrepareTarget $assignedExpr */ + reg::packed(1645, MAY_BE_CALLABLE), /* doPrepareTarget $nodeCallback */ + reg::packed(1658, 0, 1666), /* doPrepareTarget $context */ + reg::packed(1939, 0, 1944), /* doPrepareTarget $mode */ + reg::packed(1471, 0, 1982), /* doPrepareTarget return */ + reg::packed(1481, 0, 1499), /* applyWrite $nodeScopeResolver */ + reg::packed(2050, 0, 1982), /* applyWrite $target */ + reg::packed(2057, 0, 1701), /* applyWrite $valueResult */ + reg::packed(2069, MAY_BE_NULL, 1701), /* applyWrite $assignedValueResult */ + reg::packed(1534, 0, 1539), /* applyWrite $stmt */ + reg::packed(1596, 0, 1604), /* applyWrite $storage */ + reg::packed(1645, MAY_BE_CALLABLE), /* applyWrite $nodeCallback */ + reg::packed(1658, 0, 1666), /* applyWrite $context */ + reg::packed(1471, 0, 1701), /* applyWrite return */ + reg::packed(1481, 0, 1499), /* collectOffsetSetUsage $nodeScopeResolver */ + reg::packed(1559, 0, 1565), /* collectOffsetSetUsage $scope */ + reg::packed(2100, 0, 2113), /* collectOffsetSetUsage $receiverType */ + reg::packed(2131, MAY_BE_NULL, 2113), /* collectOffsetSetUsage $keyType */ + reg::packed(2139, 0, 2113), /* collectOffsetSetUsage $valueType */ + reg::packed(1471, 0, 2149), /* collectOffsetSetUsage return */ + reg::packed(2225, 0, 2232), /* createArrayDimFetchConditionalExpressionHolder $keyVar */ + reg::packed(2261, 0, 1451), /* createArrayDimFetchConditionalExpressionHolder $arrayArg */ + reg::packed(2270, 0, 2113), /* createArrayDimFetchConditionalExpressionHolder $narrowedKeyType */ + reg::packed(2286, 0, 2113), /* createArrayDimFetchConditionalExpressionHolder $dimFetchType */ + reg::packed(1471, 0, 2299), /* createArrayDimFetchConditionalExpressionHolder return */ + reg::packed(1481, 0, 1499), /* readAssignedValueType $nodeScopeResolver */ + reg::packed(2069, MAY_BE_NULL, 1701), /* readAssignedValueType $assignedValueResult */ + reg::packed(1747, 0, 1451), /* readAssignedValueType $assignedExpr */ + reg::packed(1559, 0, 1565), /* readAssignedValueType $scope */ + reg::packed(1471, 0, 2113), /* readAssignedValueType return */ + reg::packed(1481, 0, 1499), /* resolveContainerTypesAfterAssignedExprEval $nodeScopeResolver */ + reg::packed(1909, 0, 1451), /* resolveContainerTypesAfterAssignedExprEval $var */ + reg::packed(2400, 0, 1701), /* resolveContainerTypesAfterAssignedExprEval $varResult */ + reg::packed(2410, 0, 1565), /* resolveContainerTypesAfterAssignedExprEval $postEvalScope */ + reg::packed(2424, MAY_BE_NULL, 1565), /* resolveContainerTypesAfterAssignedExprEval $preEvalScope */ + reg::packed(1596, 0, 1604), /* resolveContainerTypesAfterAssignedExprEval $storage */ + reg::packed(1471, MAY_BE_ARRAY), /* resolveContainerTypesAfterAssignedExprEval return */ + reg::packed(1559, 0, 1565), /* assignDynamicVariable $scope */ + reg::packed(2480, 0, 1701), /* assignDynamicVariable $nameResult */ + reg::packed(2139, 0, 2113), /* assignDynamicVariable $valueType */ + reg::packed(2491, 0, 2113), /* assignDynamicVariable $nativeValueType */ + reg::packed(1471, 0, 1565), /* assignDynamicVariable return */ + reg::packed(1446, 0, 1451), /* unwrapAssign $expr */ + reg::packed(1471, 0, 1451), /* unwrapAssign return */ + reg::packed(1481, 0, 1499), /* processSureTypesForConditionalExpressionsAfterAssign $nodeScopeResolver */ + reg::packed(1559, 0, 1565), /* processSureTypesForConditionalExpressionsAfterAssign $scope */ + reg::packed(1596, 0, 1604), /* processSureTypesForConditionalExpressionsAfterAssign $storage */ + reg::packed(2542, MAY_BE_STRING), /* processSureTypesForConditionalExpressionsAfterAssign $variableName */ + reg::packed(2555, MAY_BE_ARRAY), /* processSureTypesForConditionalExpressionsAfterAssign $conditionalExpressions */ + reg::packed(2578, 0, 2299), /* processSureTypesForConditionalExpressionsAfterAssign $specifiedTypes */ + reg::packed(2593, 0, 2113), /* processSureTypesForConditionalExpressionsAfterAssign $variableType */ + reg::packed(2606, MAY_BE_ARRAY), /* processSureTypesForConditionalExpressionsAfterAssign $rhsImpurePoints */ + reg::packed(1747, 0, 1451), /* processSureTypesForConditionalExpressionsAfterAssign $assignedExpr */ + reg::packed(2069, MAY_BE_NULL, 1701), /* processSureTypesForConditionalExpressionsAfterAssign $assignedValueResult */ + reg::packed(1471, MAY_BE_ARRAY), /* processSureTypesForConditionalExpressionsAfterAssign return */ + reg::packed(1481, 0, 1499), /* processSureNotTypesForConditionalExpressionsAfterAssign $nodeScopeResolver */ + reg::packed(1559, 0, 1565), /* processSureNotTypesForConditionalExpressionsAfterAssign $scope */ + reg::packed(1596, 0, 1604), /* processSureNotTypesForConditionalExpressionsAfterAssign $storage */ + reg::packed(2542, MAY_BE_STRING), /* processSureNotTypesForConditionalExpressionsAfterAssign $variableName */ + reg::packed(2555, MAY_BE_ARRAY), /* processSureNotTypesForConditionalExpressionsAfterAssign $conditionalExpressions */ + reg::packed(2578, 0, 2299), /* processSureNotTypesForConditionalExpressionsAfterAssign $specifiedTypes */ + reg::packed(2593, 0, 2113), /* processSureNotTypesForConditionalExpressionsAfterAssign $variableType */ + reg::packed(2606, MAY_BE_ARRAY), /* processSureNotTypesForConditionalExpressionsAfterAssign $rhsImpurePoints */ + reg::packed(1747, 0, 1451), /* processSureNotTypesForConditionalExpressionsAfterAssign $assignedExpr */ + reg::packed(2069, MAY_BE_NULL, 1701), /* processSureNotTypesForConditionalExpressionsAfterAssign $assignedValueResult */ + reg::packed(1471, MAY_BE_ARRAY), /* processSureNotTypesForConditionalExpressionsAfterAssign return */ + reg::packed(2555, MAY_BE_ARRAY), /* remapConditionalExpressionsThroughConcatAssign $conditionalExpressions */ + reg::packed(2731, MAY_BE_STRING), /* remapConditionalExpressionsThroughConcatAssign $varExprString */ + reg::packed(2745, 0, 2113), /* remapConditionalExpressionsThroughConcatAssign $appendedType */ + reg::packed(1471, MAY_BE_ARRAY), /* remapConditionalExpressionsThroughConcatAssign return */ + reg::packed(2555, MAY_BE_ARRAY), /* processDefinednessForConditionalExpressionsAfterAssign $conditionalExpressions */ + reg::packed(2542, MAY_BE_STRING), /* processDefinednessForConditionalExpressionsAfterAssign $variableName */ + reg::packed(2593, 0, 2113), /* processDefinednessForConditionalExpressionsAfterAssign $variableType */ + reg::packed(2805, 0, 1565), /* processDefinednessForConditionalExpressionsAfterAssign $branchScope */ + reg::packed(2817, 0, 1565), /* processDefinednessForConditionalExpressionsAfterAssign $mergedScope */ + reg::packed(1471, MAY_BE_ARRAY), /* processDefinednessForConditionalExpressionsAfterAssign return */ + reg::packed(2884, 0, 2889), /* containsVariableAssignment $node */ + reg::packed(1471, MAY_BE_BOOL), /* containsVariableAssignment return */ + reg::packed(1481, 0, 1499), /* currentTypeForConditionalHolder $nodeScopeResolver */ + reg::packed(1559, 0, 1565), /* currentTypeForConditionalHolder $scope */ + reg::packed(1596, 0, 1604), /* currentTypeForConditionalHolder $storage */ + reg::packed(1446, 0, 1451), /* currentTypeForConditionalHolder $expr */ + reg::packed(1747, 0, 1451), /* currentTypeForConditionalHolder $assignedExpr */ + reg::packed(2069, MAY_BE_NULL, 1701), /* currentTypeForConditionalHolder $assignedValueResult */ + reg::packed(1471, 0, 2113), /* currentTypeForConditionalHolder return */ + reg::packed(1481, 0, 1499), /* processTernaryArmValueImpliedTypesAfterAssign $nodeScopeResolver */ + reg::packed(2963, 0, 1565), /* processTernaryArmValueImpliedTypesAfterAssign $armScope */ + reg::packed(1596, 0, 1604), /* processTernaryArmValueImpliedTypesAfterAssign $storage */ + reg::packed(2542, MAY_BE_STRING), /* processTernaryArmValueImpliedTypesAfterAssign $variableName */ + reg::packed(2555, MAY_BE_ARRAY), /* processTernaryArmValueImpliedTypesAfterAssign $conditionalExpressions */ + reg::packed(2972, 0, 1451), /* processTernaryArmValueImpliedTypesAfterAssign $armExpr */ + reg::packed(2980, 0, 2113), /* processTernaryArmValueImpliedTypesAfterAssign $remainderType */ + reg::packed(2994, 0, 2113), /* processTernaryArmValueImpliedTypesAfterAssign $otherArmType */ + reg::packed(2606, MAY_BE_ARRAY), /* processTernaryArmValueImpliedTypesAfterAssign $rhsImpurePoints */ + reg::packed(1747, 0, 1451), /* processTernaryArmValueImpliedTypesAfterAssign $assignedExpr */ + reg::packed(2069, MAY_BE_NULL, 1701), /* processTernaryArmValueImpliedTypesAfterAssign $assignedValueResult */ + reg::packed(1471, MAY_BE_ARRAY), /* processTernaryArmValueImpliedTypesAfterAssign return */ + reg::packed(2555, MAY_BE_ARRAY), /* addConditionalExpressionHolder $conditionalExpressions */ + reg::packed(2542, MAY_BE_STRING), /* addConditionalExpressionHolder $variableName */ + reg::packed(2593, 0, 2113), /* addConditionalExpressionHolder $variableType */ + reg::packed(3053, 0, 1451), /* addConditionalExpressionHolder $holderExpr */ + reg::packed(3064, MAY_BE_STRING), /* addConditionalExpressionHolder $holderExprString */ + reg::packed(3081, 0, 2113), /* addConditionalExpressionHolder $holderType */ + reg::packed(3092, 0, 3108), /* addConditionalExpressionHolder $holderCertainty */ + reg::packed(1471, MAY_BE_ARRAY), /* addConditionalExpressionHolder return */ + reg::packed(2555, MAY_BE_ARRAY), /* mergeConditionalExpressions $conditionalExpressions */ + reg::packed(3160, MAY_BE_ARRAY), /* mergeConditionalExpressions $newConditionalExpressions */ + reg::packed(1471, MAY_BE_ARRAY), /* mergeConditionalExpressions return */ + reg::packed(1559, 0, 1565), /* processMatchForConditionalExpressionsAfterAssign $scope */ + reg::packed(2542, MAY_BE_STRING), /* processMatchForConditionalExpressionsAfterAssign $variableName */ + reg::packed(1446, 0, 3214), /* processMatchForConditionalExpressionsAfterAssign $expr */ + reg::packed(1471, MAY_BE_ARRAY), /* processMatchForConditionalExpressionsAfterAssign return */ + reg::packed(1481, 0, 1499), /* processDerivedConditionalExpressionsAfterAssign $nodeScopeResolver */ + reg::packed(1559, 0, 1565), /* processDerivedConditionalExpressionsAfterAssign $scope */ + reg::packed(2542, MAY_BE_STRING), /* processDerivedConditionalExpressionsAfterAssign $variableName */ + reg::packed(2555, MAY_BE_ARRAY), /* processDerivedConditionalExpressionsAfterAssign $conditionalExpressions */ + reg::packed(1747, 0, 1451), /* processDerivedConditionalExpressionsAfterAssign $assignedExpr */ + reg::packed(3290, 0, 2113), /* processDerivedConditionalExpressionsAfterAssign $assignedType */ + reg::packed(2606, MAY_BE_ARRAY), /* processDerivedConditionalExpressionsAfterAssign $rhsImpurePoints */ + reg::packed(1471, MAY_BE_ARRAY), /* processDerivedConditionalExpressionsAfterAssign return */ + reg::packed(1481, 0, 1499), /* processInArrayForConditionalExpressionsAfterAssign $nodeScopeResolver */ + reg::packed(1559, 0, 1565), /* processInArrayForConditionalExpressionsAfterAssign $scope */ + reg::packed(2542, MAY_BE_STRING), /* processInArrayForConditionalExpressionsAfterAssign $variableName */ + reg::packed(2555, MAY_BE_ARRAY), /* processInArrayForConditionalExpressionsAfterAssign $conditionalExpressions */ + reg::packed(1747, 0, 3351), /* processInArrayForConditionalExpressionsAfterAssign $assignedExpr */ + reg::packed(3290, 0, 2113), /* processInArrayForConditionalExpressionsAfterAssign $assignedType */ + reg::packed(2606, MAY_BE_ARRAY), /* processInArrayForConditionalExpressionsAfterAssign $rhsImpurePoints */ + reg::packed(1471, MAY_BE_ARRAY), /* processInArrayForConditionalExpressionsAfterAssign return */ + reg::packed(1446, 0, 1451), /* isExprSafeToProjectThroughVariable $expr */ + reg::packed(2542, MAY_BE_STRING), /* isExprSafeToProjectThroughVariable $variableName */ + reg::packed(2606, MAY_BE_ARRAY), /* isExprSafeToProjectThroughVariable $rhsImpurePoints */ + reg::packed(1747, 0, 1451), /* isExprSafeToProjectThroughVariable $assignedExpr */ + reg::packed(1471, MAY_BE_BOOL), /* isExprSafeToProjectThroughVariable return */ + reg::packed(3466, MAY_BE_ARRAY), /* isImplicitArrayCreation $dimFetchStack */ + reg::packed(1559, 0, 3480), /* isImplicitArrayCreation $scope */ + reg::packed(1471, 0, 3108), /* isImplicitArrayCreation return */ + reg::packed(1481, 0, 1499), /* processArrayByRefItems $nodeScopeResolver */ + reg::packed(1559, 0, 1565), /* processArrayByRefItems $scope */ + reg::packed(1596, 0, 1604), /* processArrayByRefItems $storage */ + reg::packed(3527, MAY_BE_STRING), /* processArrayByRefItems $rootVarName */ + reg::packed(3539, 0, 3549), /* processArrayByRefItems $arrayExpr */ + reg::packed(3576, 0, 1451), /* processArrayByRefItems $parentExpr */ + reg::packed(1471, 0, 1565), /* processArrayByRefItems return */ + reg::packed(1481, 0, 1499), /* processArrayByRefItemsWithImplicitIndex $nodeScopeResolver */ + reg::packed(1559, 0, 1565), /* processArrayByRefItemsWithImplicitIndex $scope */ + reg::packed(1596, 0, 1604), /* processArrayByRefItemsWithImplicitIndex $storage */ + reg::packed(3527, MAY_BE_STRING), /* processArrayByRefItemsWithImplicitIndex $rootVarName */ + reg::packed(3539, 0, 3549), /* processArrayByRefItemsWithImplicitIndex $arrayExpr */ + reg::packed(3576, 0, 1451), /* processArrayByRefItemsWithImplicitIndex $parentExpr */ + reg::packed(3610, MAY_BE_NULL | MAY_BE_LONG), /* processArrayByRefItemsWithImplicitIndex $implicitIndex */ + reg::packed(1471, MAY_BE_ARRAY), /* processArrayByRefItemsWithImplicitIndex return */ + reg::packed(3539, 0, 3549), /* isFlattenableUnpackedArray $arrayExpr */ + reg::packed(1471, MAY_BE_BOOL), /* isFlattenableUnpackedArray return */ + reg::packed(3691, MAY_BE_LONG), /* advanceImplicitIndex $index */ + reg::packed(1471, MAY_BE_NULL | MAY_BE_LONG), /* advanceImplicitIndex return */ + reg::packed(1481, 0, 1499), /* produceArrayDimFetchAssignValueToWrite $nodeScopeResolver */ + reg::packed(3466, MAY_BE_ARRAY), /* produceArrayDimFetchAssignValueToWrite $dimFetchStack */ + reg::packed(3718, MAY_BE_ARRAY), /* produceArrayDimFetchAssignValueToWrite $offsetTypes */ + reg::packed(3730, 0, 2113), /* produceArrayDimFetchAssignValueToWrite $offsetValueType */ + reg::packed(3746, 0, 2113), /* produceArrayDimFetchAssignValueToWrite $valueToWrite */ + reg::packed(1559, 0, 1565), /* produceArrayDimFetchAssignValueToWrite $scope */ + reg::packed(1596, 0, 1604), /* produceArrayDimFetchAssignValueToWrite $storage */ + reg::packed(1471, MAY_BE_ARRAY), /* produceArrayDimFetchAssignValueToWrite return */ + reg::packed(1481, 0, 1499), /* shouldKeepList $nodeScopeResolver */ + reg::packed(3798, 0, 3812), /* shouldKeepList $arrayDimFetch */ + reg::packed(1559, 0, 1565), /* shouldKeepList $scope */ + reg::packed(1596, 0, 1604), /* shouldKeepList $storage */ + reg::packed(3730, 0, 2113), /* shouldKeepList $offsetValueType */ + reg::packed(1471, MAY_BE_BOOL), /* shouldKeepList return */ + reg::packed(3730, 0, 2113), /* trackedLinkImpliesOffset $offsetValueType */ + reg::packed(3861, 0, 2113), /* trackedLinkImpliesOffset $offsetType */ + reg::packed(1471, MAY_BE_BOOL), /* trackedLinkImpliesOffset return */ + reg::packed(3897, 0, 1451), /* isSameVariable $a */ + reg::packed(3899, 0, 1451), /* isSameVariable $b */ + reg::packed(1471, MAY_BE_BOOL), /* isSameVariable return */ + reg::packed(3897, 0, 1451), /* isSameOffset $a */ + reg::packed(3899, 0, 1451), /* isSameOffset $b */ + reg::packed(1471, MAY_BE_BOOL), /* isSameOffset return */ + reg::packed(1446, 0, 1451), /* getLiteralArrayKeyType $expr */ + reg::packed(1471, MAY_BE_NULL, 2113), /* getLiteralArrayKeyType return */ + reg::packed(1481, 0, 1499), /* getOriginalPropertyType $nodeScopeResolver */ + reg::packed(3952, 0, 3966), /* getOriginalPropertyType $propertyFetch */ + reg::packed(1559, 0, 1565), /* getOriginalPropertyType $scope */ + reg::packed(1471, 0, 2113), /* getOriginalPropertyType return */ + reg::packed(4064, 0, 3549), /* hasArrayReference $array */ + reg::packed(1471, MAY_BE_BOOL), /* hasArrayReference return */ + reg::packed(4088, 0, 1701), /* redundant $rhs */ + reg::packed(2050, 0, 1451), /* redundant $target */ + reg::packed(1596, 0, 1604), /* redundant $storage */ + reg::packed(1471, MAY_BE_NULL, 2113), /* redundant return */ }; using Sig = reg::Sig; } // namespace sigtab /* the signatures of the methods the class declares itself (a used trait's are in the trait's header) */ namespace sig { -inline constexpr sigtab::Sig __construct = { { 1359 /* __construct */, 20, 0, 20, reg::NoArg, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig supports = { { 1397 /* supports */, 1, 20, 1, 21, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig processExpr = { { 1660 /* processExpr */, 7, 22, 7, 29, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig captureAssignedCallArgResults = { { 1685 /* captureAssignedCallArgResults */, 2, 30, 2, 32, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig createCreateTypesCallback = { { 1781 /* createCreateTypesCallback */, 3, 33, 3, 36, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig createSpecifyTypesCallback = { { 1807 /* createSpecifyTypesCallback */, 4, 37, 4, 41, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processVirtualAssign = { { 1843 /* processVirtualAssign */, 7, 42, 8, 50, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig prepareTarget = { { 1945 /* prepareTarget */, 9, 51, 9, 60, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig doPrepareTarget = { { 1959 /* doPrepareTarget */, 9, 61, 9, 70, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig applyWrite = { { 2014 /* applyWrite */, 8, 71, 8, 79, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig collectOffsetSetUsage = { { 2128 /* collectOffsetSetUsage */, 5, 80, 5, 85, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig createArrayDimFetchConditionalExpressionHolder = { { 2256 /* createArrayDimFetchConditionalExpressionHolder */, 4, 86, 4, 90, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig readAssignedValueType = { { 2303 /* readAssignedValueType */, 4, 91, 4, 95, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig resolveContainerTypesAfterAssignedExprEval = { { 2362 /* resolveContainerTypesAfterAssignedExprEval */, 6, 96, 6, 102, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig assignDynamicVariable = { { 2432 /* assignDynamicVariable */, 4, 103, 4, 107, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig unwrapAssign = { { 2454 /* unwrapAssign */, 1, 108, 1, 109, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processSureTypesForConditionalExpressionsAfterAssign = { { 2547 /* processSureTypesForConditionalExpressionsAfterAssign */, 10, 110, 10, 120, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processSureNotTypesForConditionalExpressionsAfterAssign = { { 2600 /* processSureNotTypesForConditionalExpressionsAfterAssign */, 10, 121, 10, 131, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processDefinednessForConditionalExpressionsAfterAssign = { { 2680 /* processDefinednessForConditionalExpressionsAfterAssign */, 5, 132, 5, 137, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig containsVariableAssignment = { { 2755 /* containsVariableAssignment */, 1, 138, 1, 139, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; -inline constexpr sigtab::Sig currentTypeForConditionalHolder = { { 2782 /* currentTypeForConditionalHolder */, 6, 140, 6, 146, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processTernaryArmValueImpliedTypesAfterAssign = { { 2858 /* processTernaryArmValueImpliedTypesAfterAssign */, 11, 147, 11, 158, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig addConditionalExpressionHolder = { { 2980 /* addConditionalExpressionHolder */, 7, 159, 7, 166, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig mergeConditionalExpressions = { { 3037 /* mergeConditionalExpressions */, 2, 167, 2, 169, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processMatchForConditionalExpressionsAfterAssign = { { 3092 /* processMatchForConditionalExpressionsAfterAssign */, 3, 170, 3, 173, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processDerivedConditionalExpressionsAfterAssign = { { 3154 /* processDerivedConditionalExpressionsAfterAssign */, 7, 174, 7, 181, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processInArrayForConditionalExpressionsAfterAssign = { { 3231 /* processInArrayForConditionalExpressionsAfterAssign */, 7, 182, 7, 189, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig isExprSafeToProjectThroughVariable = { { 3282 /* isExprSafeToProjectThroughVariable */, 4, 190, 4, 194, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig isImplicitArrayCreation = { { 3354 /* isImplicitArrayCreation */, 2, 195, 2, 197, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processArrayByRefItems = { { 3438 /* processArrayByRefItems */, 6, 198, 6, 204, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processArrayByRefItemsWithImplicitIndex = { { 3475 /* processArrayByRefItemsWithImplicitIndex */, 7, 205, 7, 212, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig isFlattenableUnpackedArray = { { 3515 /* isFlattenableUnpackedArray */, 1, 213, 1, 214, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig advanceImplicitIndex = { { 3548 /* advanceImplicitIndex */, 1, 215, 1, 216, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig produceArrayDimFetchAssignValueToWrite = { { 3610 /* produceArrayDimFetchAssignValueToWrite */, 7, 217, 7, 224, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig shouldKeepList = { { 3697 /* shouldKeepList */, 5, 225, 5, 230, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig trackedLinkImpliesOffset = { { 3723 /* trackedLinkImpliesOffset */, 2, 231, 2, 233, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig isSameVariable = { { 3752 /* isSameVariable */, 2, 234, 2, 236, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig isSameOffset = { { 3767 /* isSameOffset */, 2, 237, 2, 239, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig getLiteralArrayKeyType = { { 3780 /* getLiteralArrayKeyType */, 1, 240, 1, 241, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig getOriginalPropertyType = { { 3891 /* getOriginalPropertyType */, 3, 242, 3, 245, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig hasArrayReference = { { 3921 /* hasArrayReference */, 1, 246, 1, 247, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; -inline constexpr sigtab::Sig redundant = { { 3943 /* redundant */, 3, 248, 3, 251, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig __construct = { { 1434 /* __construct */, 21, 0, 21, reg::NoArg, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig supports = { { 1472 /* supports */, 1, 21, 1, 22, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig processExpr = { { 1735 /* processExpr */, 7, 23, 7, 30, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig captureAssignedCallArgResults = { { 1760 /* captureAssignedCallArgResults */, 2, 31, 2, 33, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig createCreateTypesCallback = { { 1856 /* createCreateTypesCallback */, 3, 34, 3, 37, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig createSpecifyTypesCallback = { { 1882 /* createSpecifyTypesCallback */, 4, 38, 4, 42, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processVirtualAssign = { { 1918 /* processVirtualAssign */, 7, 43, 8, 51, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig prepareTarget = { { 2020 /* prepareTarget */, 9, 52, 9, 61, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig doPrepareTarget = { { 2034 /* doPrepareTarget */, 9, 62, 9, 71, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig applyWrite = { { 2089 /* applyWrite */, 8, 72, 8, 80, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig collectOffsetSetUsage = { { 2203 /* collectOffsetSetUsage */, 5, 81, 5, 86, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig createArrayDimFetchConditionalExpressionHolder = { { 2331 /* createArrayDimFetchConditionalExpressionHolder */, 4, 87, 4, 91, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig readAssignedValueType = { { 2378 /* readAssignedValueType */, 4, 92, 4, 96, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig resolveContainerTypesAfterAssignedExprEval = { { 2437 /* resolveContainerTypesAfterAssignedExprEval */, 6, 97, 6, 103, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig assignDynamicVariable = { { 2507 /* assignDynamicVariable */, 4, 104, 4, 108, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig unwrapAssign = { { 2529 /* unwrapAssign */, 1, 109, 1, 110, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processSureTypesForConditionalExpressionsAfterAssign = { { 2622 /* processSureTypesForConditionalExpressionsAfterAssign */, 10, 111, 10, 121, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processSureNotTypesForConditionalExpressionsAfterAssign = { { 2675 /* processSureNotTypesForConditionalExpressionsAfterAssign */, 10, 122, 10, 132, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig remapConditionalExpressionsThroughConcatAssign = { { 2758 /* remapConditionalExpressionsThroughConcatAssign */, 3, 133, 3, 136, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processDefinednessForConditionalExpressionsAfterAssign = { { 2829 /* processDefinednessForConditionalExpressionsAfterAssign */, 5, 137, 5, 142, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig containsVariableAssignment = { { 2904 /* containsVariableAssignment */, 1, 143, 1, 144, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig currentTypeForConditionalHolder = { { 2931 /* currentTypeForConditionalHolder */, 6, 145, 6, 151, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processTernaryArmValueImpliedTypesAfterAssign = { { 3007 /* processTernaryArmValueImpliedTypesAfterAssign */, 11, 152, 11, 163, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig addConditionalExpressionHolder = { { 3129 /* addConditionalExpressionHolder */, 7, 164, 7, 171, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig mergeConditionalExpressions = { { 3186 /* mergeConditionalExpressions */, 2, 172, 2, 174, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processMatchForConditionalExpressionsAfterAssign = { { 3241 /* processMatchForConditionalExpressionsAfterAssign */, 3, 175, 3, 178, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processDerivedConditionalExpressionsAfterAssign = { { 3303 /* processDerivedConditionalExpressionsAfterAssign */, 7, 179, 7, 186, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processInArrayForConditionalExpressionsAfterAssign = { { 3380 /* processInArrayForConditionalExpressionsAfterAssign */, 7, 187, 7, 194, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig isExprSafeToProjectThroughVariable = { { 3431 /* isExprSafeToProjectThroughVariable */, 4, 195, 4, 199, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig isImplicitArrayCreation = { { 3503 /* isImplicitArrayCreation */, 2, 200, 2, 202, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processArrayByRefItems = { { 3587 /* processArrayByRefItems */, 6, 203, 6, 209, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processArrayByRefItemsWithImplicitIndex = { { 3624 /* processArrayByRefItemsWithImplicitIndex */, 7, 210, 7, 217, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig isFlattenableUnpackedArray = { { 3664 /* isFlattenableUnpackedArray */, 1, 218, 1, 219, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig advanceImplicitIndex = { { 3697 /* advanceImplicitIndex */, 1, 220, 1, 221, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig produceArrayDimFetchAssignValueToWrite = { { 3759 /* produceArrayDimFetchAssignValueToWrite */, 7, 222, 7, 229, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig shouldKeepList = { { 3846 /* shouldKeepList */, 5, 230, 5, 235, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig trackedLinkImpliesOffset = { { 3872 /* trackedLinkImpliesOffset */, 2, 236, 2, 238, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig isSameVariable = { { 3901 /* isSameVariable */, 2, 239, 2, 241, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig isSameOffset = { { 3916 /* isSameOffset */, 2, 242, 2, 244, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig getLiteralArrayKeyType = { { 3929 /* getLiteralArrayKeyType */, 1, 245, 1, 246, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig getOriginalPropertyType = { { 4040 /* getOriginalPropertyType */, 3, 247, 3, 250, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig hasArrayReference = { { 4070 /* hasArrayReference */, 1, 251, 1, 252, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig redundant = { { 4092 /* redundant */, 3, 253, 3, 256, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; } // namespace sig } // namespace ptdecl::AssignHandler