Merge "Support for Object -> boxed type -> primitive type adjustment for method references."
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
index bfaee32..a4de54f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
@@ -134,6 +134,11 @@
     }
 
     if (b.isPrimitiveType()) {
+      if (a == factory.objectType) {
+        // `a` is java.lang.Object in which case we assume it represented by
+        // proper boxed type.
+        return true;
+      }
       // `a` is a boxed type for `a*` which can be
       // widened to primitive type `b`.
       DexType unboxedA = getPrimitiveFromBoxed(a);
@@ -313,9 +318,16 @@
     // type, the value must be unboxed and converted to the resulting type via primitive
     // widening conversion.
     if (toTypePrimitive) {
-      DexType fromTypeAsPrimitive = getPrimitiveFromBoxed(fromType);
+      DexType boxedType = fromType;
+      if (boxedType == factory().objectType) {
+        // We are in situation when from(=java.lang.Object) is being adjusted to a
+        // primitive type, in which case we assume it is of proper box type.
+        boxedType = getBoxedForPrimitiveType(toType);
+        register = castToBoxedType(register, boxedType);
+      }
+      DexType fromTypeAsPrimitive = getPrimitiveFromBoxed(boxedType);
       if (fromTypeAsPrimitive != null) {
-        int unboxedRegister = addPrimitiveUnboxing(register, fromTypeAsPrimitive, fromType);
+        int unboxedRegister = addPrimitiveUnboxing(register, fromTypeAsPrimitive, boxedType);
         return addPrimitiveWideningConversion(unboxedRegister, fromTypeAsPrimitive, toType);
       }
     }
@@ -461,6 +473,11 @@
     return result;
   }
 
+  private int castToBoxedType(int register, DexType boxType) {
+    add(builder -> builder.addCheckCast(register, boxType));
+    return register;
+  }
+
   private int addPrimitiveBoxing(int register, DexType primitiveType, DexType boxType) {
     // Generate factory method fo boxing.
     DexItemFactory factory = factory();
diff --git a/src/test/examplesAndroidO/lambdadesugaring/ValueAdjustments.java b/src/test/examplesAndroidO/lambdadesugaring/ValueAdjustments.java
index b9d2752..18f8d64 100644
--- a/src/test/examplesAndroidO/lambdadesugaring/ValueAdjustments.java
+++ b/src/test/examplesAndroidO/lambdadesugaring/ValueAdjustments.java
@@ -13,6 +13,10 @@
         int i, Integer I, long l, Long L, float f, Float F, double d, Double D);
   }
 
+  interface it<T> {
+    T t();
+  }
+
   interface iz {
     boolean f();
   }
@@ -135,6 +139,11 @@
 
   private static void checkDouble(StringBuffer builder) {
     builder
+        .append(((id) new it<Double>() {
+          @Override public Double t() {
+            return (double) (Integer.MAX_VALUE) + 1;
+          }
+        }::t).f()).append(' ')
         .append(((id) ValueAdjustments::b).f()).append(' ')
         .append(((id) ValueAdjustments::B).f()).append(' ')
         .append(((id) ValueAdjustments::s).f()).append(' ')
@@ -153,6 +162,11 @@
 
   private static void checkFloat(StringBuffer builder) {
     builder
+        .append(((if_) new it<Float>() {
+          @Override public Float t() {
+            return (float) (Short.MAX_VALUE) + 1;
+          }
+        }::t).f()).append(' ')
         .append(((if_) ValueAdjustments::b).f()).append(' ')
         .append(((if_) ValueAdjustments::B).f()).append(' ')
         .append(((if_) ValueAdjustments::s).f()).append(' ')
@@ -169,6 +183,11 @@
 
   private static void checkLong(StringBuffer builder) {
     builder
+        .append(((ij) new it<Long>() {
+          @Override public Long t() {
+            return (long) (Integer.MAX_VALUE) + 1;
+          }
+        }::t).f()).append(' ')
         .append(((ij) ValueAdjustments::b).f()).append(' ')
         .append(((ij) ValueAdjustments::B).f()).append(' ')
         .append(((ij) ValueAdjustments::s).f()).append(' ')
@@ -183,6 +202,11 @@
 
   private static void checkInt(StringBuffer builder) {
     builder
+        .append(((ii) new it<Integer>() {
+          @Override public Integer t() {
+            return Short.MAX_VALUE + 1;
+          }
+        }::t).f()).append(' ')
         .append(((ii) ValueAdjustments::b).f()).append(' ')
         .append(((ii) ValueAdjustments::B).f()).append(' ')
         .append(((ii) ValueAdjustments::s).f()).append(' ')
@@ -195,6 +219,11 @@
 
   private static void checkShort(StringBuffer builder) {
     builder
+        .append(((is) new it<Short>() {
+          @Override public Short t() {
+            return 256;
+          }
+        }::t).f()).append(' ')
         .append(((is) ValueAdjustments::b).f()).append(' ')
         .append(((is) ValueAdjustments::B).f()).append(' ')
         .append(((is) ValueAdjustments::s).f()).append(' ')
@@ -203,18 +232,33 @@
 
   private static void checkChar(StringBuffer builder) {
     builder
+        .append(((ic) new it<Character>() {
+          @Override public Character t() {
+            return 'C';
+          }
+        }::t).f()).append(' ')
         .append(((ic) ValueAdjustments::c).f()).append(' ')
         .append(((ic) ValueAdjustments::C).f()).append('\n');
   }
 
   private static void checkByte(StringBuffer builder) {
     builder
+        .append(((ib) new it<Byte>() {
+          @Override public Byte t() {
+            return 11;
+          }
+        }::t).f()).append(' ')
         .append(((ib) ValueAdjustments::b).f()).append(' ')
         .append(((ib) ValueAdjustments::B).f()).append('\n');
   }
 
   private static void checkBoolean(StringBuffer builder) {
     builder
+        .append(((iz) new it<Boolean>() {
+          @Override public Boolean t() {
+            return true;
+          }
+        }::t).f()).append(' ')
         .append(((iz) ValueAdjustments::z).f()).append(' ')
         .append(((iz) ValueAdjustments::Z).f()).append('\n');
   }