changeset 555:7586844b51d3

Added interoperability between method type-inference, function types and SAM conversion (as per strawman spec v0.1.5) See tests LambdaConv03.java and LambdaConv04.java for examples.
author mcimadamore
date Fri, 28 May 2010 12:12:18 +0100
parents 317bac39b8a4
children 81966684ef23
files src/share/classes/com/sun/tools/javac/code/Types.java src/share/classes/com/sun/tools/javac/comp/Attr.java src/share/classes/com/sun/tools/javac/comp/Lower.java test/tools/javac/lambda/LambdaConv03.java test/tools/javac/lambda/LambdaConv04.java
diffstat 5 files changed, 288 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/code/Types.java	Fri May 28 10:45:38 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Types.java	Fri May 28 12:12:18 2010 +0100
@@ -267,11 +267,17 @@
      * convertions to s?
      */
     public boolean isConvertible(Type t, Type s, Warner warn) {
-        if (isFunctionType(t) && findSAM(s) != null) {
-            Type mtype = findSAM(s);
+        if (isFunctionType(t) &&
+                (findSAM(s) != null ||
+                isFunctionType(s))) {
+            Type mtype = isFunctionType(s) ?
+                s.asMethodType(this) :
+                findSAM(s);
             boolean isReturnOk = t.getReturnType() == syms.voidType ?
-                (mtype.getReturnType() == syms.voidType ||
-                mtype.getReturnType() == boxedClass(syms.voidType).type) :
+                //the order is inmportant here because of type-inference
+                //(reference types first)
+                (isSameType(mtype.getReturnType(), boxedClass(syms.voidType).type) ||
+                isSameType(mtype.getReturnType(), syms.voidType)) :
                 isConvertible(t.getReturnType(), mtype.getReturnType(), warn);
             boolean argsOk = t.getParameterTypes().size() == mtype.getParameterTypes().size() &&
                     isSameTypes(t.getParameterTypes(), mtype.getParameterTypes());
@@ -494,10 +500,8 @@
                 }
                 else if (isFunctionType(s)) {
                     FunctionType that = (FunctionType)s;
-                    boolean isReturnOk = t.getReturnType() == syms.voidType ?
-                        (that.getReturnType() == syms.voidType ||
-                        that.getReturnType() == boxedClass(syms.voidType).type):
-                    isSubtype(t.getReturnType(), that.getReturnType());
+                    boolean isReturnOk =                            
+                        isSubtype(t.getReturnType(), that.getReturnType());
                     boolean argsOk = t.getParameterTypes().size() == that.getParameterTypes().size() &&
                             isSubtypes(that.getParameterTypes(), t.getParameterTypes());
                     boolean thrownOk = chk.unhandled(t.getThrownTypes(), that.getThrownTypes()).isEmpty();
@@ -1664,6 +1668,11 @@
             }
 
             @Override
+            public Type visitFunctionType(FunctionType t, Boolean recurse) {
+                return syms.methodHandleType;
+            }
+
+            @Override
             public Type visitTypeVar(TypeVar t, Boolean recurse) {
                 return erasure(t.bound, recurse);
             }
@@ -2221,6 +2230,19 @@
         }
 
         @Override
+        public Type visitFunctionType(FunctionType t, Void ignored) {
+            List<Type> argtypes = subst(t.argtypes);
+            Type restype = subst(t.restype);
+            List<Type> thrown = subst(t.thrown);
+            if (argtypes == t.argtypes &&
+                restype == t.restype &&
+                thrown == t.thrown)
+                return t;
+            else
+                return new FunctionType(argtypes, restype, thrown, t.tsym);
+        }
+
+        @Override
         public Type visitWildcardType(WildcardType t, Void ignored) {
             Type bound = t.type;
             if (t.kind != BoundKind.UNBOUND)
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Fri May 28 10:45:38 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Fri May 28 12:12:18 2010 +0100
@@ -1891,7 +1891,12 @@
             log.error(that.pos(), "cannot.infer.lambda.return.type");
             resType = types.createErrorType(resType);
         }
-        that.type = new FunctionType(argtypes.toList(), resType, List.<Type>nil(), syms.methodHandleType.tsym);
+        that.type = new FunctionType(argtypes.toList(),
+                resType == syms.botType ?
+                    syms.objectType :
+                    resType,
+                List.<Type>nil(),
+                syms.methodHandleType.tsym);
         flow.analyzeLambda(that, make);
         that.sym.type = that.type.asMethodType(types);
         result = that.type = check(that, that.type, VAL, pkind, pt);
--- a/src/share/classes/com/sun/tools/javac/comp/Lower.java	Fri May 28 10:45:38 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Lower.java	Fri May 28 12:12:18 2010 +0100
@@ -2646,7 +2646,7 @@
             translatedCall = (JCExpression)convert(translatedCall,
                     expectedType.isPrimitive() ?
                         types.boxedClass(expectedType).type :
-                        expectedType);
+                        types.erasure(expectedType));
         }
         result = translate(translatedCall, expectedType);
         return;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaConv03.java	Fri May 28 12:12:18 2010 +0100
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  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.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @summary SAM types and method type inference
+ * @author  Brian Goetz
+ * @author  Maurizio Cimadamore
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles LambdaConv03
+ */
+
+public class LambdaConv03 {
+
+    static int assertionCount = 0;
+
+    static void assertTrue(boolean cond) {
+        assertionCount++;
+        if (!cond)
+            throw new AssertionError();
+    }
+
+    interface TU<T, U> {
+      public T foo(U u);
+    }
+
+    public static <T, U> T exec(TU<T, U> lambda, U x) {
+        return lambda.foo(x);
+    }
+
+    static {
+        //void
+        exec(#(Integer x){ assertTrue(x == 3); }, 3);
+        //Covariant returns:
+        int i = exec(#(Integer x)(x), 3);
+        assertTrue(3 == i);
+        //Method resolution with boxing:
+        int x = exec(#(Integer x)(x), 3);
+        assertTrue(3 == x);
+        //Runtime exception transparency:
+        try {
+            exec(#(Object x)(x.hashCode()), null);
+        }
+        catch (RuntimeException e) {
+            assertTrue(true);
+        }
+    }
+
+    {
+        //void
+        exec(#(Integer x){ assertTrue(x == 3); }, 3);
+        //Covariant returns:
+        int i = exec(#(Integer x)(x), 3);
+        assertTrue(3 == i);
+        //Method resolution with boxing:
+        int x = exec(#(Integer x)(x), 3);
+        assertTrue(3 == x);
+        //Runtime exception transparency:
+        try {
+            exec(#(Object x)(x.hashCode()), null);
+        }
+        catch (RuntimeException e) {
+            assertTrue(true);
+        }
+    }
+
+    public static void test1() {
+        //void
+        exec(#(Integer x){ assertTrue(x == 3); }, 3);
+        //Covariant returns:
+        int i = exec(#(Integer x)(x), 3);
+        assertTrue(3 == i);
+        //Method resolution with boxing:
+        int x = exec(#(Integer x)(x), 3);
+        assertTrue(3 == x);
+        //Runtime exception transparency:
+        try {
+            exec(#(Object x)(x.hashCode()), null);
+        }
+        catch (RuntimeException e) {
+            assertTrue(true);
+        }
+    }
+
+    public void test2() {
+        //void
+        exec(#(Integer x){ assertTrue(x == 3); }, 3);
+        //Covariant returns:
+        int i = exec(#(Integer x)(x), 3);
+        assertTrue(3 == i);
+        //Method resolution with boxing:
+        int x = exec(#(Integer x)(x), 3);
+        assertTrue(3 == x);
+        //Runtime exception transparency:
+        try {
+            exec(#(Object x)(x.hashCode()), null);
+        }
+        catch (RuntimeException e) {
+            assertTrue(true);
+        }
+    }
+
+    public static void main(String[] args) {
+        test1();
+        new LambdaConv03().test2();
+        assertTrue(assertionCount == 16);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaConv04.java	Fri May 28 12:12:18 2010 +0100
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  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.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @summary function type and method type inference
+ * @author  Brian Goetz
+ * @author  Maurizio Cimadamore
+ * @compile -XDallowFunctionTypes LambdaConv04.java
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles LambdaConv04
+ */
+
+public class LambdaConv04 {
+
+    static int assertionCount = 0;
+
+    static void assertTrue(boolean cond) {
+        assertionCount++;
+        if (!cond)
+            throw new AssertionError();
+    }
+
+    public static <T, U> T exec(#T(U) lambda, U x) {
+        return lambda.(x);
+    }
+
+    static {
+        //void
+        exec(#(Integer x){ assertTrue(x == 3); }, 3);
+        //Covariant returns:
+        int i = exec(#(Integer x)(x), 3);
+        assertTrue(3 == i);
+        //Method resolution with boxing:
+        int x = exec(#(Integer x)(x), 3);
+        assertTrue(3 == x);
+        //Runtime exception transparency:
+        try {
+            exec(#(Object x)(x.hashCode()), null);
+        }
+        catch (RuntimeException e) {
+            assertTrue(true);
+        }
+    }
+
+    {
+        //void
+        exec(#(Integer x){ assertTrue(x == 3); }, 3);
+        //Covariant returns:
+        int i = exec(#(Integer x)(x), 3);
+        assertTrue(3 == i);
+        //Method resolution with boxing:
+        int x = exec(#(Integer x)(x), 3);
+        assertTrue(3 == x);
+        //Runtime exception transparency:
+        try {
+            exec(#(Object x)(x.hashCode()), null);
+        }
+        catch (RuntimeException e) {
+            assertTrue(true);
+        }
+    }
+
+    public static void test1() {
+        //void
+        exec(#(Integer x){ assertTrue(x == 3); }, 3);
+        //Covariant returns:
+        int i = exec(#(Integer x)(x), 3);
+        assertTrue(3 == i);
+        //Method resolution with boxing:
+        int x = exec(#(Integer x)(x), 3);
+        assertTrue(3 == x);
+        //Runtime exception transparency:
+        try {
+            exec(#(Object x)(x.hashCode()), null);
+        }
+        catch (RuntimeException e) {
+            assertTrue(true);
+        }
+    }
+
+    public void test2() {
+        //void
+        exec(#(Integer x){ assertTrue(x == 3); }, 3);
+        //Covariant returns:
+        int i = exec(#(Integer x)(x), 3);
+        assertTrue(3 == i);
+        //Method resolution with boxing:
+        int x = exec(#(Integer x)(x), 3);
+        assertTrue(3 == x);
+        //Runtime exception transparency:
+        try {
+            exec(#(Object x)(x.hashCode()), null);
+        }
+        catch (RuntimeException e) {
+            assertTrue(true);
+        }
+    }
+
+    public static void main(String[] args) {
+        test1();
+        new LambdaConv04().test2();
+        assertTrue(assertionCount == 16);
+    }
+}