77 */
88
99import * as ir from '../../ir' ;
10+ import * as o from '../../../../output/output_ast' ;
1011import { CompilationJob , ComponentCompilationJob } from '../compilation' ;
1112
1213/**
@@ -28,50 +29,64 @@ export function countVariables(job: CompilationJob): void {
2829 // Count variables on expressions inside ops. We do this later because some of these expressions
2930 // might be conditional (e.g. `pipeBinding` inside of a ternary), and we don't want to interfere
3031 // with indices for top-level binding slots (e.g. `property`).
31- for ( const op of unit . ops ( ) ) {
32- ir . visitExpressionsInOp ( op , ( expr ) => {
33- if ( ! ir . isIrExpression ( expr ) ) {
34- return ;
35- }
32+ const firstPassCountExpressionVars = ( expr : o . Expression ) => {
33+ if ( ! ir . isIrExpression ( expr ) ) {
34+ return ;
35+ }
3636
37- // TemplateDefinitionBuilder assigns variable offsets for everything but pure functions
38- // first, and then assigns offsets to pure functions lazily. We emulate that behavior by
39- // assigning offsets in two passes instead of one, only in compatibility mode.
40- if (
41- job . compatibility === ir . CompatibilityMode . TemplateDefinitionBuilder &&
42- expr instanceof ir . PureFunctionExpr
43- ) {
44- return ;
45- }
37+ // TemplateDefinitionBuilder assigns variable offsets for everything but pure functions
38+ // first, and then assigns offsets to pure functions lazily. We emulate that behavior by
39+ // assigning offsets in two passes instead of one, only in compatibility mode.
40+ if (
41+ job . compatibility === ir . CompatibilityMode . TemplateDefinitionBuilder &&
42+ expr instanceof ir . PureFunctionExpr
43+ ) {
44+ return ;
45+ }
4646
47- // Some expressions require knowledge of the number of variable slots consumed.
48- if ( ir . hasUsesVarOffsetTrait ( expr ) ) {
49- expr . varOffset = varCount ;
50- }
47+ // Some expressions require knowledge of the number of variable slots consumed.
48+ if ( ir . hasUsesVarOffsetTrait ( expr ) ) {
49+ expr . varOffset = varCount ;
50+ }
5151
52- if ( ir . hasConsumesVarsTrait ( expr ) ) {
53- varCount += varsUsedByIrExpression ( expr ) ;
54- }
55- } ) ;
56- }
52+ if ( ir . hasConsumesVarsTrait ( expr ) ) {
53+ varCount += varsUsedByIrExpression ( expr ) ;
54+ }
55+ } ;
5756
5857 // Compatibility mode pass for pure function offsets (as explained above).
58+ const secondPassCountExpressionVars = ( expr : o . Expression ) => {
59+ if ( ! ir . isIrExpression ( expr ) || ! ( expr instanceof ir . PureFunctionExpr ) ) {
60+ return ;
61+ }
62+
63+ // Some expressions require knowledge of the number of variable slots consumed.
64+ if ( ir . hasUsesVarOffsetTrait ( expr ) ) {
65+ expr . varOffset = varCount ;
66+ }
67+
68+ if ( ir . hasConsumesVarsTrait ( expr ) ) {
69+ varCount += varsUsedByIrExpression ( expr ) ;
70+ }
71+ } ;
72+
73+ // Note: we iterate over `create` and `update` separately, instead of going using `unit.ops()`,
74+ // because `unit.ops()` will visit nested ops too (e.g. the `ListenerOp.handlerOps`). We
75+ // don't want that, because the `visitExpressionsInOp` call below will visit the same nested
76+ // ops again, leading to vars in some expressions to be counted twice.
77+ for ( const createOp of unit . create ) {
78+ ir . visitExpressionsInOp ( createOp , firstPassCountExpressionVars ) ;
79+ }
80+ for ( const updateOp of unit . update ) {
81+ ir . visitExpressionsInOp ( updateOp , firstPassCountExpressionVars ) ;
82+ }
83+
5984 if ( job . compatibility === ir . CompatibilityMode . TemplateDefinitionBuilder ) {
60- for ( const op of unit . ops ( ) ) {
61- ir . visitExpressionsInOp ( op , ( expr ) => {
62- if ( ! ir . isIrExpression ( expr ) || ! ( expr instanceof ir . PureFunctionExpr ) ) {
63- return ;
64- }
65-
66- // Some expressions require knowledge of the number of variable slots consumed.
67- if ( ir . hasUsesVarOffsetTrait ( expr ) ) {
68- expr . varOffset = varCount ;
69- }
70-
71- if ( ir . hasConsumesVarsTrait ( expr ) ) {
72- varCount += varsUsedByIrExpression ( expr ) ;
73- }
74- } ) ;
85+ for ( const createOp of unit . create ) {
86+ ir . visitExpressionsInOp ( createOp , secondPassCountExpressionVars ) ;
87+ }
88+ for ( const updateOp of unit . update ) {
89+ ir . visitExpressionsInOp ( updateOp , secondPassCountExpressionVars ) ;
7590 }
7691 }
7792
@@ -164,7 +179,7 @@ function varsUsedByOp(op: (ir.CreateOp | ir.UpdateOp) & ir.ConsumesVarsTrait): n
164179 }
165180}
166181
167- export function varsUsedByIrExpression ( expr : ir . Expression & ir . ConsumesVarsTrait ) : number {
182+ function varsUsedByIrExpression ( expr : ir . Expression & ir . ConsumesVarsTrait ) : number {
168183 switch ( expr . kind ) {
169184 case ir . ExpressionKind . PureFunctionExpr :
170185 return 1 + expr . args . length ;
0 commit comments