66 * constructor keeps the twin's arginfo so Nette autowires it, the per-file
77 * cache lives in the twin's $cachedTypes slot with the twin's shape
88 * (spl_object_id => ['expr' => ..., 'types' => [cacheKey => [...]]]) and is
9- * updated in place. The private static $resolveClosureTypeDepth guard is a
10- * C++ counter (the declared static stays for reflection parity).
9+ * updated in place. The private static $resolveClosureTypeDepth guard and
10+ * $cappedClosureTypeWalks are C++ counters (the declared statics stay for
11+ * reflection parity).
1112 *
1213 * getClosureType(), buildClosureTypeForClosure(),
1314 * buildClosureTypeForArrowFunction() and getDeclaredClosureType() are exported
@@ -58,6 +59,9 @@ zend_string *pt_ctr_used_variables = nullptr;
5859/* the private static $resolveClosureTypeDepth */
5960int pt_ctr_resolve_closure_type_depth = 0 ;
6061
62+ /* the private static $cappedClosureTypeWalks */
63+ int pt_ctr_capped_closure_type_walks = 0 ;
64+
6165/* {{{ the PHP collaborators (one site each; switch to their direct entries
6266 * once they are ported) */
6367
@@ -355,7 +359,10 @@ class ClosureTypeResolver
355359 ZVAL_DEREF (cached);
356360 return createClosureTypeFromCache (scope, expr, p.parameters .raw (), p.isVariadic , cached, p.contextFree );
357361 }
358- if (pt_ctr_resolve_closure_type_depth >= 2 ) return signatureClosureType (scope, expr, p.parameters .raw (), p.isVariadic );
362+ if (pt_ctr_resolve_closure_type_depth >= 2 ) {
363+ pt_ctr_capped_closure_type_walks++;
364+ return signatureClosureType (scope, expr, p.parameters .raw (), p.isVariadic );
365+ }
359366
360367 if (UNEXPECTED (!countClosureTypeBodyWalk ())) return zv::Val ();
361368 int isArrowFunction = ptclosure::instanceOf (expr, PT_CLASS_ARROW_FUNCTION );
@@ -1336,6 +1343,12 @@ class ClosureTypeResolver
13361343 zend_hash_index_update (Z_ARRVAL_P (cachedTypes), id, &value);
13371344 }
13381345
1346+ /* Mirrors readableWalkStorage() (NULL for null) */
1347+ static zval *readableWalkStorage (zval *walkStorage, int cappedBefore)
1348+ {
1349+ return pt_ctr_capped_closure_type_walks == cappedBefore ? walkStorage : NULL ;
1350+ }
1351+
13391352 /* the arrow-function body walk of getClosureType() */
13401353 zv::Val walkArrowFunction (zval *scope, zval *expr, Parameters &p, zend_string *cacheKey)
13411354 {
@@ -1354,6 +1367,7 @@ class ClosureTypeResolver
13541367 zv::Val arrowFunctionImpurePoints = ptsh::newArrayReference ();
13551368 zv::Val invalidateExpressions = ptsh::newArrayReference ();
13561369 pt_ctr_resolve_closure_type_depth++;
1370+ int cappedBefore = pt_ctr_capped_closure_type_walks;
13571371 zv::Val walkStorage = pt_expression_result_storage_new ();
13581372 if (UNEXPECTED (walkStorage.isUndef ())) return zv::Val ();
13591373 if (UNEXPECTED (!pt_mutating_scope_push_expression_result_storage (Z_OBJ_P (arrowScope.raw ()), walkStorage.raw ()))) return zv::Val ();
@@ -1390,7 +1404,7 @@ class ClosureTypeResolver
13901404
13911405 // the body was processed just above; resolve the return type from its stored
13921406 // result rather than reading the still-unprocessed body expression
1393- zv::Val returnType = resolveArrowFunctionReturnType (scope, arrowScope.raw (), expr, false , walkStorage.raw ());
1407+ zv::Val returnType = resolveArrowFunctionReturnType (scope, arrowScope.raw (), expr, false , readableWalkStorage ( walkStorage.raw (), cappedBefore ));
13941408 if (UNEXPECTED (returnType.isUndef ())) return zv::Val ();
13951409
13961410 zv::Arr usedVariables = zv::Arr::empty ();
@@ -1401,6 +1415,7 @@ class ClosureTypeResolver
14011415 zv::Val walkClosure (zval *scope, zval *expr, Parameters &p, zend_string *cacheKey)
14021416 {
14031417 pt_ctr_resolve_closure_type_depth++;
1418+ int cappedBefore = pt_ctr_capped_closure_type_walks;
14041419
14051420 zval null;
14061421 ZVAL_NULL (&null);
@@ -1461,7 +1476,7 @@ class ClosureTypeResolver
14611476 zv::Val impurePoints = mergeLists (Z_REFVAL_P (closureImpurePoints.raw ()), resultImpurePoints);
14621477 if (UNEXPECTED (impurePoints.isUndef ())) return zv::Val ();
14631478
1464- return buildClosureTypeFromClosureWalk (scope, expr, p.parameters .raw (), p.isVariadic , Z_REFVAL_P (closureReturnStatements.raw ()), Z_REFVAL_P (closureYieldStatements.raw ()), Z_REFVAL_P (closureExecutionEnds.raw ()), throwPointsOwned.raw (), impurePoints.raw (), Z_REFVAL_P (invalidateExpressions.raw ()), cacheKey, false , walkStorage.raw (), p.contextFree );
1479+ return buildClosureTypeFromClosureWalk (scope, expr, p.parameters .raw (), p.isVariadic , Z_REFVAL_P (closureReturnStatements.raw ()), Z_REFVAL_P (closureYieldStatements.raw ()), Z_REFVAL_P (closureExecutionEnds.raw ()), throwPointsOwned.raw (), impurePoints.raw (), Z_REFVAL_P (invalidateExpressions.raw ()), cacheKey, false , readableWalkStorage ( walkStorage.raw (), cappedBefore ), p.contextFree );
14651480 }
14661481};
14671482
0 commit comments