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.
--- 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 @@ public class Types {
* 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 @@ public class Types {
}
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 @@ public class Types {
}
@Override
+ public Type visitFunctionType(FunctionType t, Boolean recurse) {
+ return syms.methodHandleType;
+ }
+
+ @Override
public Type visitTypeVar(TypeVar t, Boolean recurse) {
return erasure(t.bound, recurse);
}
@@ -2218,6 +2227,19 @@ public class Types {
else
return makeCompoundType(is.prepend(st));
}
+ }
+
+ @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
--- 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 @@ public class Attr extends JCTree.Visitor
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 @@ public class Lower extends TreeTranslato
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);
+ }
+}