Skip to content

Commit f780d6f

Browse files
dylhunnalxhub
authored andcommitted
refactor(compiler): extract save/restore view logic to separate phase (#50008)
Saving and restoring the view is significant enough that it makes sense to handle it independently. This makes for easier reasoning about how view save/restore works. Co-authored-by: Alex Rickabaugh <[email protected]> PR Close #50008
1 parent 6de4f26 commit f780d6f

File tree

3 files changed

+65
-33
lines changed

3 files changed

+65
-33
lines changed

packages/compiler/src/template/pipeline/src/emit.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,15 @@ import {phaseVariableOptimization} from './phases/variable_optimization';
2727
import {phaseChaining} from './phases/chaining';
2828
import {phaseMergeNextContext} from './phases/next_context_merging';
2929
import {phaseNgContainer} from './phases/ng_container';
30+
import {phaseSaveRestoreView} from './phases/save_restore_view';
3031

3132
/**
3233
* Run all transformation phases in the correct order against a `ComponentCompilation`. After this
3334
* processing, the compilation should be in a state where it can be emitted via `emitTemplateFn`.s
3435
*/
3536
export function transformTemplate(cpl: ComponentCompilation): void {
3637
phaseGenerateVariables(cpl);
38+
phaseSaveRestoreView(cpl);
3739
phaseResolveNames(cpl);
3840
phaseResolveContexts(cpl);
3941
phaseLocalRefs(cpl);

packages/compiler/src/template/pipeline/src/phases/generate_variables.ts

Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,11 @@ function recursivelyProcessView(view: ViewCompilation, parentScope: Scope|null):
4040
// Extract a `Scope` from this view.
4141
const scope = getScopeForView(view, parentScope);
4242

43-
// Start the view creation block with an operation to save the current view context. This may be
44-
// used to restore the view context in any listeners that may be present.
45-
view.create.prepend([
46-
ir.createVariableOp<ir.CreateOp>(
47-
view.tpl.allocateXrefId(), scope.savedViewVariable, new ir.GetCurrentViewExpr()),
48-
]);
43+
// Embedded views require an operation to save/restore the view context.
44+
if (view.parent !== null) {
45+
// Start the view creation block with an operation to save the current view context. This may be
46+
// used to restore the view context in any listeners that may be present.
47+
}
4948

5049
for (const op of view.create) {
5150
switch (op.kind) {
@@ -54,26 +53,8 @@ function recursivelyProcessView(view: ViewCompilation, parentScope: Scope|null):
5453
recursivelyProcessView(view.tpl.views.get(op.xref)!, scope);
5554
break;
5655
case ir.OpKind.Listener:
57-
// Listeners get a preamble which starts with a call to restore the view.
58-
const preambleOps = [
59-
ir.createVariableOp<ir.UpdateOp>(
60-
view.tpl.allocateXrefId(), scope.viewContextVariable,
61-
new ir.RestoreViewExpr(view.xref)),
62-
// And includes all variables available to this view.
63-
...generateVariablesInScopeForView(view, scope)
64-
];
65-
66-
op.handlerOps.prepend(preambleOps);
67-
68-
// The "restore view" operation in listeners requires a call to `resetView` to reset the
69-
// context prior to returning from the listener operation. Find any `return` statements in
70-
// the listener body and wrap them in a call to reset the view.
71-
for (const handlerOp of op.handlerOps) {
72-
if (handlerOp.kind === ir.OpKind.Statement &&
73-
handlerOp.statement instanceof o.ReturnStatement) {
74-
handlerOp.statement.value = new ir.ResetViewExpr(handlerOp.statement.value);
75-
}
76-
}
56+
// Prepend variables to listener handler functions.
57+
op.handlerOps.prepend(generateVariablesInScopeForView(view, scope));
7758
break;
7859
}
7960
}
@@ -94,8 +75,6 @@ interface Scope {
9475

9576
viewContextVariable: ir.SemanticVariable;
9677

97-
savedViewVariable: ir.SemanticVariable;
98-
9978
contextVariables: Map<string, ir.SemanticVariable>;
10079

10180
/**
@@ -148,11 +127,6 @@ function getScopeForView(view: ViewCompilation, parent: Scope|null): Scope {
148127
name: null,
149128
view: view.xref,
150129
},
151-
savedViewVariable: {
152-
kind: ir.SemanticVariableKind.SavedView,
153-
name: null,
154-
view: view.xref,
155-
},
156130
contextVariables: new Map<string, ir.SemanticVariable>(),
157131
references: [],
158132
parent,
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import * as o from '../../../../output/output_ast';
10+
import * as ir from '../../ir';
11+
import type {ComponentCompilation} from '../compilation';
12+
13+
export function phaseSaveRestoreView(cpl: ComponentCompilation): void {
14+
for (const view of cpl.views.values()) {
15+
if (view === cpl.root) {
16+
// Save/restore operations are not necessary for the root view.
17+
continue;
18+
}
19+
20+
view.create.prepend([
21+
ir.createVariableOp<ir.CreateOp>(
22+
view.tpl.allocateXrefId(), {
23+
kind: ir.SemanticVariableKind.SavedView,
24+
name: null,
25+
view: view.xref,
26+
},
27+
new ir.GetCurrentViewExpr()),
28+
]);
29+
30+
for (const op of view.create) {
31+
if (op.kind !== ir.OpKind.Listener) {
32+
continue;
33+
}
34+
35+
op.handlerOps.prepend([
36+
ir.createVariableOp<ir.UpdateOp>(
37+
view.tpl.allocateXrefId(), {
38+
kind: ir.SemanticVariableKind.Context,
39+
name: null,
40+
view: view.xref,
41+
},
42+
new ir.RestoreViewExpr(view.xref)),
43+
]);
44+
45+
// The "restore view" operation in listeners requires a call to `resetView` to reset the
46+
// context prior to returning from the listener operation. Find any `return` statements in
47+
// the listener body and wrap them in a call to reset the view.
48+
for (const handlerOp of op.handlerOps) {
49+
if (handlerOp.kind === ir.OpKind.Statement &&
50+
handlerOp.statement instanceof o.ReturnStatement) {
51+
handlerOp.statement.value = new ir.ResetViewExpr(handlerOp.statement.value);
52+
}
53+
}
54+
}
55+
}
56+
}

0 commit comments

Comments
 (0)