Desugaring of List.of

Bug: 134732760
Change-Id: I74aa0df81db77241fdbfdbecc164f468d0728a71
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 50c343e..726efc4 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -1215,6 +1215,10 @@
         parameters.length == 0 ? DexTypeList.empty() : new DexTypeList(parameters));
   }
 
+  public DexProto createProto(DexType returnType, List<DexType> parameters) {
+    return createProto(returnType, parameters.toArray(DexType.EMPTY_ARRAY));
+  }
+
   public DexProto protoWithDifferentFirstParameter(DexProto proto, DexType firstParameter) {
     DexType[] parameterTypes = proto.parameters.values.clone();
     parameterTypes[0] = firstParameter;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index 6a5030e..c74391d 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -35,6 +35,7 @@
 import com.android.tools.r8.ir.desugar.backports.DoubleMethods;
 import com.android.tools.r8.ir.desugar.backports.FloatMethods;
 import com.android.tools.r8.ir.desugar.backports.IntegerMethods;
+import com.android.tools.r8.ir.desugar.backports.ListMethods;
 import com.android.tools.r8.ir.desugar.backports.LongMethods;
 import com.android.tools.r8.ir.desugar.backports.MathMethods;
 import com.android.tools.r8.ir.desugar.backports.ObjectsMethods;
@@ -825,6 +826,18 @@
       proto =
           factory.createProto(factory.intType, factory.intType, factory.intType, factory.intType);
       addProvider(new MethodGenerator(clazz, method, proto, ObjectsMethods::new));
+
+      // List of
+      clazz = factory.listDescriptor;
+      method = factory.createString("of");
+
+      // From 0 to 10 arguments.
+      ArrayList<DexType> parameters = new ArrayList<>();
+      for (int i = 0; i <= 10; i++) {
+        proto = factory.createProto(factory.listType, parameters);
+        addProvider(new MethodGenerator(clazz, method, proto, ListMethods::new));
+        parameters.add(factory.objectType);
+      }
     }
 
     private void initializeJava11MethodProviders(DexItemFactory factory) {
@@ -992,6 +1005,8 @@
           UTILITY_CLASS_DESCRIPTOR_PREFIX
               + '$'
               + unqualifiedName
+              + '$'
+              + proto.parameters.size()
               + coreLibUtilitySuffix
               + '$'
               + methodName
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/ListMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/ListMethods.java
new file mode 100644
index 0000000..87f2a62
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/ListMethods.java
@@ -0,0 +1,67 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.desugar.backports;
+
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.ir.synthetic.TemplateMethodCode;
+import com.android.tools.r8.utils.InternalOptions;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class ListMethods extends TemplateMethodCode {
+
+  public ListMethods(InternalOptions options, DexMethod method, String methodName) {
+    super(options, method, methodName, method.proto.toDescriptorString());
+  }
+
+  public static <E> List<E> of() {
+    return Collections.emptyList();
+  }
+
+  public static <E> List<E> of(E e0) {
+    return Collections.singletonList(e0);
+  }
+
+  public static <E> List<E> of(E e0, E e1) {
+    return Collections.unmodifiableList(Arrays.asList(e0, e1));
+  }
+
+  public static <E> List<E> of(E e0, E e1, E e2) {
+    return Collections.unmodifiableList(Arrays.asList(e0, e1, e2));
+  }
+
+  public static <E> List<E> of(E e0, E e1, E e2, E e3) {
+    return Collections.unmodifiableList(Arrays.asList(e0, e1, e2, e3));
+  }
+
+  public static <E> List<E> of(E e0, E e1, E e2, E e3, E e4) {
+    return Collections.unmodifiableList(Arrays.asList(e0, e1, e2, e3, e4));
+  }
+
+  public static <E> List<E> of(E e0, E e1, E e2, E e3, E e4, E e5) {
+    return Collections.unmodifiableList(Arrays.asList(e0, e1, e2, e3, e4, e5));
+  }
+
+  public static <E> List<E> of(E e0, E e1, E e2, E e3, E e4, E e5, E e6) {
+    return Collections.unmodifiableList(Arrays.asList(e0, e1, e2, e3, e4, e5, e6));
+  }
+
+  public static <E> List<E> of(E e0, E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
+    return Collections.unmodifiableList(Arrays.asList(e0, e1, e2, e3, e4, e5, e6, e7));
+  }
+
+  public static <E> List<E> of(E e0, E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
+    return Collections.unmodifiableList(Arrays.asList(e0, e1, e2, e3, e4, e5, e6, e7, e8));
+  }
+
+  public static <E> List<E> of(E e0, E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
+    return Collections.unmodifiableList(Arrays.asList(e0, e1, e2, e3, e4, e5, e6, e7, e8, e9));
+  }
+
+  public static <E> List<E> of(E e0, E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
+    return Collections.unmodifiableList(Arrays.asList(e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10));
+  }
+}
diff --git a/src/test/examplesJava9/backport/ListBackportJava9Main.java b/src/test/examplesJava9/backport/ListBackportJava9Main.java
new file mode 100644
index 0000000..9ad147f
--- /dev/null
+++ b/src/test/examplesJava9/backport/ListBackportJava9Main.java
@@ -0,0 +1,66 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package backport;
+
+import java.util.List;
+
+public class ListBackportJava9Main {
+
+  public static void main(String[] args) throws Exception {
+    testOf0();
+    testOf1();
+    testOf2();
+    testOf10();
+  }
+
+  private static void testOf0() {
+    List<Object> ofObject = List.of();
+    List<Integer> ofInteger = List.of();
+    assertTrue(ofObject instanceof List);
+    assertTrue(ofObject.size() == 0);
+    assertTrue(ofInteger instanceof List);
+    assertTrue(ofInteger.size() == 0);
+  }
+
+  private static void testOf1() {
+    List<Object> ofObject = List.of(new Object());
+    List<Integer> ofInteger = List.of(1);
+    assertTrue(ofObject instanceof List);
+    assertTrue(ofObject.size() == 1);
+    assertTrue(ofInteger instanceof List);
+    assertTrue(ofInteger.size() == 1);
+  }
+
+  private static void testOf2() {
+    List<Object> ofObject = List.of(new Object(), new Object());
+    List<Integer> ofInteger = List.of(1, 2);
+    List<Object> ofMixed = List.of(new Object(), 1);
+    assertTrue(ofObject instanceof List);
+    assertTrue(ofObject.size() == 2);
+    assertTrue(ofInteger instanceof List);
+    assertTrue(ofInteger.size() == 2);
+    assertTrue(ofMixed instanceof List);
+    assertTrue(ofMixed.size() == 2);
+  }
+
+  private static void testOf10() {
+    Object e = new Object();
+    List<Object> ofObject = List.of(e, e, e, e, e, e, e, e, e, e);
+    List<Integer> ofInteger = List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+    List<Object> ofMixed = List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, e);
+    assertTrue(ofObject instanceof List);
+    assertTrue(ofObject.size() == 10);
+    assertTrue(ofInteger instanceof List);
+    assertTrue(ofInteger.size() == 10);
+    assertTrue(ofMixed instanceof List);
+    assertTrue(ofMixed.size() == 10);
+  }
+
+  private static void assertTrue(boolean value) {
+    if (!value) {
+      throw new AssertionError("Expected <true> but was <false>");
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java
new file mode 100644
index 0000000..b512634
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java
@@ -0,0 +1,35 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugar.backports;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ListBackportJava9Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+        .withDexRuntimes()
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public ListBackportJava9Test(TestParameters parameters) {
+    super(parameters, Byte.class, TEST_JAR, "backport.ListBackportJava9Main");
+    // TODO Once shipped in an actual API level, migrate to ByteBackportTest
+  }
+}