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&lt;T&gt; { int m(T x); }</code> if this SAM type is used in a lambda
+ * <code>I&lt;Byte&gt; 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('@'), '@');
+    }
+
+}