MethodHandles: Fix MethodType::IsConvertible() error.

Conversions between non-numeric primitives and their boxed equivalents
were being rejected.

Test: m test-art-host-run-test-956-methodhandles
Bug: 30550796
Change-Id: I4ee255be3a4549246548185e362789561382ba1b
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index f1adc32..3c22d7f 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -141,7 +141,14 @@
     }
     Primitive::Type unboxed_type;
     if (GetUnboxedPrimitiveType(from, &unboxed_type)) {
-      return Primitive::IsWidenable(unboxed_type, to_primitive);
+      if (unboxed_type == to_primitive) {
+        // Straightforward unboxing conversion such as Boolean => boolean.
+        return true;
+      } else {
+        // Check if widening operations for numeric primitives would work,
+        // such as Byte => byte => long.
+        return Primitive::IsWidenable(unboxed_type, to_primitive);
+      }
     }
   }
 
diff --git a/runtime/primitive.h b/runtime/primitive.h
index 7cc47ad..a0edaee 100644
--- a/runtime/primitive.h
+++ b/runtime/primitive.h
@@ -162,7 +162,7 @@
   }
 
   // Return true if |type| is an numeric type.
-  static bool IsNumericType(Type type) {
+  static constexpr bool IsNumericType(Type type) {
     switch (type) {
       case Primitive::Type::kPrimNot: return false;
       case Primitive::Type::kPrimBoolean: return false;
@@ -177,13 +177,16 @@
     }
   }
 
-  // Returns true if |from| and |to| are the same or a widening conversion exists between them.
+  // Returns true if it is possible to widen type |from| to type |to|. Both |from| and
+  // |to| should be numeric primitive types.
   static bool IsWidenable(Type from, Type to) {
     static_assert(Primitive::Type::kPrimByte < Primitive::Type::kPrimShort, "Bad ordering");
     static_assert(Primitive::Type::kPrimShort < Primitive::Type::kPrimInt, "Bad ordering");
     static_assert(Primitive::Type::kPrimInt < Primitive::Type::kPrimLong, "Bad ordering");
     static_assert(Primitive::Type::kPrimLong < Primitive::Type::kPrimFloat, "Bad ordering");
     static_assert(Primitive::Type::kPrimFloat < Primitive::Type::kPrimDouble, "Bad ordering");
+    // Widening is only applicable between numeric types, like byte
+    // and int. Non-numeric types, such as boolean, cannot be widened.
     return IsNumericType(from) && IsNumericType(to) && from <= to;
   }
 
diff --git a/test/956-methodhandles/src/Main.java b/test/956-methodhandles/src/Main.java
index 3d714c9..aab9f50 100644
--- a/test/956-methodhandles/src/Main.java
+++ b/test/956-methodhandles/src/Main.java
@@ -843,6 +843,42 @@
     long l = (long) mh.invoke();
     if (l != 0) fail();
 
+    // boolean -> Boolean
+    mh = MethodHandles.lookup().findStatic(Boolean.class, "parseBoolean",
+                                           MethodType.methodType(boolean.class, String.class));
+    Boolean z = (Boolean) mh.invoke("True");
+    if (!z.booleanValue()) fail();
+
+    // boolean -> int
+    try {
+        int dummy = (int) mh.invoke("True");
+        fail();
+    } catch (WrongMethodTypeException e) {}
+
+    // boolean -> Integer
+    try {
+        Integer dummy = (Integer) mh.invoke("True");
+        fail();
+    } catch (WrongMethodTypeException e) {}
+
+    // Boolean -> boolean
+    mh = MethodHandles.lookup().findStatic(Boolean.class, "valueOf",
+                                           MethodType.methodType(Boolean.class, boolean.class));
+    boolean w = (boolean) mh.invoke(false);
+    if (w) fail();
+
+    // Boolean -> int
+    try {
+        int dummy = (int) mh.invoke(false);
+        fail();
+    } catch (WrongMethodTypeException e) {}
+
+    // Boolean -> Integer
+    try {
+        Integer dummy = (Integer) mh.invoke("True");
+        fail();
+    } catch (WrongMethodTypeException e) {}
+
     System.out.println("testPrimitiveReturnValueConversions done.");
   }