VarHandle desugar: Better handling of polymorphic return types

Bug: b/247076137
Change-Id: If14311abf0e2fe40a28f09dd0168a37d8523b6ba
diff --git a/src/test/examplesJava9/varhandle/InstanceIntField.java b/src/test/examplesJava9/varhandle/InstanceIntField.java
index 0320030..aeadbcc 100644
--- a/src/test/examplesJava9/varhandle/InstanceIntField.java
+++ b/src/test/examplesJava9/varhandle/InstanceIntField.java
@@ -18,10 +18,54 @@
     throw e;
   }
 
-  public static void testSet(VarHandle varHandle) {
+  public static void testGet(VarHandle varHandle) {
     System.out.println("testGet");
 
     InstanceIntField instance = new InstanceIntField();
+    varHandle.set(instance, 1);
+
+    System.out.println(varHandle.get(instance));
+    System.out.println((Object) varHandle.get(instance));
+    System.out.println((int) varHandle.get(instance));
+    System.out.println((long) varHandle.get(instance));
+    System.out.println((float) varHandle.get(instance));
+    System.out.println((double) varHandle.get(instance));
+    try {
+      System.out.println((boolean) varHandle.get(instance));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((byte) varHandle.get(instance));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((short) varHandle.get(instance));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((char) varHandle.get(instance));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((String) varHandle.get(instance));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+  }
+
+  public static void testSet(VarHandle varHandle) {
+    System.out.println("testSet");
+
+    InstanceIntField instance = new InstanceIntField();
     System.out.println((int) varHandle.get(instance));
 
     // int and Integer values.
@@ -217,6 +261,7 @@
   public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
     VarHandle varHandle =
         MethodHandles.lookup().findVarHandle(InstanceIntField.class, "field", int.class);
+    testGet(varHandle);
     testSet(varHandle);
     testCompareAndSet(varHandle);
   }
diff --git a/src/test/examplesJava9/varhandle/InstanceLongField.java b/src/test/examplesJava9/varhandle/InstanceLongField.java
index fac0ef3..b23e692 100644
--- a/src/test/examplesJava9/varhandle/InstanceLongField.java
+++ b/src/test/examplesJava9/varhandle/InstanceLongField.java
@@ -18,6 +18,55 @@
     throw e;
   }
 
+  public static void testGet(VarHandle varHandle) {
+    System.out.println("testGet");
+
+    InstanceLongField instance = new InstanceLongField();
+    varHandle.set(instance, 1L);
+
+    System.out.println(varHandle.get(instance));
+    System.out.println((Object) varHandle.get(instance));
+    System.out.println((long) varHandle.get(instance));
+    System.out.println((float) varHandle.get(instance));
+    System.out.println((double) varHandle.get(instance));
+    try {
+      System.out.println((boolean) varHandle.get(instance));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((byte) varHandle.get(instance));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((short) varHandle.get(instance));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((char) varHandle.get(instance));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((int) varHandle.get(instance));
+      System.out.println("Unexpected success 5");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((String) varHandle.get(instance));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+  }
+
   public static void testSet(VarHandle varHandle) {
     System.out.println("testSet");
 
@@ -187,6 +236,7 @@
   public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
     VarHandle varHandle =
         MethodHandles.lookup().findVarHandle(InstanceLongField.class, "field", long.class);
+    testGet(varHandle);
     testSet(varHandle);
     testCompareAndSet(varHandle);
   }
diff --git a/src/test/examplesJava9/varhandle/InstanceStringField.java b/src/test/examplesJava9/varhandle/InstanceStringField.java
index 1be6f67..231ee6a 100644
--- a/src/test/examplesJava9/varhandle/InstanceStringField.java
+++ b/src/test/examplesJava9/varhandle/InstanceStringField.java
@@ -14,12 +14,31 @@
     System.out.println(s);
   }
 
-  public static void testSet(VarHandle varHandle) {
+  public static void testGet(VarHandle varHandle) {
     System.out.println("testGet");
 
     InstanceStringField instance = new InstanceStringField();
 
     // Then polymorphic invoke will remove the cast and make that as the return type of the get.
+    System.out.println((String) varHandle.get(instance));
+    varHandle.set(instance, "1");
+    System.out.println(varHandle.get(instance));
+    System.out.println((Object) varHandle.get(instance));
+    System.out.println((String) varHandle.get(instance));
+    System.out.println((CharSequence) varHandle.get(instance));
+    try {
+      System.out.println((Byte) varHandle.get(instance));
+      System.out.println("Unexpected success");
+    } catch (ClassCastException e) {
+    }
+  }
+
+  public static void testSet(VarHandle varHandle) {
+    System.out.println("testSet");
+
+    InstanceStringField instance = new InstanceStringField();
+
+    // Then polymorphic invoke will remove the cast and make that as the return type of the get.
     println((String) varHandle.get(instance));
     varHandle.set(instance, "1");
     println((String) varHandle.get(instance));
@@ -39,6 +58,7 @@
   public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
     VarHandle varHandle =
         MethodHandles.lookup().findVarHandle(InstanceStringField.class, "field", Object.class);
+    testGet(varHandle);
     testSet(varHandle);
     testCompareAndSet(varHandle);
   }
diff --git a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceIntFieldTest.java b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceIntFieldTest.java
index 7cfc0e5..f676891 100644
--- a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceIntFieldTest.java
+++ b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceIntFieldTest.java
@@ -17,6 +17,13 @@
   private static final String EXPECTED_OUTPUT =
       StringUtils.lines(
           "testGet",
+          "1",
+          "1",
+          "1",
+          "1",
+          "1.0",
+          "1.0",
+          "testSet",
           "0",
           "1",
           "2",
diff --git a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceLongFieldTest.java b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceLongFieldTest.java
index 227cc76..7303ec5 100644
--- a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceLongFieldTest.java
+++ b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceLongFieldTest.java
@@ -16,6 +16,12 @@
 
   private static final String EXPECTED_OUTPUT =
       StringUtils.lines(
+          "testGet",
+          "1",
+          "1",
+          "1",
+          "1.0",
+          "1.0",
           "testSet",
           "0",
           "1",
diff --git a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceStringFieldTest.java b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceStringFieldTest.java
index f33f52c..f1440c1 100644
--- a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceStringFieldTest.java
+++ b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceStringFieldTest.java
@@ -15,7 +15,19 @@
 public class VarHandleDesugaringInstanceStringFieldTest extends VarHandleDesugaringTestBase {
 
   private static final String EXPECTED_OUTPUT =
-      StringUtils.lines("testGet", "null", "1", "testCompareAndSet", "null", "1");
+      StringUtils.lines(
+          "testGet",
+          "null",
+          "1",
+          "1",
+          "1",
+          "1",
+          "testSet",
+          "null",
+          "1",
+          "testCompareAndSet",
+          "null",
+          "1");
   private static final String MAIN_CLASS = VarHandle.InstanceStringField.typeName();
   private static final String JAR_ENTRY = "varhandle/InstanceStringField.class";
 
@@ -38,4 +50,9 @@
   protected String getExpectedOutputForReferenceImplementation() {
     return EXPECTED_OUTPUT;
   }
+
+  @Override
+  protected boolean getTestWithDesugaring() {
+    return true;
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/varhandle/DesugarVarHandle.java b/src/test/java/com/android/tools/r8/ir/desugar/varhandle/DesugarVarHandle.java
index 5780485..2ba4cf4 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/varhandle/DesugarVarHandle.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/varhandle/DesugarVarHandle.java
@@ -142,11 +142,38 @@
     return U.getObject(ct1, offset);
   }
 
+  Object getInBox(Object ct1, Class<?> expectedBox) {
+    if (type == int.class) {
+      int value = U.getInt(ct1, offset);
+      if (expectedBox == Long.class) {
+        return Long.valueOf(value);
+      }
+      if (expectedBox == Float.class) {
+        return Float.valueOf(value);
+      }
+      if (expectedBox == Double.class) {
+        return Double.valueOf(value);
+      }
+      throw desugarWrongMethodTypeException();
+    }
+    if (type == long.class) {
+      long value = U.getLong(ct1, offset);
+      if (expectedBox == Float.class) {
+        return Float.valueOf(value);
+      }
+      if (expectedBox == Double.class) {
+        return Double.valueOf(value);
+      }
+      throw desugarWrongMethodTypeException();
+    }
+    return U.getObject(ct1, offset);
+  }
+
   int getInt(Object ct1) {
     if (type == int.class) {
       return U.getInt(ct1, offset);
     } else if (type == long.class) {
-      return (int) U.getLong(ct1, offset);
+      throw desugarWrongMethodTypeException();
     } else {
       return toIntIfPossible(U.getObject(ct1, offset), true);
     }
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/varhandle/GenerateVarHandleMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/varhandle/GenerateVarHandleMethods.java
index 369bc51..7052773 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/varhandle/GenerateVarHandleMethods.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/varhandle/GenerateVarHandleMethods.java
@@ -223,7 +223,8 @@
     for (String prefix : ImmutableList.of("get", "set", "compareAndSet")) {
       if (name.startsWith(prefix)
           && (name.substring(prefix.length()).equals("Int")
-              || name.substring(prefix.length()).equals("Long"))) {
+              || name.substring(prefix.length()).equals("Long")
+              || name.substring(prefix.length()).equals("InBox"))) {
         return prefix;
       }
     }