Backport Optional/OptionalInt/OptionalLong/OptionalDouble.orElseThrow()
Test: tools/test.py --dex_vm all --no-internal -v *Backport*Test*
Test: tools/test.py --no-internal -v *GenerateBackportMethods*
Change-Id: I6b1e9c09f033c4a1fe95c939fdef02095ef8d5a1
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 faad0e6..5d85611 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -230,6 +230,9 @@
public final DexString consumerDescriptor = createString("Ljava/util/function/Consumer;");
public final DexString runnableDescriptor = createString("Ljava/lang/Runnable;");
public final DexString optionalDescriptor = createString("Ljava/util/Optional;");
+ public final DexString optionalDoubleDescriptor = createString("Ljava/util/OptionalDouble;");
+ public final DexString optionalIntDescriptor = createString("Ljava/util/OptionalInt;");
+ public final DexString optionalLongDescriptor = createString("Ljava/util/OptionalLong;");
public final DexString streamDescriptor = createString("Ljava/util/stream/Stream;");
public final DexString arraysDescriptor = createString("Ljava/util/Arrays;");
@@ -328,6 +331,9 @@
public final DexType consumerType = createType(consumerDescriptor);
public final DexType runnableType = createType(runnableDescriptor);
public final DexType optionalType = createType(optionalDescriptor);
+ public final DexType optionalDoubleType = createType(optionalDoubleDescriptor);
+ public final DexType optionalIntType = createType(optionalIntDescriptor);
+ public final DexType optionalLongType = createType(optionalLongDescriptor);
public final DexType streamType = createType(streamDescriptor);
public final DexType runtimeExceptionType = createType(runtimeExceptionDescriptor);
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 424604f..d6650ab 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
@@ -40,6 +40,7 @@
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;
+import com.android.tools.r8.ir.desugar.backports.OptionalMethodRewrites;
import com.android.tools.r8.origin.SynthesizedOrigin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions;
@@ -504,7 +505,8 @@
// we do not desugar to avoid confusion in error messages.
if (appView.rewritePrefix.hasRewrittenType(factory.optionalType)
|| options.minApiLevel >= AndroidApiLevel.N.getLevel()) {
- initializeOptionalMethodProviders(factory);
+ initializeJava9OptionalMethodProviders(factory);
+ initializeJava10OptionalMethodProviders(factory);
}
if (appView.rewritePrefix.hasRewrittenType(factory.streamType)
|| options.minApiLevel >= AndroidApiLevel.N.getLevel()) {
@@ -1416,7 +1418,7 @@
method, BackportedMethods::CharacterMethods_toStringCodepoint, "toStringCodepoint"));
}
- private void initializeOptionalMethodProviders(DexItemFactory factory) {
+ private void initializeJava9OptionalMethodProviders(DexItemFactory factory) {
// Optional
DexType optionalType = factory.optionalType;
@@ -1432,9 +1434,9 @@
DexType[] optionalTypes =
new DexType[] {
optionalType,
- factory.createType(factory.createString("Ljava/util/OptionalDouble;")),
- factory.createType(factory.createString("Ljava/util/OptionalLong;")),
- factory.createType(factory.createString("Ljava/util/OptionalInt;")),
+ factory.optionalDoubleType,
+ factory.optionalLongType,
+ factory.optionalIntType,
};
DexType[] streamReturnTypes =
new DexType[] {
@@ -1487,6 +1489,37 @@
}
}
+ private void initializeJava10OptionalMethodProviders(DexItemFactory factory) {
+ // Optional{void,Int,Long,Double}.orElseThrow()
+ DexType[] optionalTypes =
+ new DexType[] {
+ factory.optionalType,
+ factory.optionalDoubleType,
+ factory.optionalLongType,
+ factory.optionalIntType,
+ };
+ DexType[] returnTypes =
+ new DexType[] {
+ factory.objectType,
+ factory.doubleType,
+ factory.longType,
+ factory.intType,
+ };
+ MethodInvokeRewriter[] rewriters =
+ new MethodInvokeRewriter[] {
+ OptionalMethodRewrites::rewriteOrElseGet,
+ OptionalMethodRewrites::rewriteDoubleOrElseGet,
+ OptionalMethodRewrites::rewriteLongOrElseGet,
+ OptionalMethodRewrites::rewriteIntOrElseGet,
+ };
+ DexString name = factory.createString("orElseThrow");
+ for (int i = 0; i < optionalTypes.length; i++) {
+ DexProto proto = factory.createProto(returnTypes[i]);
+ DexMethod method = factory.createMethod(optionalTypes[i], proto, name);
+ addProvider(new InvokeRewriter(method, rewriters[i]));
+ }
+ }
+
private void initializeStreamMethodProviders(DexItemFactory factory) {
// Stream
DexType streamType = factory.streamType;
@@ -1497,7 +1530,7 @@
DexMethod method = factory.createMethod(streamType, proto, name);
addProvider(
new MethodGenerator(
- method, BackportedMethods::StreamMethods_ofNullable, "ofNullable") {});
+ method, BackportedMethods::StreamMethods_ofNullable, "ofNullable"));
}
private void warnMissingRetargetCoreLibraryMember(DexType type, AppView<?> appView) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/OptionalMethodRewrites.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/OptionalMethodRewrites.java
new file mode 100644
index 0000000..7965b0b
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/OptionalMethodRewrites.java
@@ -0,0 +1,47 @@
+// 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.DexItemFactory;
+import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.InvokeVirtual;
+
+public final class OptionalMethodRewrites {
+
+ private OptionalMethodRewrites() {}
+
+ public static void rewriteOrElseGet(
+ InvokeMethod invoke, InstructionListIterator iterator, DexItemFactory factory) {
+ InvokeVirtual getInvoke = new InvokeVirtual(
+ factory.createMethod(factory.optionalType, invoke.getInvokedMethod().proto,
+ "get"), invoke.outValue(), invoke.inValues());
+ iterator.replaceCurrentInstruction(getInvoke);
+ }
+
+ public static void rewriteDoubleOrElseGet(
+ InvokeMethod invoke, InstructionListIterator iterator, DexItemFactory factory) {
+ InvokeVirtual getInvoke = new InvokeVirtual(
+ factory.createMethod(factory.optionalDoubleType, invoke.getInvokedMethod().proto,
+ "getAsDouble"), invoke.outValue(), invoke.inValues());
+ iterator.replaceCurrentInstruction(getInvoke);
+ }
+
+ public static void rewriteIntOrElseGet(
+ InvokeMethod invoke, InstructionListIterator iterator, DexItemFactory factory) {
+ InvokeVirtual getInvoke = new InvokeVirtual(
+ factory.createMethod(factory.optionalIntType, invoke.getInvokedMethod().proto,
+ "getAsInt"), invoke.outValue(), invoke.inValues());
+ iterator.replaceCurrentInstruction(getInvoke);
+ }
+
+ public static void rewriteLongOrElseGet(
+ InvokeMethod invoke, InstructionListIterator iterator, DexItemFactory factory) {
+ InvokeVirtual getInvoke = new InvokeVirtual(
+ factory.createMethod(factory.optionalLongType, invoke.getInvokedMethod().proto,
+ "getAsLong"), invoke.outValue(), invoke.inValues());
+ iterator.replaceCurrentInstruction(getInvoke);
+ }
+}
diff --git a/src/test/examplesJava10/backport/OptionalBackportJava10Main.java b/src/test/examplesJava10/backport/OptionalBackportJava10Main.java
new file mode 100644
index 0000000..3d2c919
--- /dev/null
+++ b/src/test/examplesJava10/backport/OptionalBackportJava10Main.java
@@ -0,0 +1,32 @@
+// 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.NoSuchElementException;
+import java.util.Optional;
+
+public final class OptionalBackportJava10Main {
+
+ public static void main(String[] args) {
+ testOrElseThrow();
+ }
+
+ private static void testOrElseThrow() {
+ Optional<String> present = Optional.of("hey");
+ assertEquals("hey", present.orElseThrow());
+
+ Optional<String> absent = Optional.empty();
+ try {
+ throw new AssertionError(absent.orElseThrow());
+ } catch (NoSuchElementException expected) {
+ }
+ }
+
+ 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/examplesJava10/backport/OptionalDoubleBackportJava10Main.java b/src/test/examplesJava10/backport/OptionalDoubleBackportJava10Main.java
new file mode 100644
index 0000000..1c27538
--- /dev/null
+++ b/src/test/examplesJava10/backport/OptionalDoubleBackportJava10Main.java
@@ -0,0 +1,32 @@
+// 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.NoSuchElementException;
+import java.util.OptionalDouble;
+
+public final class OptionalDoubleBackportJava10Main {
+
+ public static void main(String[] args) {
+ testOrElseThrow();
+ }
+
+ private static void testOrElseThrow() {
+ OptionalDouble present = OptionalDouble.of(2d);
+ assertEquals(2d, present.orElseThrow());
+
+ OptionalDouble absent = OptionalDouble.empty();
+ try {
+ throw new AssertionError(absent.orElseThrow());
+ } catch (NoSuchElementException expected) {
+ }
+ }
+
+ 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/examplesJava10/backport/OptionalIntBackportJava10Main.java b/src/test/examplesJava10/backport/OptionalIntBackportJava10Main.java
new file mode 100644
index 0000000..06c85f5
--- /dev/null
+++ b/src/test/examplesJava10/backport/OptionalIntBackportJava10Main.java
@@ -0,0 +1,32 @@
+// 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.NoSuchElementException;
+import java.util.OptionalInt;
+
+public final class OptionalIntBackportJava10Main {
+
+ public static void main(String[] args) {
+ testOrElseThrow();
+ }
+
+ private static void testOrElseThrow() {
+ OptionalInt present = OptionalInt.of(2);
+ assertEquals(2, present.orElseThrow());
+
+ OptionalInt absent = OptionalInt.empty();
+ try {
+ throw new AssertionError(absent.orElseThrow());
+ } catch (NoSuchElementException expected) {
+ }
+ }
+
+ 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/examplesJava10/backport/OptionalLongBackportJava10Main.java b/src/test/examplesJava10/backport/OptionalLongBackportJava10Main.java
new file mode 100644
index 0000000..e92b9a5
--- /dev/null
+++ b/src/test/examplesJava10/backport/OptionalLongBackportJava10Main.java
@@ -0,0 +1,32 @@
+// 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.NoSuchElementException;
+import java.util.OptionalLong;
+
+public final class OptionalLongBackportJava10Main {
+
+ public static void main(String[] args) {
+ testOrElseThrow();
+ }
+
+ private static void testOrElseThrow() {
+ OptionalLong present = OptionalLong.of(2L);
+ assertEquals(2L, present.orElseThrow());
+
+ OptionalLong absent = OptionalLong.empty();
+ try {
+ throw new AssertionError(absent.orElseThrow());
+ } catch (NoSuchElementException expected) {
+ }
+ }
+
+ 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/OptionalBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava10Test.java
new file mode 100644
index 0000000..25d4081
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava10Test.java
@@ -0,0 +1,45 @@
+// 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 com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+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 final class OptionalBackportJava10Test extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+ .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK10)
+ .build();
+ }
+
+ private static final Path TEST_JAR =
+ Paths.get(ToolHelper.EXAMPLES_JAVA10_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+ public OptionalBackportJava10Test(TestParameters parameters) {
+ super(parameters, Optional.class, TEST_JAR, "backport.OptionalBackportJava10Main");
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to OptionalBackportTest.
+
+ // Available since N as part of library desugaring.
+ ignoreInvokes("empty");
+ ignoreInvokes("get");
+ ignoreInvokes("of");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava10Test.java
new file mode 100644
index 0000000..97d70df
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava10Test.java
@@ -0,0 +1,46 @@
+// 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 com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+import java.util.OptionalDouble;
+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 final class OptionalDoubleBackportJava10Test extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+ .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK10)
+ .build();
+ }
+
+ private static final Path TEST_JAR =
+ Paths.get(ToolHelper.EXAMPLES_JAVA10_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+ public OptionalDoubleBackportJava10Test(TestParameters parameters) {
+ super(parameters, OptionalDouble.class, TEST_JAR, "backport.OptionalDoubleBackportJava10Main");
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to OptionalBackportTest.
+
+ // Available since N as part of library desugaring.
+ ignoreInvokes("empty");
+ ignoreInvokes("getAsDouble");
+ ignoreInvokes("of");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava10Test.java
new file mode 100644
index 0000000..b44f1cf
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava10Test.java
@@ -0,0 +1,46 @@
+// 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 com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
+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 final class OptionalIntBackportJava10Test extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+ .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK10)
+ .build();
+ }
+
+ private static final Path TEST_JAR =
+ Paths.get(ToolHelper.EXAMPLES_JAVA10_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+ public OptionalIntBackportJava10Test(TestParameters parameters) {
+ super(parameters, OptionalInt.class, TEST_JAR, "backport.OptionalIntBackportJava10Main");
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to OptionalBackportTest.
+
+ // Available since N as part of library desugaring.
+ ignoreInvokes("empty");
+ ignoreInvokes("getAsInt");
+ ignoreInvokes("of");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava10Test.java
new file mode 100644
index 0000000..a4bef8c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava10Test.java
@@ -0,0 +1,45 @@
+// 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 com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.OptionalLong;
+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 final class OptionalLongBackportJava10Test extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+ .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK10)
+ .build();
+ }
+
+ private static final Path TEST_JAR =
+ Paths.get(ToolHelper.EXAMPLES_JAVA10_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+ public OptionalLongBackportJava10Test(TestParameters parameters) {
+ super(parameters, OptionalLong.class, TEST_JAR, "backport.OptionalLongBackportJava10Main");
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to OptionalBackportTest.
+
+ // Available since N as part of library desugaring.
+ ignoreInvokes("empty");
+ ignoreInvokes("getAsLong");
+ ignoreInvokes("of");
+ }
+}