diff options
| -rw-r--r-- | runtime/method_handles.cc | 9 | ||||
| -rw-r--r-- | runtime/primitive.h | 7 | ||||
| -rw-r--r-- | test/956-methodhandles/src/Main.java | 36 |
3 files changed, 49 insertions, 3 deletions
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc index f1adc32ce2..3c22d7f656 100644 --- a/runtime/method_handles.cc +++ b/runtime/method_handles.cc @@ -141,7 +141,14 @@ bool IsParameterTypeConvertible(ObjPtr<mirror::Class> from, ObjPtr<mirror::Class } 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 7cc47ad79b..a0edaee6fe 100644 --- a/runtime/primitive.h +++ b/runtime/primitive.h @@ -162,7 +162,7 @@ class Primitive { } // 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 @@ class Primitive { } } - // 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 3d714c9dc2..aab9f50be7 100644 --- a/test/956-methodhandles/src/Main.java +++ b/test/956-methodhandles/src/Main.java @@ -843,6 +843,42 @@ public class Main { 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."); } |