mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(compiler): do not use constants for colocated shallow references
Currently the TS generated output (not JIT), breaks at runtime because we emit all variables using the `Final` modifier. i.e. constants. This breaks shallow references when we run our acceptance signal tests using AOT.
This commit is contained in:
@@ -68,18 +68,25 @@ export interface VariableOp<OpT extends Op<OpT>> extends Op<OpT> {
|
||||
* Expression representing the value of the variable.
|
||||
*/
|
||||
initializer: o.Expression;
|
||||
|
||||
/**
|
||||
* Whether the variable created is a constant.
|
||||
*/
|
||||
isConstant: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a `VariableOp`.
|
||||
*/
|
||||
export function createVariableOp<OpT extends Op<OpT>>(
|
||||
xref: XrefId, variable: SemanticVariable, initializer: o.Expression): VariableOp<OpT> {
|
||||
xref: XrefId, variable: SemanticVariable, initializer: o.Expression,
|
||||
isConstant: boolean): VariableOp<OpT> {
|
||||
return {
|
||||
kind: OpKind.Variable,
|
||||
xref,
|
||||
variable,
|
||||
initializer,
|
||||
isConstant,
|
||||
...NEW_OP,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -79,6 +79,8 @@ function processUnit(unit: CompilationUnit): void {
|
||||
// initializer to `undefined`, and set the variable to its value after its declaration.
|
||||
const initializer = declOp.initializer;
|
||||
declOp.initializer = o.literal(undefined);
|
||||
declOp.isConstant = false;
|
||||
|
||||
const readVar = new ir.ReadVariableExpr(declOp.xref);
|
||||
// TODO: variable naming should run after this and take care of this for us.
|
||||
readVar.name = declOp.variable.name;
|
||||
|
||||
@@ -179,7 +179,8 @@ function generateVariablesInScopeForView<OpT extends ir.Op<OpT>>(
|
||||
// view with a `nextContext` expression. This context switching operation itself declares a
|
||||
// variable, because the context of the view may be referenced directly.
|
||||
newOps.push(ir.createVariableOp(
|
||||
view.job.allocateXrefId(), scope.viewContextVariable, new ir.NextContextExpr()));
|
||||
view.job.allocateXrefId(), scope.viewContextVariable, new ir.NextContextExpr(),
|
||||
/* isConstant */ true));
|
||||
}
|
||||
|
||||
// Add variables for all context variables available in this scope's view.
|
||||
@@ -189,13 +190,15 @@ function generateVariablesInScopeForView<OpT extends ir.Op<OpT>>(
|
||||
const variable = value === ir.CTX_REF ? context : new o.ReadPropExpr(context, value);
|
||||
// Add the variable declaration.
|
||||
newOps.push(ir.createVariableOp(
|
||||
view.job.allocateXrefId(), scope.contextVariables.get(name)!, variable));
|
||||
view.job.allocateXrefId(), scope.contextVariables.get(name)!, variable,
|
||||
/* isConstant */ true));
|
||||
}
|
||||
|
||||
// Add variables for all local references declared for elements in this scope.
|
||||
for (const ref of scope.references) {
|
||||
newOps.push(ir.createVariableOp(
|
||||
view.job.allocateXrefId(), ref.variable, new ir.ReferenceExpr(ref.targetId, ref.offset)));
|
||||
view.job.allocateXrefId(), ref.variable, new ir.ReferenceExpr(ref.targetId, ref.offset),
|
||||
/* isConstant */ true));
|
||||
}
|
||||
|
||||
if (scope.parent !== null) {
|
||||
|
||||
@@ -122,6 +122,8 @@ function reifyCreateOperations(unit: CompilationUnit, ops: ir.OpList<ir.CreateOp
|
||||
if (op.variable.name === null) {
|
||||
throw new Error(`AssertionError: unnamed variable ${op.xref}`);
|
||||
}
|
||||
// Optimization for variable co-location. If we know the initializer is undefined,
|
||||
// we don't need to set an explicit one to avoid e.g. a `let b = undefined`.
|
||||
let initializer: o.Expression|undefined = op.initializer;
|
||||
if (initializer instanceof o.LiteralExpr && initializer.value === undefined) {
|
||||
initializer = undefined;
|
||||
@@ -129,7 +131,8 @@ function reifyCreateOperations(unit: CompilationUnit, ops: ir.OpList<ir.CreateOp
|
||||
ir.OpList.replace<ir.CreateOp>(
|
||||
op,
|
||||
ir.createStatementOp(new o.DeclareVarStmt(
|
||||
op.variable.name, initializer, undefined, o.StmtModifier.Final)));
|
||||
op.variable.name, initializer, undefined,
|
||||
op.isConstant ? o.StmtModifier.Final : undefined)));
|
||||
break;
|
||||
case ir.OpKind.Namespace:
|
||||
switch (op.active) {
|
||||
@@ -280,7 +283,8 @@ function reifyUpdateOperations(_unit: CompilationUnit, ops: ir.OpList<ir.UpdateO
|
||||
ir.OpList.replace<ir.UpdateOp>(
|
||||
op,
|
||||
ir.createStatementOp(new o.DeclareVarStmt(
|
||||
op.variable.name, op.initializer, undefined, o.StmtModifier.Final)));
|
||||
op.variable.name, op.initializer, undefined,
|
||||
op.isConstant ? o.StmtModifier.Final : undefined)));
|
||||
break;
|
||||
case ir.OpKind.Conditional:
|
||||
if (op.processed === null) {
|
||||
|
||||
@@ -19,7 +19,8 @@ export function phaseSaveRestoreView(job: ComponentCompilationJob): void {
|
||||
name: null,
|
||||
view: view.xref,
|
||||
},
|
||||
new ir.GetCurrentViewExpr()),
|
||||
new ir.GetCurrentViewExpr(), /* isConstant */ true),
|
||||
|
||||
]);
|
||||
|
||||
for (const op of view.create) {
|
||||
@@ -56,7 +57,7 @@ function addSaveRestoreViewOperationToListener(unit: ViewCompilationUnit, op: ir
|
||||
name: null,
|
||||
view: unit.xref,
|
||||
},
|
||||
new ir.RestoreViewExpr(unit.xref)),
|
||||
new ir.RestoreViewExpr(unit.xref), /* isConstant */ true),
|
||||
]);
|
||||
|
||||
// The "restore view" operation in listeners requires a call to `resetView` to reset the
|
||||
|
||||
Reference in New Issue
Block a user