Fix AbstractReturnValue and number unboxing

Bug: b/307872552
Change-Id: Ie6ef8f268122c56c888fffa0b8833851bc33ceef
diff --git a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescriptionMethodOptimizationInfoFixer.java b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescriptionMethodOptimizationInfoFixer.java
index 2d536b4..77fef31 100644
--- a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescriptionMethodOptimizationInfoFixer.java
+++ b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescriptionMethodOptimizationInfoFixer.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraint;
 import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraintFactory;
 import com.android.tools.r8.ir.analysis.type.DynamicType;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
 import com.android.tools.r8.ir.optimize.enums.classification.EnumUnboxerMethodClassification;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
@@ -172,6 +173,23 @@
     return dynamicType;
   }
 
+  @Override
+  public AbstractValue fixupAbstractReturnValue(
+      AppView<AppInfoWithLiveness> appView, AbstractValue returnValue) {
+    if (!prototypeChanges.hasRewrittenReturnInfo()) {
+      return returnValue;
+    }
+    RewrittenTypeInfo rewrittenReturnInfo = prototypeChanges.getRewrittenReturnInfo();
+    if (rewrittenReturnInfo.getNewType().isPrimitiveType()) {
+      // This covers for number unboxing, however, enum unboxing should never have a single
+      // boxed primitive as return value.
+      if (returnValue.isSingleBoxedPrimitive()) {
+        return returnValue.asSingleBoxedPrimitive().toPrimitive(appView.abstractValueFactory());
+      }
+    }
+    return returnValue;
+  }
+
   private BitSet fixupArgumentInfo(BitSet bitSet) {
     if (getArgumentInfoCollection().isEmpty() || bitSet == null) {
       return bitSet;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfoFixer.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfoFixer.java
index 9f75f68..c90d850 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfoFixer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfoFixer.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraint;
 import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraintFactory;
 import com.android.tools.r8.ir.analysis.type.DynamicType;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
 import com.android.tools.r8.ir.optimize.enums.classification.EnumUnboxerMethodClassification;
 import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
@@ -80,4 +81,10 @@
   public DynamicType fixupDynamicType(DynamicType dynamicType) {
     return dynamicType;
   }
+
+  @Override
+  public AbstractValue fixupAbstractReturnValue(
+      AppView<AppInfoWithLiveness> appView, AbstractValue returnValue) {
+    return returnValue;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoFixer.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoFixer.java
index 764942d..06ef441 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoFixer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoFixer.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraint;
 import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraintFactory;
 import com.android.tools.r8.ir.analysis.type.DynamicType;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
 import com.android.tools.r8.ir.optimize.enums.classification.EnumUnboxerMethodClassification;
 import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
@@ -47,4 +48,7 @@
   public abstract BitSet fixupArguments(BitSet arguments);
 
   public abstract DynamicType fixupDynamicType(DynamicType dynamicType);
+
+  public abstract AbstractValue fixupAbstractReturnValue(
+      AppView<AppInfoWithLiveness> appView, AbstractValue returnValue);
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
index 2a33935..602b555 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
@@ -160,6 +160,7 @@
         .fixupBridgeInfo(fixer)
         .fixupClassInlinerMethodConstraint(appView, fixer)
         .fixupDynamicType(fixer)
+        .fixupAbstractReturnValue(appView, fixer)
         .fixupEnumUnboxerMethodClassification(fixer)
         .fixupInstanceInitializerInfo(appView, fixer)
         .fixupNonNullParamOnNormalExits(fixer)
@@ -210,6 +211,15 @@
   }
 
   public MutableMethodOptimizationInfo fixupAbstractReturnValue(
+      AppView<AppInfoWithLiveness> appView, MethodOptimizationInfoFixer fixer) {
+    if (abstractReturnValue.isUnknown()) {
+      return this;
+    }
+    abstractReturnValue = fixer.fixupAbstractReturnValue(appView, abstractReturnValue);
+    return this;
+  }
+
+  public MutableMethodOptimizationInfo fixupAbstractReturnValue(
       AppView<AppInfoWithLiveness> appView,
       DexEncodedMethod method,
       GraphLens lens,
diff --git a/src/test/java/com/android/tools/r8/numberunboxing/VirtualMethodsOverrideNumberUnboxingTest.java b/src/test/java/com/android/tools/r8/numberunboxing/VirtualMethodsOverrideNumberUnboxingTest.java
index b402cb1..67c4241 100644
--- a/src/test/java/com/android/tools/r8/numberunboxing/VirtualMethodsOverrideNumberUnboxingTest.java
+++ b/src/test/java/com/android/tools/r8/numberunboxing/VirtualMethodsOverrideNumberUnboxingTest.java
@@ -6,7 +6,7 @@
 
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.NeverInline;
@@ -14,7 +14,6 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import org.junit.Test;
@@ -49,19 +48,14 @@
         .compile()
         .inspect(this::assertUnboxing)
         .run(parameters.getRuntime(), Main.class)
-        .assertSuccessWithOutputLines("3", "1", "5", "0");
+        .assertSuccessWithOutputLines("3", "1", "43", "5", "0", "43");
   }
 
   private void assertUnboxed(MethodSubject methodSubject) {
     assertThat(methodSubject, isPresent());
-    MethodSignature originalSignature = methodSubject.getOriginalSignature();
-    MethodSignature finalSignature = methodSubject.getFinalSignature().asMethodSignature();
-    assertEquals("java.lang.Long", originalSignature.type);
-    assertEquals("long", finalSignature.type);
-    assertEquals("java.lang.Double", originalSignature.parameters[0]);
-    assertEquals("double", finalSignature.parameters[0]);
-    assertEquals("java.lang.Integer", originalSignature.parameters[1]);
-    assertEquals("int", finalSignature.parameters[1]);
+    assertTrue(methodSubject.getProgramMethod().getParameter(0).isDoubleType());
+    assertTrue(methodSubject.getProgramMethod().getParameter(1).isIntType());
+    assertTrue(methodSubject.getProgramMethod().getReturnType().isLongType());
   }
 
   private void assertUnboxing(CodeInspector codeInspector) {
@@ -73,8 +67,10 @@
     public static void main(String[] args) {
       System.out.println(new Add().convert(1.3, 1) + 1L);
       System.out.println(new Sub().convert(1.4, 2) + 1L);
+      System.out.println(new Cst().convert(1.4, 2) + 1L);
       run(new Add());
       run(new Sub());
+      run(new Cst());
     }
 
     @NeverInline
@@ -95,7 +91,6 @@
     @Override
     @NeverInline
     public Long convert(Double d, Integer i) {
-      System.out.print("");
       return Long.valueOf((long) (d.doubleValue() + i.intValue()));
     }
   }
@@ -106,8 +101,17 @@
     @Override
     @NeverInline
     public Long convert(Double d, Integer i) {
-      System.out.print("");
       return Long.valueOf((long) (d.doubleValue() - i.intValue()));
     }
   }
+
+  @NeverClassInline
+  @NoHorizontalClassMerging
+  static class Cst implements Top {
+    @Override
+    @NeverInline
+    public Long convert(Double d, Integer i) {
+      return Long.valueOf(42L);
+    }
+  }
 }