From 1e0fc79054f3a5c9345c49e94162cd1455792b13 Mon Sep 17 00:00:00 2001 From: Attila Szegedi Date: Mon, 26 Jan 2015 11:11:15 +0100 Subject: [PATCH] Changes for correct handling of void composites. --- .../dynalink/beans/AbstractJavaLinker.java | 5 +++-- .../dynalink/beans/OverloadedMethod.java | 1 - .../dynalink/support/TypeUtilities.java | 22 +++++++++---------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/dynalang/dynalink/beans/AbstractJavaLinker.java b/src/main/java/org/dynalang/dynalink/beans/AbstractJavaLinker.java index 9abff8a..73e0a23 100644 --- a/src/main/java/org/dynalang/dynalink/beans/AbstractJavaLinker.java +++ b/src/main/java/org/dynalang/dynalink/beans/AbstractJavaLinker.java @@ -446,8 +446,9 @@ private GuardedInvocationComponent getPropertySetter(final CallSiteDescriptor ca // We want setters that conform to "Object(O, V)". Note, we aren't doing "R(O, V)" as it might not be // valid for us to convert return values proactively. Also, since we don't know what setters will be - // invoked, we'll conservatively presume Object return type. - final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class); + // invoked, we'll conservatively presume Object return type. The one exception is void return. + final MethodType origType = callSiteDescriptor.getMethodType(); + final MethodType type = origType.returnType() == void.class ? origType : origType.changeReturnType(Object.class); // What's below is basically: // foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation), diff --git a/src/main/java/org/dynalang/dynalink/beans/OverloadedMethod.java b/src/main/java/org/dynalang/dynalink/beans/OverloadedMethod.java index d194e98..bee9170 100644 --- a/src/main/java/org/dynalang/dynalink/beans/OverloadedMethod.java +++ b/src/main/java/org/dynalang/dynalink/beans/OverloadedMethod.java @@ -91,7 +91,6 @@ class OverloadedMethod { varArgMethods = new ArrayList<>(methodHandles.size()); final int argNum = callSiteType.parameterCount(); for(MethodHandle mh: methodHandles) { - mh = mh.asType(mh.type().changeReturnType(commonRetType)); if(mh.isVarargsCollector()) { final MethodHandle asFixed = mh.asFixedArity(); if(argNum == asFixed.type().parameterCount()) { diff --git a/src/main/java/org/dynalang/dynalink/support/TypeUtilities.java b/src/main/java/org/dynalang/dynalink/support/TypeUtilities.java index 23fb289..9f41599 100644 --- a/src/main/java/org/dynalang/dynalink/support/TypeUtilities.java +++ b/src/main/java/org/dynalang/dynalink/support/TypeUtilities.java @@ -86,17 +86,13 @@ private TypeUtilities() { public static Class getCommonLosslessConversionType(final Class c1, final Class c2) { if(c1 == c2) { return c1; + } else if (c1 == void.class || c2 == void.class) { + return Object.class; } else if(isConvertibleWithoutLoss(c2, c1)) { return c1; } else if(isConvertibleWithoutLoss(c1, c2)) { return c2; - } - if(c1 == void.class) { - return c2; - } else if(c2 == void.class) { - return c1; - } - if(c1.isPrimitive() && c2.isPrimitive()) { + } else if(c1.isPrimitive() && c2.isPrimitive()) { if((c1 == byte.class && c2 == char.class) || (c1 == char.class && c2 == byte.class)) { // byte + char = int return int.class; @@ -236,20 +232,24 @@ public static boolean isMethodInvocationConvertible(final Class sourceType, f } /** - * Determines whether a type can be converted to another without losing any - * precision. + * Determines whether a type can be converted to another without losing any precision. As a special case, + * void is considered convertible only to Object and void, while anything can be converted to void. This + * is because a target type of void means we don't care about the value, so the conversion is always + * permissible. * * @param sourceType the source type * @param targetType the target type * @return true if lossless conversion is possible */ public static boolean isConvertibleWithoutLoss(final Class sourceType, final Class targetType) { - if(targetType.isAssignableFrom(sourceType)) { + if(targetType.isAssignableFrom(sourceType) || targetType == void.class) { return true; } if(sourceType.isPrimitive()) { if(sourceType == void.class) { - return false; // Void can't be losslessly represented by any type + // Void should be losslessly representable by Object, either as null or as a custom value that + // can be set with DynamicLinkerFactory.setAutoConversionStrategy. + return targetType == Object.class; } if(targetType.isPrimitive()) { return isProperPrimitiveLosslessSubtype(sourceType, targetType);