@@ -441,9 +441,60 @@ class TryCatchHandler
441441 zv::Val mentionFlow = pt_statements_handler_get_variable_mention_flow (statementsHandler, catchNode);
442442 if (UNEXPECTED (mentionFlow.isUndef ())) return zv::Val ();
443443 zv::Arr catchFlow = zv::Arr::create (2 );
444- catchFlow.push (std::move (originalCatchType));
444+ catchFlow.push (zv::Ref (originalCatchType. raw () ));
445445 catchFlow.push (std::move (mentionFlow));
446446 catchFlows.push (zv::Val (std::move (catchFlow)));
447+
448+ // the catch block is not reachable, but rules still need to see its statements;
449+ // it is entered from where the try block can throw anything, and the result
450+ // of the walk does not flow anywhere
451+ zend_string *deadVariableName = NULL ;
452+ {
453+ zval *catchVar = ptsh::readNodeProperty (pt_tch_catch_var_site, catchNode, PT_LC (" var" ));
454+ if (UNEXPECTED (catchVar == NULL )) return zv::Val ();
455+ if (Z_TYPE_P (catchVar) != IS_NULL ) {
456+ zval *name = ptsh::readNodeProperty (pt_tch_variable_name_site, catchVar, PT_LC (" name" ));
457+ if (UNEXPECTED (name == NULL )) return zv::Val ();
458+ if (Z_TYPE_P (name) == IS_STRING ) {
459+ deadVariableName = Z_STR_P (name);
460+ }
461+ }
462+ }
463+ zv::Val deadVariableNameHold = deadVariableName != NULL ? zv::Val::string (deadVariableName) : zv::Val::null ();
464+ zv::Val mergedScope = zv::Val::null ();
465+ {
466+ zv::Val hold;
467+ zval *branchThrowPoints = pt_internal_statement_result_throw_points (branch, hold);
468+ if (UNEXPECTED (branchThrowPoints == NULL )) return zv::Val ();
469+ zv::Val branchThrowPointsHold = zv::Val::copyOf (zv::Ref (branchThrowPoints));
470+ if (Z_TYPE_P (branchThrowPointsHold.raw ()) == IS_ARRAY ) {
471+ for (auto throwEntry : zv::ArrRef (branchThrowPointsHold.raw ())) {
472+ zv::Val scopeHold;
473+ zval *throwScope = pt_internal_throw_point_scope (throwEntry.value ().deref ().raw (), scopeHold);
474+ if (UNEXPECTED (throwScope == NULL )) return zv::Val ();
475+ if (mergedScope.isNull ()) {
476+ mergedScope = zv::Val::copyOf (zv::Ref (throwScope));
477+ continue ;
478+ }
479+ zv::Val merged = pt_mutating_scope_merge_with (Z_OBJ_P (mergedScope.raw ()), throwScope);
480+ if (UNEXPECTED (merged.isUndef ())) return zv::Val ();
481+ mergedScope = std::move (merged);
482+ }
483+ }
484+ }
485+ if (mergedScope.isNull ()) {
486+ mergedScope = pt_mutating_scope_merge_with (Z_OBJ_P (scope), branchScope.raw ());
487+ if (UNEXPECTED (mergedScope.isUndef ())) return zv::Val ();
488+ }
489+ zval *deadCatchType = isNeverType (catchType.raw ()) ? originalCatchType.raw () : catchType.raw ();
490+ zv::Val deadCatchScope = pt_mutating_scope_enter_catch_type (Z_OBJ_P (mergedScope.raw ()), deadCatchType, deadVariableName != NULL ? Z_STR_P (deadVariableNameHold.raw ()) : NULL );
491+ if (UNEXPECTED (deadCatchScope.isUndef ())) return zv::Val ();
492+ zval *deadCatchStmts = ptsh::readNodeProperty (pt_tch_catch_stmts_site, catchNode, PT_LC (" stmts" ));
493+ if (UNEXPECTED (deadCatchStmts == NULL )) return zv::Val ();
494+ zv::Val deadCatchStmtsHold = zv::Val::copyOf (zv::Ref (deadCatchStmts));
495+ zv::Val deadCatchResult = pt_node_scope_resolver_process_stmt_nodes_internal (nodeScopeResolver, catchNode, deadCatchStmtsHold.raw (), deadCatchScope.raw (), storage, nodeCallback, context);
496+ if (UNEXPECTED (deadCatchResult.isUndef ())) return zv::Val ();
497+ if (UNEXPECTED (!pushStatementDependencies (dependencies, deadCatchResult.raw ()))) return zv::Val ();
447498 continue ;
448499 }
449500
0 commit comments