feat(compiler): ability to mark an InvokeFunctionExpr as pure (#26860)

Uglify and other tree-shakers attempt to determine if the invocation
of a function is side-effectful, and remove it if so (and the result
is unused). A /*@__PURE__*/ annotation on the call site can be used
to hint to the optimizer that the invocation has no side effects and
is safe to tree-shake away.

This commit adds a 'pure' flag to the output AST function call node,
which can be used to signal to downstream emitters that a pure
annotation should be added. It also modifies ngtsc's emitter to
emit an Uglify pure annotation when this flag is set.

Testing strategy: this will be tested via its consumers, by asserting
that pure functions are translated with the correct comment.

PR Close #26860
This commit is contained in:
Alex Rickabaugh 2018-10-30 10:05:12 -07:00 committed by Matias Niemelä
parent 4e9f2e5895
commit 4dfa71f018
2 changed files with 7 additions and 3 deletions

View File

@ -185,9 +185,13 @@ class ExpressionTranslatorVisitor implements ExpressionVisitor, StatementVisitor
} }
visitInvokeFunctionExpr(ast: InvokeFunctionExpr, context: Context): ts.CallExpression { visitInvokeFunctionExpr(ast: InvokeFunctionExpr, context: Context): ts.CallExpression {
return ts.createCall( const expr = ts.createCall(
ast.fn.visitExpression(this, context), undefined, ast.fn.visitExpression(this, context), undefined,
ast.args.map(arg => arg.visitExpression(this, context))); ast.args.map(arg => arg.visitExpression(this, context)));
if (ast.pure) {
ts.addSyntheticLeadingComment(expr, ts.SyntaxKind.MultiLineCommentTrivia, '@__PURE__', false);
}
return expr;
} }
visitInstantiateExpr(ast: InstantiateExpr, context: Context): ts.NewExpression { visitInstantiateExpr(ast: InstantiateExpr, context: Context): ts.NewExpression {

View File

@ -424,13 +424,13 @@ export class InvokeMethodExpr extends Expression {
export class InvokeFunctionExpr extends Expression { export class InvokeFunctionExpr extends Expression {
constructor( constructor(
public fn: Expression, public args: Expression[], type?: Type|null, public fn: Expression, public args: Expression[], type?: Type|null,
sourceSpan?: ParseSourceSpan|null) { sourceSpan?: ParseSourceSpan|null, public pure = false) {
super(type, sourceSpan); super(type, sourceSpan);
} }
isEquivalent(e: Expression): boolean { isEquivalent(e: Expression): boolean {
return e instanceof InvokeFunctionExpr && this.fn.isEquivalent(e.fn) && return e instanceof InvokeFunctionExpr && this.fn.isEquivalent(e.fn) &&
areAllEquivalent(this.args, e.args); areAllEquivalent(this.args, e.args) && this.pure === e.pure;
} }
isConstant() { return false; } isConstant() { return false; }