Backport Set.of factories
Test: tools/test.py --dex_vm all --no-internal -v *Backport*Test*
Test: tools/test.py --no-internal -v *GenerateBackportMethods*
Change-Id: I7c351021c1bcb420e197f664aeea832d1c5aaeca
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 36e4cc8..9c08a90 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -214,6 +214,7 @@
public final DexString proxyDescriptor = createString("Ljava/lang/reflect/Proxy;");
public final DexString serviceLoaderDescriptor = createString("Ljava/util/ServiceLoader;");
public final DexString listDescriptor = createString("Ljava/util/List;");
+ public final DexString setDescriptor = createString("Ljava/util/Set;");
public final DexString comparatorDescriptor = createString("Ljava/util/Comparator;");
public final DexString callableDescriptor = createString("Ljava/util/concurrent/Callable;");
public final DexString supplierDescriptor = createString("Ljava/util/function/Supplier;");
@@ -302,6 +303,7 @@
public final DexType proxyType = createType(proxyDescriptor);
public final DexType serviceLoaderType = createType(serviceLoaderDescriptor);
public final DexType listType = createType(listDescriptor);
+ public final DexType setType = createType(setDescriptor);
public final DexType comparatorType = createType(comparatorDescriptor);
public final DexType callableType = createType(callableDescriptor);
public final DexType supplierType = createType(supplierDescriptor);
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 0e13782..13c599e 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
@@ -31,9 +31,9 @@
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.desugar.backports.BackportedMethods;
import com.android.tools.r8.ir.desugar.backports.BooleanMethodRewrites;
+import com.android.tools.r8.ir.desugar.backports.CollectionMethodGenerators;
+import com.android.tools.r8.ir.desugar.backports.CollectionMethodRewrites;
import com.android.tools.r8.ir.desugar.backports.FloatMethodRewrites;
-import com.android.tools.r8.ir.desugar.backports.ListMethodGenerators;
-import com.android.tools.r8.ir.desugar.backports.ListMethodRewrites;
import com.android.tools.r8.ir.desugar.backports.LongMethodRewrites;
import com.android.tools.r8.ir.desugar.backports.NumericMethodRewrites;
import com.android.tools.r8.ir.desugar.backports.ObjectsMethodRewrites;
@@ -1003,15 +1003,38 @@
method = factory.createMethod(type, proto, name);
addProvider(
i == 0
- ? new InvokeRewriter(method, ListMethodRewrites::rewriteEmptyOf)
+ ? new InvokeRewriter(method, CollectionMethodRewrites::rewriteListOfEmpty)
: new MethodGenerator(
method,
(options, methodArg, ignored) ->
- ListMethodGenerators.generateListOf(options, methodArg, formalCount)));
+ CollectionMethodGenerators.generateListOf(options, methodArg, formalCount)));
}
proto = factory.createProto(factory.listType, factory.objectArrayType);
method = factory.createMethod(type, proto, name);
- addProvider(new MethodGenerator(method, BackportedMethods::ListMethods_ofArray, "ofArray"));
+ addProvider(
+ new MethodGenerator(
+ method, BackportedMethods::CollectionMethods_listOfArray, "ofArray"));
+
+ // Set<E> Set.of(<args>) for 0 to 10 arguments and Set.of(E[])
+ type = factory.setType;
+ name = factory.createString("of");
+ for (int i = 0; i <= 10; i++) {
+ final int formalCount = i;
+ proto = factory.createProto(factory.setType, Collections.nCopies(i, factory.objectType));
+ method = factory.createMethod(type, proto, name);
+ addProvider(
+ i == 0
+ ? new InvokeRewriter(method, CollectionMethodRewrites::rewriteSetOfEmpty)
+ : new MethodGenerator(
+ method,
+ (options, methodArg, ignored) ->
+ CollectionMethodGenerators.generateSetOf(options, methodArg, formalCount)));
+ }
+ proto = factory.createProto(factory.setType, factory.objectArrayType);
+ method = factory.createMethod(type, proto, name);
+ addProvider(
+ new MethodGenerator(
+ method, BackportedMethods::CollectionMethods_setOfArray, "ofArray"));
}
private void initializeJava11MethodProviders(DexItemFactory factory) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
index fb025c9..5d81f7b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
@@ -518,6 +518,229 @@
ImmutableList.of());
}
+ public static CfCode CollectionMethods_listOfArray(
+ InternalOptions options, DexMethod method, String name) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ CfLabel label4 = new CfLabel();
+ CfLabel label5 = new CfLabel();
+ CfLabel label6 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 3,
+ 6,
+ ImmutableList.of(
+ label0,
+ new CfNew(options.itemFactory.createType("Ljava/util/ArrayList;")),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfArrayLength(),
+ new CfInvoke(
+ 183,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/ArrayList;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("V"), options.itemFactory.createType("I")),
+ options.itemFactory.createString("<init>")),
+ false),
+ new CfStore(ValueType.OBJECT, 1),
+ label1,
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfStore(ValueType.OBJECT, 2),
+ new CfLoad(ValueType.OBJECT, 2),
+ new CfArrayLength(),
+ new CfStore(ValueType.INT, 3),
+ new CfConstNumber(0, ValueType.INT),
+ new CfStore(ValueType.INT, 4),
+ label2,
+ new CfLoad(ValueType.INT, 4),
+ new CfLoad(ValueType.INT, 3),
+ new CfIfCmp(If.Type.GE, ValueType.INT, label5),
+ new CfLoad(ValueType.OBJECT, 2),
+ new CfLoad(ValueType.INT, 4),
+ new CfArrayLoad(MemberType.OBJECT),
+ new CfStore(ValueType.OBJECT, 5),
+ label3,
+ new CfLoad(ValueType.OBJECT, 1),
+ new CfLoad(ValueType.OBJECT, 5),
+ new CfInvoke(
+ 184,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Objects;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/lang/Object;"),
+ options.itemFactory.createType("Ljava/lang/Object;")),
+ options.itemFactory.createString("requireNonNull")),
+ false),
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/ArrayList;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Z"),
+ options.itemFactory.createType("Ljava/lang/Object;")),
+ options.itemFactory.createString("add")),
+ false),
+ new CfStackInstruction(CfStackInstruction.Opcode.Pop),
+ label4,
+ new CfIinc(4, 1),
+ new CfGoto(label2),
+ label5,
+ new CfLoad(ValueType.OBJECT, 1),
+ new CfInvoke(
+ 184,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Collections;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/util/List;"),
+ options.itemFactory.createType("Ljava/util/List;")),
+ options.itemFactory.createString("unmodifiableList")),
+ false),
+ new CfReturn(ValueType.OBJECT),
+ label6),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
+ public static CfCode CollectionMethods_setOfArray(
+ InternalOptions options, DexMethod method, String name) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ CfLabel label4 = new CfLabel();
+ CfLabel label5 = new CfLabel();
+ CfLabel label6 = new CfLabel();
+ CfLabel label7 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 4,
+ 6,
+ ImmutableList.of(
+ label0,
+ new CfNew(options.itemFactory.createType("Ljava/util/HashSet;")),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfArrayLength(),
+ new CfInvoke(
+ 183,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/HashSet;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("V"), options.itemFactory.createType("I")),
+ options.itemFactory.createString("<init>")),
+ false),
+ new CfStore(ValueType.OBJECT, 1),
+ label1,
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfStore(ValueType.OBJECT, 2),
+ new CfLoad(ValueType.OBJECT, 2),
+ new CfArrayLength(),
+ new CfStore(ValueType.INT, 3),
+ new CfConstNumber(0, ValueType.INT),
+ new CfStore(ValueType.INT, 4),
+ label2,
+ new CfLoad(ValueType.INT, 4),
+ new CfLoad(ValueType.INT, 3),
+ new CfIfCmp(If.Type.GE, ValueType.INT, label6),
+ new CfLoad(ValueType.OBJECT, 2),
+ new CfLoad(ValueType.INT, 4),
+ new CfArrayLoad(MemberType.OBJECT),
+ new CfStore(ValueType.OBJECT, 5),
+ label3,
+ new CfLoad(ValueType.OBJECT, 1),
+ new CfLoad(ValueType.OBJECT, 5),
+ new CfInvoke(
+ 184,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Objects;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/lang/Object;"),
+ options.itemFactory.createType("Ljava/lang/Object;")),
+ options.itemFactory.createString("requireNonNull")),
+ false),
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/HashSet;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Z"),
+ options.itemFactory.createType("Ljava/lang/Object;")),
+ options.itemFactory.createString("add")),
+ false),
+ new CfIf(If.Type.NE, ValueType.INT, label5),
+ label4,
+ new CfNew(options.itemFactory.createType("Ljava/lang/IllegalArgumentException;")),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfNew(options.itemFactory.createType("Ljava/lang/StringBuilder;")),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfInvoke(
+ 183,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/lang/StringBuilder;"),
+ options.itemFactory.createProto(options.itemFactory.createType("V")),
+ options.itemFactory.createString("<init>")),
+ false),
+ new CfConstString(options.itemFactory.createString("duplicate element: ")),
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/lang/StringBuilder;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/lang/StringBuilder;"),
+ options.itemFactory.createType("Ljava/lang/String;")),
+ options.itemFactory.createString("append")),
+ false),
+ new CfLoad(ValueType.OBJECT, 5),
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/lang/StringBuilder;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/lang/StringBuilder;"),
+ options.itemFactory.createType("Ljava/lang/Object;")),
+ options.itemFactory.createString("append")),
+ false),
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/lang/StringBuilder;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/lang/String;")),
+ options.itemFactory.createString("toString")),
+ false),
+ new CfInvoke(
+ 183,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/lang/IllegalArgumentException;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("V"),
+ options.itemFactory.createType("Ljava/lang/String;")),
+ options.itemFactory.createString("<init>")),
+ false),
+ new CfThrow(),
+ label5,
+ new CfIinc(4, 1),
+ new CfGoto(label2),
+ label6,
+ new CfLoad(ValueType.OBJECT, 1),
+ new CfInvoke(
+ 184,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Collections;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/util/Set;"),
+ options.itemFactory.createType("Ljava/util/Set;")),
+ options.itemFactory.createString("unmodifiableSet")),
+ false),
+ new CfReturn(ValueType.OBJECT),
+ label7),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
public static CfCode CollectionsMethods_emptyEnumeration(
InternalOptions options, DexMethod method, String name) {
CfLabel label0 = new CfLabel();
@@ -1142,91 +1365,6 @@
ImmutableList.of());
}
- public static CfCode ListMethods_ofArray(InternalOptions options, DexMethod method, String name) {
- CfLabel label0 = new CfLabel();
- CfLabel label1 = new CfLabel();
- CfLabel label2 = new CfLabel();
- CfLabel label3 = new CfLabel();
- CfLabel label4 = new CfLabel();
- CfLabel label5 = new CfLabel();
- CfLabel label6 = new CfLabel();
- return new CfCode(
- method.holder,
- 3,
- 6,
- ImmutableList.of(
- label0,
- new CfNew(options.itemFactory.createType("Ljava/util/ArrayList;")),
- new CfStackInstruction(CfStackInstruction.Opcode.Dup),
- new CfLoad(ValueType.OBJECT, 0),
- new CfArrayLength(),
- new CfInvoke(
- 183,
- options.itemFactory.createMethod(
- options.itemFactory.createType("Ljava/util/ArrayList;"),
- options.itemFactory.createProto(
- options.itemFactory.createType("V"), options.itemFactory.createType("I")),
- options.itemFactory.createString("<init>")),
- false),
- new CfStore(ValueType.OBJECT, 1),
- label1,
- new CfLoad(ValueType.OBJECT, 0),
- new CfStore(ValueType.OBJECT, 2),
- new CfLoad(ValueType.OBJECT, 2),
- new CfArrayLength(),
- new CfStore(ValueType.INT, 3),
- new CfConstNumber(0, ValueType.INT),
- new CfStore(ValueType.INT, 4),
- label2,
- new CfLoad(ValueType.INT, 4),
- new CfLoad(ValueType.INT, 3),
- new CfIfCmp(If.Type.GE, ValueType.INT, label5),
- new CfLoad(ValueType.OBJECT, 2),
- new CfLoad(ValueType.INT, 4),
- new CfArrayLoad(MemberType.OBJECT),
- new CfStore(ValueType.OBJECT, 5),
- label3,
- new CfLoad(ValueType.OBJECT, 1),
- new CfLoad(ValueType.OBJECT, 5),
- new CfInvoke(
- 184,
- options.itemFactory.createMethod(
- options.itemFactory.createType("Ljava/util/Objects;"),
- options.itemFactory.createProto(
- options.itemFactory.createType("Ljava/lang/Object;"),
- options.itemFactory.createType("Ljava/lang/Object;")),
- options.itemFactory.createString("requireNonNull")),
- false),
- new CfInvoke(
- 182,
- options.itemFactory.createMethod(
- options.itemFactory.createType("Ljava/util/ArrayList;"),
- options.itemFactory.createProto(
- options.itemFactory.createType("Z"),
- options.itemFactory.createType("Ljava/lang/Object;")),
- options.itemFactory.createString("add")),
- false),
- new CfStackInstruction(CfStackInstruction.Opcode.Pop),
- label4,
- new CfIinc(4, 1),
- new CfGoto(label2),
- label5,
- new CfLoad(ValueType.OBJECT, 1),
- new CfInvoke(
- 184,
- options.itemFactory.createMethod(
- options.itemFactory.createType("Ljava/util/Collections;"),
- options.itemFactory.createProto(
- options.itemFactory.createType("Ljava/util/List;"),
- options.itemFactory.createType("Ljava/util/List;")),
- options.itemFactory.createString("unmodifiableList")),
- false),
- new CfReturn(ValueType.OBJECT),
- label6),
- ImmutableList.of(),
- ImmutableList.of());
- }
-
public static CfCode LongMethods_compareUnsigned(
InternalOptions options, DexMethod method, String name) {
CfLabel label0 = new CfLabel();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/ListMethodGenerators.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/CollectionMethodGenerators.java
similarity index 74%
rename from src/main/java/com/android/tools/r8/ir/desugar/backports/ListMethodGenerators.java
rename to src/main/java/com/android/tools/r8/ir/desugar/backports/CollectionMethodGenerators.java
index 1319752..040e133 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/ListMethodGenerators.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/CollectionMethodGenerators.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.cf.code.CfStackInstruction;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.code.MemberType;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.utils.InternalOptions;
@@ -20,11 +21,20 @@
import com.google.common.collect.ImmutableList.Builder;
import org.objectweb.asm.Opcodes;
-public final class ListMethodGenerators {
+public final class CollectionMethodGenerators {
- private ListMethodGenerators() {}
+ private CollectionMethodGenerators() {}
public static CfCode generateListOf(InternalOptions options, DexMethod method, int formalCount) {
+ return generateFixedMethods(options, method, formalCount, options.itemFactory.listType);
+ }
+
+ public static CfCode generateSetOf(InternalOptions options, DexMethod method, int formalCount) {
+ return generateFixedMethods(options, method, formalCount, options.itemFactory.setType);
+ }
+
+ private static CfCode generateFixedMethods(
+ InternalOptions options, DexMethod method, int formalCount, DexType returnType) {
Builder<CfInstruction> builder = ImmutableList.builder();
builder.add(
new CfConstNumber(formalCount, ValueType.INT),
@@ -42,9 +52,8 @@
new CfInvoke(
Opcodes.INVOKESTATIC,
options.itemFactory.createMethod(
- options.itemFactory.listType,
- options.itemFactory.createProto(
- options.itemFactory.listType, options.itemFactory.objectArrayType),
+ returnType,
+ options.itemFactory.createProto(returnType, options.itemFactory.objectArrayType),
options.itemFactory.createString("of")),
false),
new CfReturn(ValueType.OBJECT));
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/ListMethodRewrites.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/CollectionMethodRewrites.java
similarity index 61%
rename from src/main/java/com/android/tools/r8/ir/desugar/backports/ListMethodRewrites.java
rename to src/main/java/com/android/tools/r8/ir/desugar/backports/CollectionMethodRewrites.java
index c3245d8..ce159be 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/ListMethodRewrites.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/CollectionMethodRewrites.java
@@ -11,16 +11,26 @@
import com.android.tools.r8.ir.code.InvokeStatic;
import java.util.Collections;
-public final class ListMethodRewrites {
+public final class CollectionMethodRewrites {
- private ListMethodRewrites() {}
+ private CollectionMethodRewrites() {}
- public static void rewriteEmptyOf(
+ public static void rewriteListOfEmpty(
InvokeMethod invoke, InstructionListIterator iterator, DexItemFactory factory) {
+ rewriteToCollectionMethod(invoke, iterator, factory, "emptyList");
+ }
+
+ public static void rewriteSetOfEmpty(
+ InvokeMethod invoke, InstructionListIterator iterator, DexItemFactory factory) {
+ rewriteToCollectionMethod(invoke, iterator, factory, "emptySet");
+ }
+
+ private static void rewriteToCollectionMethod(InvokeMethod invoke,
+ InstructionListIterator iterator, DexItemFactory factory, String methodName) {
assert invoke.inValues().isEmpty();
DexMethod collectionsEmptyList =
- factory.createMethod(factory.collectionsType, invoke.getInvokedMethod().proto, "emptyList");
+ factory.createMethod(factory.collectionsType, invoke.getInvokedMethod().proto, methodName);
InvokeStatic newInvoke =
new InvokeStatic(collectionsEmptyList, invoke.outValue(), Collections.emptyList());
iterator.replaceCurrentInstruction(newInvoke);
diff --git a/src/test/examplesJava9/backport/SetBackportJava9Main.java b/src/test/examplesJava9/backport/SetBackportJava9Main.java
new file mode 100644
index 0000000..d824bd0
--- /dev/null
+++ b/src/test/examplesJava9/backport/SetBackportJava9Main.java
@@ -0,0 +1,207 @@
+// 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.Set;
+
+public class SetBackportJava9Main {
+
+ public static void main(String[] args) {
+ testOf0();
+ testOf1();
+ testOf2();
+ testOf10();
+ testOfVarargs();
+ }
+
+ private static void testOf0() {
+ Set<Object> ofObject = Set.of();
+ assertEquals(0, ofObject.size());
+ assertFalse(ofObject.contains(new Object()));
+ assertMutationNotAllowed(ofObject);
+
+ Set<Integer> ofInteger = Set.of();
+ assertEquals(0, ofInteger.size());
+ assertFalse(ofInteger.contains(0));
+ }
+
+ private static void testOf1() {
+ Object anObject = new Object();
+ Set<Object> ofObject = Set.of(anObject);
+ assertEquals(1, ofObject.size());
+ assertTrue(ofObject.contains(anObject));
+ assertFalse(ofObject.contains(new Object()));
+ assertMutationNotAllowed(ofObject);
+
+ Set<Integer> ofInteger = Set.of(1);
+ assertEquals(1, ofInteger.size());
+ assertTrue(ofInteger.contains(1));
+ assertFalse(ofInteger.contains(2));
+
+ try {
+ Set.of((Object) null);
+ throw new AssertionError();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ private static void testOf2() {
+ Object anObject0 = new Object();
+ Object anObject1 = new Object();
+ Set<Object> ofObject = Set.of(anObject0, anObject1);
+ assertEquals(2, ofObject.size());
+ assertTrue(ofObject.contains(anObject0));
+ assertTrue(ofObject.contains(anObject1));
+ assertFalse(ofObject.contains(new Object()));
+ assertMutationNotAllowed(ofObject);
+
+ Set<Integer> ofInteger = Set.of(1, 2);
+ assertEquals(2, ofInteger.size());
+ assertTrue(ofInteger.contains(1));
+ assertTrue(ofInteger.contains(2));
+ assertFalse(ofInteger.contains(3));
+
+ Set<Object> ofMixed = Set.of(anObject0, 1);
+ assertEquals(2, ofMixed.size());
+ assertTrue(ofMixed.contains(anObject0));
+ assertTrue(ofMixed.contains(1));
+ assertFalse(ofMixed.contains(2));
+ assertFalse(ofMixed.contains(anObject1));
+ assertMutationNotAllowed(ofMixed);
+
+ try {
+ Set.of(1, null);
+ throw new AssertionError();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ Set.of(1, 1);
+ throw new AssertionError();
+ } catch (IllegalArgumentException expected) {
+ assertEquals("duplicate element: 1", expected.getMessage());
+ }
+ }
+
+ private static void testOf10() {
+ Object anObject0 = new Object();
+ Object anObject6 = new Object();
+ Object anObject9 = new Object();
+ Set<Object> ofObject =
+ Set.of(anObject0, new Object(), new Object(), new Object(), new Object(), new Object(),
+ anObject6, new Object(), new Object(), anObject9);
+ assertEquals(10, ofObject.size());
+ assertTrue(ofObject.contains(anObject0));
+ assertTrue(ofObject.contains(anObject6));
+ assertTrue(ofObject.contains(anObject9));
+ assertFalse(ofObject.contains(new Object()));
+ assertMutationNotAllowed(ofObject);
+
+ Set<Integer> ofInteger = Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+ assertEquals(10, ofInteger.size());
+ assertTrue(ofInteger.contains(0));
+ assertTrue(ofInteger.contains(6));
+ assertTrue(ofInteger.contains(9));
+ assertFalse(ofInteger.contains(10));
+
+ Set<Object> ofMixed = Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, anObject9);
+ assertEquals(10, ofMixed.size());
+ assertTrue(ofMixed.contains(0));
+ assertTrue(ofMixed.contains(6));
+ assertTrue(ofMixed.contains(anObject9));
+ assertFalse(ofMixed.contains(anObject0));
+ assertMutationNotAllowed(ofMixed);
+
+ try {
+ Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, null);
+ throw new AssertionError();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 0);
+ throw new AssertionError();
+ } catch (IllegalArgumentException expected) {
+ assertEquals("duplicate element: 0", expected.getMessage());
+ }
+ }
+
+ private static void testOfVarargs() {
+ Object anObject0 = new Object();
+ Object anObject6 = new Object();
+ Object anObject10 = new Object();
+ Set<Object> ofObject =
+ Set.of(anObject0, new Object(), new Object(), new Object(), new Object(), new Object(),
+ anObject6, new Object(), new Object(), new Object(), anObject10);
+ assertEquals(11, ofObject.size());
+ assertTrue(ofObject.contains(anObject0));
+ assertTrue(ofObject.contains(anObject6));
+ assertTrue(ofObject.contains(anObject10));
+ assertFalse(ofObject.contains(new Object()));
+ assertMutationNotAllowed(ofObject);
+
+ Set<Integer> ofInteger = Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+ assertEquals(11, ofInteger.size());
+ assertTrue(ofInteger.contains(0));
+ assertTrue(ofInteger.contains(6));
+ assertTrue(ofInteger.contains(10));
+ assertFalse(ofInteger.contains(11));
+
+ Set<Object> ofMixed = Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, anObject10);
+ assertEquals(11, ofMixed.size());
+ assertTrue(ofMixed.contains(0));
+ assertTrue(ofMixed.contains(6));
+ assertTrue(ofMixed.contains(anObject10));
+ assertFalse(ofMixed.contains(10));
+ assertFalse(ofMixed.contains(anObject0));
+ assertMutationNotAllowed(ofMixed);
+
+ // Ensure the supplied mutable array is not used directly since it is mutable.
+ Object[] mutableArray = { anObject0 };
+ Set<Object> ofMutableArray = Set.of(mutableArray);
+ mutableArray[0] = anObject10;
+ assertTrue(ofMutableArray.contains(anObject0));
+ assertFalse(ofMutableArray.contains(anObject10));
+
+ try {
+ Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, null);
+ throw new AssertionError();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
+ throw new AssertionError();
+ } catch (IllegalArgumentException expected) {
+ assertEquals("duplicate element: 0", expected.getMessage());
+ }
+ }
+
+ private static void assertMutationNotAllowed(Set<Object> ofObject) {
+ try {
+ ofObject.add(new Object());
+ throw new AssertionError();
+ } catch (UnsupportedOperationException expected) {
+ }
+ }
+
+ private static void assertTrue(boolean value) {
+ if (!value) {
+ throw new AssertionError("Expected <true> but was <false>");
+ }
+ }
+
+ private static void assertFalse(boolean value) {
+ if (value) {
+ throw new AssertionError("Expected <false> but was <true>");
+ }
+ }
+
+ private static void assertEquals(Object expected, Object actual) {
+ if (expected != actual && !expected.equals(actual)) {
+ throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+ }
+ }
+}
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
index b512634..3ff18bc 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.ToolHelper;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.List;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@@ -29,7 +30,13 @@
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
+ super(parameters, List.class, TEST_JAR, "backport.ListBackportJava9Main");
+ // TODO Once shipped in an actual API level, migrate to ListBackportTest
+
+ // Available since API 1 and used to test created lists.
+ ignoreInvokes("add");
+ ignoreInvokes("get");
+ ignoreInvokes("set");
+ ignoreInvokes("size");
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java
new file mode 100644
index 0000000..b87816e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java
@@ -0,0 +1,41 @@
+// 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 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 java.util.Set;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public class SetBackportJava9Test 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 SetBackportJava9Test(TestParameters parameters) {
+ super(parameters, Set.class, TEST_JAR, "backport.SetBackportJava9Main");
+ // TODO Once shipped in an actual API level, migrate to SetBackportTest
+
+ // Available since API 1 and used to test created sets.
+ ignoreInvokes("add");
+ ignoreInvokes("contains");
+ ignoreInvokes("size");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/CollectionMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/CollectionMethods.java
new file mode 100644
index 0000000..8076224
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/CollectionMethods.java
@@ -0,0 +1,33 @@
+// 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 java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+public class CollectionMethods {
+
+ public static <E> List<E> listOfArray(E[] elements) {
+ ArrayList<E> list = new ArrayList<>(elements.length);
+ for (E element : elements) {
+ list.add(Objects.requireNonNull(element));
+ }
+ return Collections.unmodifiableList(list);
+ }
+
+ public static <E> Set<E> setOfArray(E[] elements) {
+ HashSet<E> set = new HashSet<>(elements.length);
+ for (E element : elements) {
+ if (!set.add(Objects.requireNonNull(element))) {
+ throw new IllegalArgumentException("duplicate element: " + element);
+ }
+ }
+ return Collections.unmodifiableSet(set);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/GenerateBackportMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/GenerateBackportMethods.java
index 2bb7dc3..e210196 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/backports/GenerateBackportMethods.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/GenerateBackportMethods.java
@@ -29,6 +29,7 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -73,11 +74,11 @@
ByteMethods.class,
CharacterMethods.class,
CloseResourceMethod.class,
+ CollectionMethods.class,
CollectionsMethods.class,
DoubleMethods.class,
FloatMethods.class,
IntegerMethods.class,
- ListMethods.class,
LongMethods.class,
MathMethods.class,
ObjectsMethods.class,
@@ -99,7 +100,7 @@
@Test
public void test() throws Exception {
ArrayList<Class<?>> sorted = new ArrayList<>(methodTemplateClasses);
- sorted.sort((a, b) -> a.getTypeName().compareTo(b.getTypeName()));
+ sorted.sort(Comparator.comparing(Class::getTypeName));
assertEquals("Classes should be listed in sorted order", sorted, methodTemplateClasses);
assertEquals(
FileUtils.readTextFile(backportMethodsFile, StandardCharsets.UTF_8),
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/ListMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/ListMethods.java
deleted file mode 100644
index 7d74919..0000000
--- a/src/test/java/com/android/tools/r8/ir/desugar/backports/ListMethods.java
+++ /dev/null
@@ -1,23 +0,0 @@
-// 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 java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-public class ListMethods {
-
- public static <E> List<E> ofArray(E[] elements) {
- // TODO(140709356): The other overloads should call into this method to ensure consistent
- // behavior, but we cannot link against List.of(E[]) because it's only available in Java 9.
- ArrayList<E> list = new ArrayList<>(elements.length);
- for (E element : elements) {
- list.add(Objects.requireNonNull(element));
- }
- return Collections.unmodifiableList(list);
- }
-}