OpenJDK / lambda / lambda / jdk
changeset 5999:f0cf4b53d08d
Fix handling of implementation method with parameterized return type to SAM with primitive return. Overhaul documentation of bootstrap arguments and type conversion. Tighten link-time type checking. Optimize argument/return runtime unboxing. Make var names consistent with description. Change combo-test to used TestNG 6.5.2.
author | Robert Field <Robert.Field@oracle.com> |
---|---|
date | Thu, 13 Sep 2012 01:13:16 -0700 |
parents | 2e6170973d92 |
children | 3012c72bf3da |
files | combo-tests/build.xml src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java src/share/classes/java/lang/invoke/LambdaMetafactory.java src/share/classes/java/lang/invoke/MethodHandleProxyLambdaMetafactory.java src/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java test-ng/tests/org/openjdk/tests/javac/MethodReferenceTestTypeConversion.java |
diffstat | 7 files changed, 188 insertions(+), 97 deletions(-) [+] |
line wrap: on
line diff
--- a/combo-tests/build.xml Wed Sep 05 18:06:11 2012 -0700 +++ b/combo-tests/build.xml Thu Sep 13 01:13:16 2012 -0700 @@ -11,7 +11,7 @@ <property name="lambda.metafactory" value="" /> <property name="combo.debug" value="" /> - <property name="lib.testng.jar" value="${lib.dir}/testng-6.5.1.jar"/> + <property name="lib.testng.jar" value="${lib.dir}/testng-6.5.2.jar"/> <property name="lib.tools.jar" value="${java.home}/../lib/tools.jar"/> <path id="test.class.path">
--- a/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java Wed Sep 05 18:06:11 2012 -0700 +++ b/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java Thu Sep 13 01:13:16 2012 -0700 @@ -49,19 +49,19 @@ * System.out.printf(">>> %s\n", iii.foo(44)); * }} */ - final Class<?> targetClass; // The class calling the meta-factory via invokedynamic "class X" - final MethodType invokedType; // The type of the invoked method "(CC)II" - final Class<?> samBase; // The type of the returned instance "interface JJ" - final boolean isSerializable; // Should the returned instance be serializable - final MethodHandleInfo samInfo; // Info about the SAM method handle "MethodHandleInfo[9 II.foo(Object)Object]" - final Class<?> samClass; // Interface containing the SAM method "interface II" - final MethodType samMethodType; // Type of the SAM method "(Object)Object" - final MethodHandleInfo implInfo; // Info about the implementation method handle "MethodHandleInfo[5 CC.impl(int)String]" - final int implKind; // Invocation kind for implementation "5"=invokevirtual - final boolean implIsInstanceMethod; // Is the implementation an instance method "true" - final Class<?> implDefiningClass; // Type defining the implementation "class CC" - final MethodType implMethodType; // Type of the implementation method "(int)String" - final MethodType functionalMethodType;// Type of the functional interface "(Integer)Object" + final Class<?> targetClass; // The class calling the meta-factory via invokedynamic "class X" + final MethodType invokedType; // The type of the invoked method "(CC)II" + final Class<?> samBase; // The type of the returned instance "interface JJ" + final boolean isSerializable; // Should the returned instance be serializable + final MethodHandleInfo samInfo; // Info about the SAM method handle "MethodHandleInfo[9 II.foo(Object)Object]" + final Class<?> samClass; // Interface containing the SAM method "interface II" + final MethodType samMethodType; // Type of the SAM method "(Object)Object" + final MethodHandleInfo implInfo; // Info about the implementation method handle "MethodHandleInfo[5 CC.impl(int)String]" + final int implKind; // Invocation kind for implementation "5"=invokevirtual + final boolean implIsInstanceMethod; // Is the implementation an instance method "true" + final Class<?> implDefiningClass; // Type defining the implementation "class CC" + final MethodType implMethodType; // Type of the implementation method "(int)String" + final MethodType instantiatedMethodType; // Instantiated erased functional interface method type "(Integer)Object" /** * Meta-factory constructor. @@ -77,14 +77,14 @@ * @param implMethod The implementation method which should be called (with suitable adaptation of argument * types, return types, and adjustment for captured arguments) when methods of the resulting * functional interface instance are invoked. - * @param functionalMethodType The signature of the SAM method from the functional interface's perspective + * @param instantiatedMethodType The signature of the SAM method from the functional interface's perspective * @throws ReflectiveOperationException */ AbstractValidatingLambdaMetafactory(MethodHandles.Lookup caller, MethodType invokedType, MethodHandle samMethod, MethodHandle implMethod, - MethodType functionalMethodType) + MethodType instantiatedMethodType) throws ReflectiveOperationException { this.targetClass = caller.lookupClass(); this.invokedType = invokedType; @@ -105,7 +105,7 @@ this.implDefiningClass = implInfo.getDeclaringClass(); this.implMethodType = implInfo.getMethodType(); - this.functionalMethodType = functionalMethodType; + this.instantiatedMethodType = instantiatedMethodType; } /** @@ -177,16 +177,16 @@ final int receiverArity = implIsInstanceMethod ? 1 : 0; final int capturedArity = invokedType.parameterCount(); final int samArity = samMethodType.parameterCount(); - final int functionalArity = functionalMethodType.parameterCount(); + final int instantiatedArity = instantiatedMethodType.parameterCount(); if (implArity + receiverArity != capturedArity + samArity) { throw new LambdaConversionException(String.format("Incorrect number of parameters for %s method %s; %d captured parameters, %d functional interface parameters, %d implementation parameters", implIsInstanceMethod ? "instance" : "static", implInfo, capturedArity, samArity, implArity)); } - if (functionalArity != samArity) { + if (instantiatedArity != samArity) { throw new LambdaConversionException(String.format("Incorrect number of parameters for %s method %s; %d functional interface parameters, %d SAM method parameters", implIsInstanceMethod ? "instance" : "static", implInfo, - functionalArity, samArity)); + instantiatedArity, samArity)); } // If instance: first captured arg (receiver) must be subtype of class where impl method is defined @@ -200,7 +200,7 @@ // receiver is function parameter capturedStart = 0; samStart = 1; - receiverClass = functionalMethodType.parameterType(0); + receiverClass = instantiatedMethodType.parameterType(0); } else { // receiver is a captured variable capturedStart = 1; @@ -233,15 +233,15 @@ final int samOffset = samStart - implFromCaptured; for (int i=implFromCaptured; i<implArity; i++) { Class<?> implParamType = implMethodType.parameterType(i); - Class<?> samParamType = functionalMethodType.parameterType(i + samOffset); - if (!isAdaptableTo(samParamType, implParamType)) { + Class<?> instantiatedParamType = instantiatedMethodType.parameterType(i + samOffset); + if (!isAdaptableTo(instantiatedParamType, implParamType, true)) { throw new LambdaConversionException( - String.format("Type mismatch for lambda argument %d: %s is not convertible to %s", i, samParamType, implParamType)); + String.format("Type mismatch for lambda argument %d: %s is not convertible to %s", i, instantiatedParamType, implParamType)); } } // Adaptation match: return type - Class<?> expectedType = functionalMethodType.returnType(); + Class<?> expectedType = instantiatedMethodType.returnType(); Class<?> actualReturnType = (implKind == MethodHandleInfo.REF_newInvokeSpecial) ? implDefiningClass @@ -258,7 +258,7 @@ * @param toType * @return True if 'fromType' can be converted to 'toType' */ - private boolean isAdaptableTo(Class<?> fromType, Class<?> toType) { + private boolean isAdaptableTo(Class<?> fromType, Class<?> toType, boolean strict) { if (fromType.equals(toType)) { return true; } @@ -266,32 +266,28 @@ boolean toIsPrimitive = toType.isPrimitive(); if (fromIsPrimitive) { if (toIsPrimitive) { - // widening + // both are primitive: widening Set<Class<?>> classes = assignableTo.get(fromType); return classes != null && classes.contains(toType); - } - else { - // boxing + } else { + // from primitive to reference: boxing return toType.isAssignableFrom(boxesTo.get(fromType)); } - } - else { + } else { if (toIsPrimitive) { - // unboxing + // from reference to primitive: unboxing Class<?> unboxedFrom = unboxesTo.get(fromType); - if (unboxedFrom != null) { + if (unboxedFrom == null) { + // must be convertible to primitive + return !strict; + } else { // fromType is a primitive wrapper; unbox+widen Set<Class<?>> classes = assignableTo.get(unboxedFrom); return classes != null && classes.contains(toType); } - else { - // cast to wrapper for toType, and unbox - return true; - } - } - else { - // blind cast to toType - return true; + } else { + // both are reference types: fromType should be a superclass of toType. + return strict? toType.isAssignableFrom(fromType) : true; } } } @@ -304,7 +300,7 @@ */ private boolean isAdaptableToAsReturn(Class<?> fromType, Class<?> toType) { return toType.equals(void.class) - || !fromType.equals(void.class) && isAdaptableTo(fromType, toType); + || !fromType.equals(void.class) && isAdaptableTo(fromType, toType, false); } }
--- a/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java Wed Sep 05 18:06:11 2012 -0700 +++ b/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java Thu Sep 13 01:13:16 2012 -0700 @@ -70,7 +70,7 @@ private final Type[] argTypes; // ASM types for the constructor arguments private final String[] argNames; // Generated names for the constructor arguments private final String lambdaClassName; // Generated name for the generated class "X$$Lambda$1" - private final Type[] functionalArgumentTypes; // ASM types for the functional interface arguments + private final Type[] instantiatedArgumentTypes; // ASM types for the functional interface arguments /** * Meta-factory constructor. @@ -86,16 +86,16 @@ * @param implMethod The implementation method which should be called (with suitable adaptation of argument * types, return types, and adjustment for captured arguments) when methods of the resulting * functional interface instance are invoked. - * @param functionalMethodType The signature of the SAM method from the functional interface's perspective + * @param instantiatedMethodType The signature of the SAM method from the functional interface's perspective * @throws ReflectiveOperationException */ public InnerClassLambdaMetafactory(MethodHandles.Lookup caller, MethodType invokedType, MethodHandle samMethod, MethodHandle implMethod, - MethodType functionalMethodType) + MethodType instantiatedMethodType) throws ReflectiveOperationException { - super(caller, invokedType, samMethod, implMethod, functionalMethodType); + super(caller, invokedType, samMethod, implMethod, instantiatedMethodType); implMethodClassName = implDefiningClass.getName().replace('.', '/'); implMethodName = implInfo.getName(); implMethodDesc = implMethodType.toMethodDescriptorString(); @@ -111,7 +111,7 @@ for (int i = 0; i < argTypes.length; i++) { argNames[i] = "arg$" + (i + 1); } - functionalArgumentTypes = Type.getArgumentTypes(functionalMethodType.toMethodDescriptorString()); + instantiatedArgumentTypes = Type.getArgumentTypes(instantiatedMethodType.toMethodDescriptorString()); } @@ -378,21 +378,21 @@ if (samIncludesReceiver) { // push receiver Type rcvrType = samArgumentTypes[0]; - Type functionalType = functionalArgumentTypes[0]; + Type instantiatedRcvrType = instantiatedArgumentTypes[0]; load(lvIndex + 1, rcvrType); lvIndex += rcvrType.getSize(); - convertType(rcvrType, Type.getType(implDefiningClass), functionalType); + convertType(rcvrType, Type.getType(implDefiningClass), instantiatedRcvrType); } int argOffset = implMethodArgumentTypes.length - samArgumentTypes.length; for (int i = samReceiverLength; i < samArgumentTypes.length; i++) { Type argType = samArgumentTypes[i]; Type targetType = implMethodArgumentTypes[argOffset + i]; - Type functionalType = functionalArgumentTypes[i]; + Type instantiatedArgType = instantiatedArgumentTypes[i]; load(lvIndex + 1, argType); lvIndex += argType.getSize(); - convertType(argType, targetType, functionalType); + convertType(argType, targetType, instantiatedArgType); } }
--- a/src/share/classes/java/lang/invoke/LambdaMetafactory.java Wed Sep 05 18:06:11 2012 -0700 +++ b/src/share/classes/java/lang/invoke/LambdaMetafactory.java Thu Sep 13 01:13:16 2012 -0700 @@ -29,20 +29,28 @@ * <p>Bootstrap methods for converting lambda expressions and method references to functional interface objects.</p> * * <p>For every lambda expressions or method reference in the source code, there is a target type which is a - * functional interface. Evaluating a lambda expression produces an object of its target type. The - * mechanism for evaluating lambda expressions is to invoke an invokedynamic call site, which takes a method - * handle describing the sole method of the functional interface, a method handle describing the implementation - * method, and returns an object (the lambda object) that implements the target type and whose methods invoke - * the implementation method. For method references, the implementation method is simply the referenced method; - * for lambda expressions, the implementation method is produced by the compiler based on the body of the lambda - * expression. The methods in this file are the bootstrap methods for those invokedynamic call sites, called - * lambda factories, and the bootstrap methods responsible for linking the lambda factories are called lambda - * meta-factories. + * functional interface. Evaluating a lambda expression produces an object of its target type. The mechanism for + * evaluating lambda expressions is to invoke an invokedynamic call site, which takes arguments describing the sole + * method of the functional interface and the implementation method, and returns an object (the lambda object) that + * implements the target type. Methods of the lambda object invoke the implementation method. For method + * references, the implementation method is simply the referenced method; for lambda expressions, the + * implementation method is produced by the compiler based on the body of the lambda expression. The methods in + * this file are the bootstrap methods for those invokedynamic call sites, called lambda factories, and the + * bootstrap methods responsible for linking the lambda factories are called lambda meta-factories. * * <p>The bootstrap methods in this class take the information about the functional interface, the implementation * method, and the static types of the captured lambda arguments, and link a call site which, when invoked, * produces the lambda object. * + * <p>Two pieces of information are needed about the functional interface: the SAM method and the type of the SAM + * method in the functional interface. The type can be different when parameterized types are used. For example, + * consider + * <code>interface I<T> { int m(T x); }</code> if this SAM type is used in a lambda + * <code>I<Byte> v = ...</code>, we need both the actual SAM method which has the signature + * <code>(Object)int</code> and the functional interface type of the method, which has signature + * <code>(Byte)int</code>. The latter is the instantiated erased functional interface method type, or + * simply <I>instantiated method type</I>. + * * <p>While functional interfaces only have a single abstract method from the language perspective (concrete * methods in Object are and default methods may be present), at the bytecode level they may actually have multiple * methods because of the need for bridge methods. Invoking any of these methods on the lambda object will result @@ -52,7 +60,7 @@ * may differ in several ways. The implementation methods may have additional arguments to accommodate arguments * captured by the lambda expression; there may also be differences resulting from permitted adaptations of * arguments, such as casting, boxing, unboxing, and primitive widening. They may also differ because of var-args, - * but this is handled in the compiler by adapter methods for the implementation method. + * but this is expected to be handled by the compiler. * * <p>Invokedynamic call sites have two argument lists: a static argument list and a dynamic argument list. The * static argument list lives in the constant pool; the dynamic argument list lives on the operand stack at @@ -61,15 +69,24 @@ * as well as a method signature describing the number and static types (but not the values) of the dynamic * arguments, and the static return type of the invokedynamic site. * - * <p>The implementation method may be an instance method, or a static method (constructors are considered static - * methods for purposes of this classification.) Assume the functional interface method has N arguments, of types - * (T1, T2, ... Tn) and returns type Rf, the implementation method has M arguments, of types (A1..Am) and return - * type Ri, the dynamic argument list has K arguments of types (D1..Dk), and the invokedynamic return site has - * type Rd, and the functional interface type is F. + * <p>The implementation method can, in theory, be anything representable with a method handle. Currently supported + * are method handles representing invocation of virtual, interface, constructor and static methods. + * + * <p>Assume: + * <ul> + * <li>the functional interface method has N arguments, of types (U1, U2, ... Un) and return type Ru</li> + * <li>then the instantiated method type also has N arguments, of types (T1, T2, ... Tn) and return type Rt</li> + * <li>the implementation method has M arguments, of types (A1..Am) and return type Ra,</li> + * <li>the dynamic argument list has K arguments of types (D1..Dk), and the invokedynamic return site has + * type Rd</li> + * <li>the functional interface type is F</li> + * </ul> * * <p>The following signature invariants must hold: * <ul> * <li>Rd is a subtype of F</li> + * <li>For i=1..N, Ti is a subtype of Ui</li> + * <li>Rt is a subtype of Ru</li> * <li>If the implementation method is a static method: * <ul> * <li>K + N = M</li> @@ -83,31 +100,33 @@ * <li>For i=2..K, Di = Aj, where j=i-1</li> * <li>For i=1..N, Ti is adaptable to Aj, where j=i+k-1</li> * </ul></li> - * <li>The return type Rf is void, or the return type Ri is not void and is adaptable to Rf</li> + * <li>The return type Rt is void, or the return type Ra is not void and is adaptable to Rt</li> * </ul> * - * <p>The type T is considered adaptable to U as follows: + * <p>A type Q is considered adaptable to S as follows: * <table> - * <tr><th>T</th><th>U</th><th>Link-time checks</th><th>Capture-time checks</th></tr> + * <tr><th>Q</th><th>S</th><th>Link-time checks</th><th>Capture-time checks</th></tr> * <tr> * <td>Primitive</td><td>Primitive</td> - * <td>T can be converted to U via a primitive widening conversion</td> + * <td>Q can be converted to S via a primitive widening conversion</td> * <td>None</td> * </tr> * <tr> * <td>Primitive</td><td>Reference</td> - * <td>U is a supertype of the Wrapper(T)</td> - * <td>Casting from Wrapper(T) to U</td> + * <td>S is a supertype of the Wrapper(Q)</td> + * <td>Cast from Wrapper(Q) to S</td> * </tr> * <tr> * <td>Reference</td><td>Primitive</td> - * <td>If T is a primitive wrapper, check that Primitive(T) can be widened to U</td> - * <td>If T is not a primitive wrapper, cast T to Wrapper(U)</td> + * <td>strict: Q is a primitive wrapper and Primitive(Q) can be widened to S + * <br>loose: If Q is a primitive wrapper, check that Primitive(Q) can be widened to S</td> + * <td>If Q is not a primitive wrapper, cast Q to Wrapper(S)</td> * </tr> * <tr> * <td>Reference</td><td>Reference</td> - * <td>None</td> - * <td>Casting from T to U</td> + * <td>strict: S is a supertype of Q + * <br>loose: none</td> + * <td>Cast from Q to S</td> * </tr> * </table> * @@ -139,7 +158,7 @@ * @param implMethod The implementation method which should be called (with suitable adaptation of argument * types, return types, and adjustment for captured arguments) when methods of the resulting * functional interface instance are invoked. - * @param functionDescType The signature of the SAM method from the functional interface's perspective + * @param instantiatedMethodType The signature of the SAM method from the functional interface's perspective * @return a CallSite, which, when invoked, will return an instance of the functional interface * @throws ReflectiveOperationException * @throws LambdaConversionException If any of the meta-factory protocol invariants are violated @@ -149,15 +168,15 @@ MethodType invokedType, MethodHandle samMethod, MethodHandle implMethod, - MethodType functionDescType) + MethodType instantiatedMethodType) throws ReflectiveOperationException, LambdaConversionException { AbstractValidatingLambdaMetafactory mf; switch (whichMetafactory) { case "innerClass": - mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, functionDescType); + mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, instantiatedMethodType); break; case "mhProxy": - mf = new MethodHandleProxyLambdaMetafactory(caller, invokedType, samMethod, implMethod, functionDescType); + mf = new MethodHandleProxyLambdaMetafactory(caller, invokedType, samMethod, implMethod, instantiatedMethodType); break; default: throw new Error("Unknown metafactory");
--- a/src/share/classes/java/lang/invoke/MethodHandleProxyLambdaMetafactory.java Wed Sep 05 18:06:11 2012 -0700 +++ b/src/share/classes/java/lang/invoke/MethodHandleProxyLambdaMetafactory.java Thu Sep 13 01:13:16 2012 -0700 @@ -72,16 +72,16 @@ * @param implMethod The implementation method which should be called (with suitable adaptation of argument * types, return types, and adjustment for captured arguments) when methods of the resulting * functional interface instance are invoked. - * @param functionalMethodType The signature of the SAM method from the functional interface's perspective + * @param instantiatedMethodType The signature of the SAM method from the functional interface's perspective * @throws ReflectiveOperationException */ MethodHandleProxyLambdaMetafactory(MethodHandles.Lookup caller, MethodType invokedType, MethodHandle samMethod, MethodHandle implMethod, - MethodType functionalMethodType) + MethodType instantiatedMethodType) throws ReflectiveOperationException { - super(caller, invokedType, samMethod, implMethod, functionalMethodType); + super(caller, invokedType, samMethod, implMethod, instantiatedMethodType); this.implMethod = implMethod; }
--- a/src/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java Wed Sep 05 18:06:11 2012 -0700 +++ b/src/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java Thu Sep 13 01:13:16 2012 -0700 @@ -68,6 +68,19 @@ "java/lang/Double", }; + // Indexed by Type.getSort; class name of wrapper class for that primitive sort + private static final String[] NAME_PRIMITIVE_BASE_WRAPPER = { + "java/lang/Void", + "java/lang/Boolean", + "java/lang/Character", + "java/lang/Number", + "java/lang/Number", + "java/lang/Number", + "java/lang/Number", + "java/lang/Number", + "java/lang/Number", + }; + // Indexed by Type.getSort; signature character for that primitive sort private static final String[] PRIMITIVE_SIG = { "V", @@ -167,12 +180,23 @@ boxingDescriptor(sort)); } - void unbox(Type type) { - int sort = type.getSort(); + void unbox(Type sType, Type tType) { + int sSort = sType.getSort(); + int tSort = tType.getSort(); visitMethodInsn(INVOKEVIRTUAL, - NAME_PRIMITIVE_WRAPPER[sort], - NAME_UNBOX_METHOD[sort], - unboxingDescriptor(sort)); + NAME_PRIMITIVE_WRAPPER[sSort], + NAME_UNBOX_METHOD[tSort], + unboxingDescriptor(tSort)); + } + + void looseUnbox(Type sType, Type tType) { + int tSort = tType.getSort(); + String baseWrapper = NAME_PRIMITIVE_BASE_WRAPPER[tSort]; + cast(sType, baseWrapper); + visitMethodInsn(INVOKEVIRTUAL, + baseWrapper, + NAME_UNBOX_METHOD[tSort], + unboxingDescriptor(tSort)); } void cast(Type sType, Type tType) { @@ -231,7 +255,6 @@ } else { Type sType; if (isPrimitive(functionalType)) { - //@@@ Shold not be possible sType = argType; } else { // Cast to convert to possibly more specific type, and generate CCE for invalid arg @@ -242,14 +265,11 @@ // Reference argument to primitive target Type spType = unboxedType(sType); if (spType != null) { - // The source type is a boxed primitive, unbox and widen - unbox(spType); - widen(spType, targetType); + // The source type is a boxed primitive, unbox to the desired type + unbox(spType, targetType); } else { - //@@@ Should not be possible - // The source type is not primitive, cast to boxed target type, and unbox - cast(sType, boxedType(targetType)); - unbox(targetType); + // The source type is (hopefully) a supertype of a boxed type, unbox from the base + looseUnbox(sType, targetType); } } else { // Both reference types: just case to target type
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-ng/tests/org/openjdk/tests/javac/MethodReferenceTestTypeConversion.java Thu Sep 13 01:13:16 2012 -0700 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.tests.javac; + +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; + +/** + * @author Robert Field + */ + +class MethodReferenceTestTypeConversion_E<T> { + T xI(T t) { return t; } +} + +@Test +public class MethodReferenceTestTypeConversion { + + interface ISi { int m(Short a); } + + interface ICc { char m(Character a); } + + public void testUnboxObjectToNumberWiden() { + ISi q = (new MethodReferenceTestTypeConversion_E<Short>())::xI; + assertEquals(q.m((short)77), (short)77); + } + + public void testUnboxObjectToChar() { + ICc q = (new MethodReferenceTestTypeConversion_E<Character>())::xI; + assertEquals(q.m('@'), '@'); + } + +}