diff --git a/transpiler/java/com/google/j2cl/transpiler/passes/NormalizeArrayLiterals.java b/transpiler/java/com/google/j2cl/transpiler/passes/NormalizeArrayLiterals.java index efa6d96877..d04cf9a096 100644 --- a/transpiler/java/com/google/j2cl/transpiler/passes/NormalizeArrayLiterals.java +++ b/transpiler/java/com/google/j2cl/transpiler/passes/NormalizeArrayLiterals.java @@ -18,13 +18,22 @@ import com.google.j2cl.transpiler.ast.AbstractRewriter; import com.google.j2cl.transpiler.ast.ArrayLiteral; import com.google.j2cl.transpiler.ast.AstUtils; +import com.google.j2cl.transpiler.ast.Expression; import com.google.j2cl.transpiler.ast.NewArray; import com.google.j2cl.transpiler.ast.Node; +import com.google.j2cl.transpiler.ast.NullLiteral; +import com.google.j2cl.transpiler.ast.NumberLiteral; +import com.google.j2cl.transpiler.ast.PrefixExpression; +import com.google.j2cl.transpiler.ast.PrefixOperator; import com.google.j2cl.transpiler.ast.Type; +import java.util.List; /** * Rewrites the rare short form array literal initializers (like "int[] foo = {1, 2, 3};") into the * more common long form (like "int[] foo = new int[] {1, 2, 3};"). + * + *

Remove spread operator on an Array present in an array initializer: `new int[] {...new int[] + * {1,2,3}} -> new int[] {1,2,3} */ public class NormalizeArrayLiterals extends NormalizationPass { @@ -49,5 +58,68 @@ public Node rewriteArrayLiteral(ArrayLiteral arrayLiteral) { .build(); } }); + + // Remove spread operator on an Array inside an ArrayLiteral: + // `new int[] {...new int[] {1,2,3}} -> new int[] {1,2,3} + type.accept( + new AbstractRewriter() { + @Override + public Node rewriteNewArray(NewArray newArray) { + if (!(newArray.getInitializer() instanceof ArrayLiteral)) { + return newArray; + } + + ArrayLiteral arrayLiteral = (ArrayLiteral) newArray.getInitializer(); + if (arrayLiteral.getValueExpressions().size() != 1) { + // we only support the case where the spread operation is the only element of the + // array initializer. + return newArray; + } + + Expression uniqueElement = arrayLiteral.getValueExpressions().get(0); + if (!isRedundantSpreadOperator(uniqueElement)) { + // The element is not on the form `...new int[] {1,2,3}` + return newArray; + } + + return ((PrefixExpression) uniqueElement).getOperand(); + } + }); + } + + private static boolean isRedundantSpreadOperator(Expression expression) { + if (!(expression instanceof PrefixExpression)) { + return false; + } + + PrefixExpression prefixExpression = (PrefixExpression) expression; + + if (prefixExpression.getOperator() != PrefixOperator.SPREAD) { + return false; + } + + if (!(prefixExpression.getOperand() instanceof NewArray)) { + return false; + } + + NewArray newArrayExpression = (NewArray) prefixExpression.getOperand(); + + if (newArrayExpression.getInitializer() instanceof ArrayLiteral) { + // Spread operation is redundant on new int[] {1,2,..} + return true; + } + + List dimensions = newArrayExpression.getDimensionExpressions(); + + // Spread operation is redundant on new Foo[0] or new Foo[0][][] + return newArrayExpression.getInitializer() == null + && !dimensions.isEmpty() + && dimensions.get(0) instanceof NumberLiteral + && ((NumberLiteral) dimensions.get(0)).getValue().intValue() == 0 + && isAllNullLiterals(dimensions.subList(1, dimensions.size())); + } + + private static boolean isAllNullLiterals(List expressions) { + return expressions.stream().allMatch(e -> e instanceof NullLiteral); } }