1414use PHPStan \NeverException ;
1515use PHPStan \Node \Printer \ExprPrinter ;
1616use PHPStan \ShouldNotHappenException ;
17+ use Throwable ;
1718use function array_map ;
1819use function array_merge ;
1920use function array_pop ;
2021use function count ;
2122use function get_class ;
2223use function get_debug_type ;
2324use function implode ;
25+ use function is_array ;
2426use function sprintf ;
2527
2628/**
@@ -111,17 +113,68 @@ private function processStmtNodes(
111113 StatementContext $ context ,
112114 ): StmtAnalysisResult
113115 {
116+ $ gen = new IdentifiedGeneratorInStack ($ this ->analyseStmts ($ stmts , $ scope , $ context , null ), $ stmts , null , null );
117+ $ gen ->generator ->current ();
118+
114119 $ stack = [];
115120
116- $ gen = $ this ->analyseStmts ($ stmts , $ scope , $ context , null );
117- $ gen ->current ();
121+ try {
122+ return $ this ->runTrampoline (
123+ $ fibersStorage ,
124+ $ exprAnalysisResultStorage ,
125+ $ gen ,
126+ $ nodeCallback ,
127+ $ stack ,
128+ );
129+ } catch (Throwable $ e ) {
130+ $ stackTrace = [];
131+ foreach (array_merge ($ stack , [$ gen ]) as $ identifiedGenerator ) {
132+ if ($ identifiedGenerator ->file === null && $ identifiedGenerator ->line === null ) {
133+ continue ;
134+ }
135+ if (is_array ($ identifiedGenerator ->node )) {
136+ $ stackTrace [] = sprintf (
137+ "Stmts \n -> %s on line %d " ,
138+ $ identifiedGenerator ->file ,
139+ $ identifiedGenerator ->line ,
140+ );
141+ continue ;
142+ }
143+
144+ $ stackTrace [] = sprintf (
145+ "%s:%d \n -> %s on line %d " ,
146+ $ identifiedGenerator ->file ,
147+ $ identifiedGenerator ->line ,
148+ get_class ($ identifiedGenerator ->node ),
149+ $ identifiedGenerator ->node ->getStartLine (),
150+ );
151+ }
152+
153+ throw new TrampolineException (sprintf (
154+ "Error ocurred in GNSR trampoline: %s \n\nAST processor stack trace: \n%s " ,
155+ $ e ->getMessage (),
156+ implode ("\n" , $ stackTrace ),
157+ ), previous: $ e );
158+ }
159+ }
118160
119- // Trampoline loop
161+ /**
162+ * @param callable(Node, Scope): void $nodeCallback
163+ * @param list<IdentifiedGeneratorInStack> $stack
164+ */
165+ private function runTrampoline (
166+ PendingFibersStorage $ fibersStorage ,
167+ ExprAnalysisResultStorage $ exprAnalysisResultStorage ,
168+ IdentifiedGeneratorInStack &$ gen ,
169+ callable $ nodeCallback ,
170+ array &$ stack ,
171+ ): StmtAnalysisResult
172+ {
120173 while (true ) {
121174 $ this ->processPendingFibers ($ fibersStorage , $ exprAnalysisResultStorage );
122175
123- if ($ gen ->valid ()) {
124- $ yielded = $ gen ->current ();
176+ if ($ gen ->generator -> valid ()) {
177+ $ yielded = $ gen ->generator -> current ();
125178
126179 if ($ yielded instanceof NodeCallbackRequest) {
127180 $ this ->invokeNodeCallback (
@@ -132,7 +185,7 @@ private function processStmtNodes(
132185 $ nodeCallback ,
133186 );
134187
135- $ gen ->next ();
188+ $ gen ->generator -> next ();
136189 continue ;
137190 } elseif ($ yielded instanceof AlternativeNodeCallbackRequest) {
138191 $ alternativeNodeCallback = $ yielded ->nodeCallback ;
@@ -146,29 +199,44 @@ static function (Node $node, Scope $scope) use ($alternativeNodeCallback, $nodeC
146199 },
147200 );
148201
149- $ gen ->next ();
202+ $ gen ->generator -> next ();
150203 continue ;
151204 } elseif ($ yielded instanceof ExprAnalysisRequest) {
152205 $ stack [] = $ gen ;
153- $ gen = $ this ->analyseExpr ($ exprAnalysisResultStorage , $ yielded ->stmt , $ yielded ->expr , $ yielded ->scope , $ yielded ->context , $ yielded ->alternativeNodeCallback );
154- $ gen ->current ();
206+ $ gen = new IdentifiedGeneratorInStack (
207+ $ this ->analyseExpr ($ exprAnalysisResultStorage , $ yielded ->stmt , $ yielded ->expr , $ yielded ->scope , $ yielded ->context , $ yielded ->alternativeNodeCallback ),
208+ $ yielded ->expr ,
209+ $ yielded ->originFile ,
210+ $ yielded ->originLine ,
211+ );
212+ $ gen ->generator ->current ();
155213 continue ;
156214 } elseif ($ yielded instanceof StmtAnalysisRequest) {
157215 $ stack [] = $ gen ;
158- $ gen = $ this ->analyseStmt ($ yielded ->stmt , $ yielded ->scope , $ yielded ->context , $ yielded ->alternativeNodeCallback );
159- $ gen ->current ();
216+ $ gen = new IdentifiedGeneratorInStack (
217+ $ this ->analyseStmt ($ yielded ->stmt , $ yielded ->scope , $ yielded ->context , $ yielded ->alternativeNodeCallback ),
218+ $ yielded ->stmt ,
219+ $ yielded ->originFile ,
220+ $ yielded ->originLine ,
221+ );
222+ $ gen ->generator ->current ();
160223 continue ;
161224 } elseif ($ yielded instanceof StmtsAnalysisRequest) {
162225 $ stack [] = $ gen ;
163- $ gen = $ this ->analyseStmts ($ yielded ->stmts , $ yielded ->scope , $ yielded ->context , $ yielded ->alternativeNodeCallback );
164- $ gen ->current ();
226+ $ gen = new IdentifiedGeneratorInStack (
227+ $ this ->analyseStmts ($ yielded ->stmts , $ yielded ->scope , $ yielded ->context , $ yielded ->alternativeNodeCallback ),
228+ $ yielded ->stmts ,
229+ $ yielded ->originFile ,
230+ $ yielded ->originLine ,
231+ );
232+ $ gen ->generator ->current ();
165233 continue ;
166234 } else { // phpcs:ignore
167235 throw new NeverException ($ yielded );
168236 }
169237 }
170238
171- $ result = $ gen ->getReturn ();
239+ $ result = $ gen ->generator -> getReturn ();
172240 if (count ($ stack ) === 0 ) {
173241 foreach ($ fibersStorage ->pendingFibers as $ pending ) {
174242 $ request = $ pending ['request ' ];
@@ -200,7 +268,7 @@ static function () {
200268 }
201269
202270 $ gen = array_pop ($ stack );
203- $ gen ->send ($ result );
271+ $ gen ->generator -> send ($ result );
204272 }
205273 }
206274
0 commit comments