diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index b31ccecf985..2bd8e73b26e 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -1410,10 +1410,6 @@ public function specifyTypesOfNewWorldHandlerNode(Expr $node, TypeSpecifierConte */ public function obtainResultForNode(Expr $node): ExpressionResult { - // see resolveTypeOfNewWorldHandlerNode() - rules ask the dispatcher - // with their NodeCallbackScope (e.g. ImpossibleCheckTypeHelper), the engine - // side of the boundary works with the mutating flavor - $scope = $this->toWalkScope(); $storage = $this->expressionResultStorageStack->getCurrent(); if ($storage !== null) { $result = $storage->findExpressionResult($node); @@ -1434,6 +1430,11 @@ public function obtainResultForNode(Expr $node): ExpressionResult )); } + // see resolveTypeOfNewWorldHandlerNode() - rules ask the dispatcher + // with their NodeCallbackScope (e.g. ImpossibleCheckTypeHelper), the engine + // side of the boundary works with the mutating flavor + $scope = $this->toWalkScope(); + // a synthetic node, or no analysis in progress return $this->container->getByType(NodeScopeResolver::class)->processExprOnDemand( $node, diff --git a/src/Analyser/StmtHandler/ForeachHandler.php b/src/Analyser/StmtHandler/ForeachHandler.php index 9bd2d818f92..2ba5323bf7b 100644 --- a/src/Analyser/StmtHandler/ForeachHandler.php +++ b/src/Analyser/StmtHandler/ForeachHandler.php @@ -604,39 +604,40 @@ private function enterForeach(NodeScopeResolver $nodeScopeResolver, MutatingScop } } - $constantArrays = $iterateeType->getConstantArrays(); if ( $stmt->getDocComment() === null && $iterateeType->isConstantArray()->yes() - && count($constantArrays) === 1 && $stmt->valueVar instanceof Variable && is_string($stmt->valueVar->name) && $stmt->keyVar instanceof Variable && is_string($stmt->keyVar->name) ) { - $valueConditionalHolders = []; - $arrayDimFetchConditionalHolders = []; - foreach ($constantArrays[0]->getKeyTypes() as $i => $keyType) { - $valueType = $constantArrays[0]->getValueTypes()[$i]; - $keyExpressionTypeHolder = ExpressionTypeHolder::createYes(new Variable($stmt->keyVar->name), $keyType); - - $holder = new ConditionalExpressionHolder([ - '$' . $stmt->keyVar->name => $keyExpressionTypeHolder, - ], ExpressionTypeHolder::createYes($stmt->valueVar, $valueType)); - $valueConditionalHolders[$holder->getKey()] = $holder; - $arrayDimFetchHolder = new ConditionalExpressionHolder([ - '$' . $stmt->keyVar->name => $keyExpressionTypeHolder, - ], ExpressionTypeHolder::createYes(new ArrayDimFetch($stmt->expr, $stmt->keyVar), $valueType)); - $arrayDimFetchConditionalHolders[$arrayDimFetchHolder->getKey()] = $arrayDimFetchHolder; - } + $constantArrays = $iterateeType->getConstantArrays(); + if (count($constantArrays) === 1) { + $valueConditionalHolders = []; + $arrayDimFetchConditionalHolders = []; + foreach ($constantArrays[0]->getKeyTypes() as $i => $keyType) { + $valueType = $constantArrays[0]->getValueTypes()[$i]; + $keyExpressionTypeHolder = ExpressionTypeHolder::createYes(new Variable($stmt->keyVar->name), $keyType); + + $holder = new ConditionalExpressionHolder([ + '$' . $stmt->keyVar->name => $keyExpressionTypeHolder, + ], ExpressionTypeHolder::createYes($stmt->valueVar, $valueType)); + $valueConditionalHolders[$holder->getKey()] = $holder; + $arrayDimFetchHolder = new ConditionalExpressionHolder([ + '$' . $stmt->keyVar->name => $keyExpressionTypeHolder, + ], ExpressionTypeHolder::createYes(new ArrayDimFetch($stmt->expr, $stmt->keyVar), $valueType)); + $arrayDimFetchConditionalHolders[$arrayDimFetchHolder->getKey()] = $arrayDimFetchHolder; + } - $scope = $scope->addConditionalExpressions( - '$' . $stmt->valueVar->name, - $valueConditionalHolders, - ); - if ($stmt->expr instanceof Variable && is_string($stmt->expr->name)) { $scope = $scope->addConditionalExpressions( - sprintf('$%s[$%s]', $stmt->expr->name, $stmt->keyVar->name), - $arrayDimFetchConditionalHolders, + '$' . $stmt->valueVar->name, + $valueConditionalHolders, ); + if ($stmt->expr instanceof Variable && is_string($stmt->expr->name)) { + $scope = $scope->addConditionalExpressions( + sprintf('$%s[$%s]', $stmt->expr->name, $stmt->keyVar->name), + $arrayDimFetchConditionalHolders, + ); + } } } diff --git a/src/Turbo/TurboExtensionEnabler.php b/src/Turbo/TurboExtensionEnabler.php index cd4159ef40b..9e9e8609bea 100644 --- a/src/Turbo/TurboExtensionEnabler.php +++ b/src/Turbo/TurboExtensionEnabler.php @@ -34,7 +34,7 @@ final class TurboExtensionEnabler { - public const EXPECTED_EXTENSION_VERSION = '536f37b'; + public const EXPECTED_EXTENSION_VERSION = '6366ed7'; private static bool $active = false; diff --git a/turbo-ext/src/ForeachHandler.cpp b/turbo-ext/src/ForeachHandler.cpp index d98a92c834a..93d6fd6990c 100644 --- a/turbo-ext/src/ForeachHandler.cpp +++ b/turbo-ext/src/ForeachHandler.cpp @@ -1295,16 +1295,18 @@ class ForeachHandler } } - zv::Val constantArrays = typeOp(iterateeType, PT_OP_GET_CONSTANT_ARRAYS, "getConstantArrays"); - if (UNEXPECTED(constantArrays.isUndef())) return zv::Val(); bool noDocComment; if (UNEXPECTED(!hasNoDocComment(stmt, noDocComment))) return zv::Val(); - if (noDocComment) { + if (noDocComment && parts.valueVarName != NULL && parts.keyVarName != NULL) { zend_long isConstantArray = pt_type_op_trinary(Z_OBJ_P(iterateeType), PT_OP_IS_CONSTANT_ARRAY, 0, NULL); if (UNEXPECTED(isConstantArray < 0)) return zv::Val(); - if (isConstantArray == PT_TRI_YES && ptlh::countOf(constantArrays.raw()) == 1 && parts.valueVarName != NULL && parts.keyVarName != NULL) { - scope = addConstantArrayConditionalHolders(scope.raw(), parts, listAt(constantArrays.raw(), 0)); - if (UNEXPECTED(scope.isUndef())) return zv::Val(); + if (isConstantArray == PT_TRI_YES) { + zv::Val constantArrays = typeOp(iterateeType, PT_OP_GET_CONSTANT_ARRAYS, "getConstantArrays"); + if (UNEXPECTED(constantArrays.isUndef())) return zv::Val(); + if (ptlh::countOf(constantArrays.raw()) == 1) { + scope = addConstantArrayConditionalHolders(scope.raw(), parts, listAt(constantArrays.raw(), 0)); + if (UNEXPECTED(scope.isUndef())) return zv::Val(); + } } } diff --git a/turbo-ext/src/MutatingScope.cpp b/turbo-ext/src/MutatingScope.cpp index 66e26133896..c4c6424a79b 100644 --- a/turbo-ext/src/MutatingScope.cpp +++ b/turbo-ext/src/MutatingScope.cpp @@ -2938,8 +2938,6 @@ class MutatingScope zv::Val obtainResultForNode(zend_object *node) { - zv::Val scope = thisToWalkScope(); - if (UNEXPECTED(scope.isUndef())) return zv::Val(); zv::Val storage = currentStorage(); if (UNEXPECTED(storage.isUndef())) return zv::Val(); if (!storage.isNull()) { @@ -2955,6 +2953,9 @@ class MutatingScope return zv::Val(); } + zv::Val scope = thisToWalkScope(); + if (UNEXPECTED(scope.isUndef())) return zv::Val(); + /* a synthetic node, or no analysis in progress */ zv::Val resolver = containerGetByType(PT_LC("PHPStan\\Analyser\\NodeScopeResolver")); if (UNEXPECTED(resolver.isUndef())) return zv::Val();