initial lambda push; the current prototype suuports the following features:
authormcimadamore
Thu May 27 18:11:12 2010 +0100 (3 years ago)
changeset 5537704dcd17e0b
parent 55267cac01ed62a
child 554317bac39b8a4
initial lambda push; the current prototype suuports the following features:
*) function types syntax (optionally enabled with -XDallowFunctionTypes)
*) function types subtyping
*) full support for lambda expression of type 1 and 2
*) inference of thrown types/return type in a lambda
*) lambda conversion using rules specified in v0.1.5 draft
*) support references to 'this' (both explicit and implicit)
*) translation using method handles

The modified script build of the langtools repository now generates an additional jarfile called javacrt.jar which contains an helper class to be used during SAM conversion; after the build, the generated scripts javac/java will take care of automatically setting up the required dependencies so that code containing lambda expressions can be compiled and executed.
make/build.properties
make/build.xml
src/share/bin/java.sh-template
src/share/bin/launcher.sh-template
src/share/classes/com/sun/runtime/ProxyHelper.java
src/share/classes/com/sun/source/tree/FunctionTypeTree.java
src/share/classes/com/sun/source/tree/LambdaExpressionTree.java
src/share/classes/com/sun/source/tree/Tree.java
src/share/classes/com/sun/source/tree/TreeVisitor.java
src/share/classes/com/sun/source/util/SimpleTreeVisitor.java
src/share/classes/com/sun/source/util/TreeScanner.java
src/share/classes/com/sun/tools/javac/code/Flags.java
src/share/classes/com/sun/tools/javac/code/Printer.java
src/share/classes/com/sun/tools/javac/code/Scope.java
src/share/classes/com/sun/tools/javac/code/Source.java
src/share/classes/com/sun/tools/javac/code/Symtab.java
src/share/classes/com/sun/tools/javac/code/Type.java
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/Check.java
src/share/classes/com/sun/tools/javac/comp/Flow.java
src/share/classes/com/sun/tools/javac/comp/Lower.java
src/share/classes/com/sun/tools/javac/comp/Resolve.java
src/share/classes/com/sun/tools/javac/comp/TransTypes.java
src/share/classes/com/sun/tools/javac/jvm/ClassReader.java
src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java
src/share/classes/com/sun/tools/javac/parser/JavacParser.java
src/share/classes/com/sun/tools/javac/parser/Scanner.java
src/share/classes/com/sun/tools/javac/parser/Token.java
src/share/classes/com/sun/tools/javac/resources/compiler.properties
src/share/classes/com/sun/tools/javac/tree/JCTree.java
src/share/classes/com/sun/tools/javac/tree/Pretty.java
src/share/classes/com/sun/tools/javac/tree/TreeCopier.java
src/share/classes/com/sun/tools/javac/tree/TreeMaker.java
src/share/classes/com/sun/tools/javac/tree/TreeScanner.java
src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java
src/share/classes/com/sun/tools/javac/util/Names.java
src/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java
test/tools/javac/lambda/LambdaCapture01.java
test/tools/javac/lambda/LambdaConv01.java
test/tools/javac/lambda/LambdaExpr01.java
test/tools/javac/lambda/LambdaExpr02.java
test/tools/javac/lambda/LambdaScope01.java
test/tools/javac/lambda/NakedThis.java
test/tools/javac/lambda/NakedThis.out
--- a/make/build.properties Thu May 20 16:00:35 2010 -0700
+++ b/make/build.properties Thu May 27 18:11:12 2010 +0100
@@ -99,6 +99,9 @@ javac.includes = \
javax/tools/ \
com/sun/source/ com/sun/tools/javac/
+javac.runtime.includes = \
+ com/sun/runtime/
+
javac.tests = \
tools/javac
--- a/make/build.xml Thu May 20 16:00:35 2010 -0700
+++ b/make/build.xml Thu May 27 18:11:12 2010 +0100
@@ -245,12 +245,26 @@
</target>
<target name="build-classes-javac" depends="build-bootstrap-javac,-create-import-jdk-stubs">
- <build-classes includes="${javac.includes}"/>
- </target>
-
- <target name="build-javac" depends="build-classes-javac">
+ <build-classes includes="${javac.includes}"/>
+ </target>
+
+ <target name="build-rtjavac" depends="build-runtime-classes">
+ <build-jar name="javacrt" includes="${javac.runtime.includes}"/>
+ </target>
+
+
+ <target name="build-runtime-support" depends="build-runtime-classes">
+ <build-jar name="javacrt" includes="${javac.runtime.includes}"/>
+ </target>
+
+ <target name="build-runtime-classes">
+ <build-classes java.home="${target.java.home}" includes="${javac.runtime.includes}"/>
+ </target>
+
+ <target name="build-javac" depends="build-classes-javac,build-rtjavac,-def-build-java-launcher">
<build-jar name="javac" includes="${javac.includes}"/>
<build-tool name="javac"/>
+ <build-java-launcher/>
</target>
<target name="javadoc-javac" depends="build-javac,-def-javadoc-tool">
@@ -475,6 +489,22 @@
</filterset>
</copy>
<chmod file="@{bin.dir}/@{name}" perm="ugo+rx"/>
+ </sequential>
+ </macrodef>
+ </target>
+
+ <target name="-def-build-java-launcher">
+ <macrodef name="build-java-launcher">
+ <attribute name="bin.dir" default="${dist.bin.dir}"/>
+ <attribute name="java" default="${launcher.java}"/>
+ <sequential>
+ <mkdir dir="@{bin.dir}"/>
+ <copy file="${src.bin.dir}/java.sh-template" tofile="@{bin.dir}/java">
+ <filterset begintoken="#" endtoken="#">
+ <filter token="TARGET_JAVA" value="@{java}"/>
+ </filterset>
+ </copy>
+ <chmod file="@{bin.dir}/java" perm="ugo+rx"/>
</sequential>
</macrodef>
</target>
--- a/src/share/bin/launcher.sh-template Thu May 20 16:00:35 2010 -0700
+++ b/src/share/bin/launcher.sh-template Thu May 27 18:11:12 2010 +0100
@@ -41,7 +41,7 @@ if [ "$LANGTOOLS_USE_BOOTCLASSPATH" != "
cp=`unzip -c "$mylib/#PROGRAM#.jar" META-INF/MANIFEST.MF |
grep "Class-Path:" |
sed -e 's|Class-Path: *||' -e 's|\([a-z]*\.jar\) *|'"$mylib"'/\1:|g'`
- bcp="$mylib/#PROGRAM#.jar":$cp
+ bcp="$mylib/#PROGRAM#.jar":"$mylib/#PROGRAM#rt.jar":$cp
fi
# tools currently assumes that assertions are enabled in the launcher
--- a/src/share/classes/com/sun/source/tree/Tree.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/source/tree/Tree.java Thu May 27 18:11:12 2010 +0100
@@ -184,6 +184,11 @@ public interface Tree {
NEW_ARRAY(NewArrayTree.class),
/**
+ * Used for instances of {@link LambdaExpressionTree}.
+ */
+ LAMBDA_EXPRESSION(LambdaExpressionTree.class),
+
+ /**
* Used for instances of {@link NewClassTree}.
*/
NEW_CLASS(NewClassTree.class),
@@ -237,6 +242,11 @@ public interface Tree {
* Used for instances of {@link DisjointTypeTree}.
*/
DISJOINT_TYPE(DisjointTypeTree.class),
+
+ /**
+ * Used for instances of {@link FunctionTypeTree}.
+ */
+ FUNCTION_TYPE(FunctionTypeTree.class),
/**
* Used for instances of {@link TypeCastTree}.
--- a/src/share/classes/com/sun/source/tree/TreeVisitor.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/source/tree/TreeVisitor.java Thu May 27 18:11:12 2010 +0100
@@ -86,6 +86,7 @@ public interface TreeVisitor<R,P> {
R visitModifiers(ModifiersTree node, P p);
R visitNewArray(NewArrayTree node, P p);
R visitNewClass(NewClassTree node, P p);
+ R visitLambdaExpression(LambdaExpressionTree node, P p);
R visitParenthesized(ParenthesizedTree node, P p);
R visitReturn(ReturnTree node, P p);
R visitMemberSelect(MemberSelectTree node, P p);
@@ -97,6 +98,7 @@ public interface TreeVisitor<R,P> {
R visitTry(TryTree node, P p);
R visitParameterizedType(ParameterizedTypeTree node, P p);
R visitDisjointType(DisjointTypeTree node, P p);
+ R visitFunctionType(FunctionTypeTree node, P p);
R visitArrayType(ArrayTypeTree node, P p);
R visitTypeCast(TypeCastTree node, P p);
R visitPrimitiveType(PrimitiveTypeTree node, P p);
--- a/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java Thu May 27 18:11:12 2010 +0100
@@ -172,6 +172,10 @@ public class SimpleTreeVisitor <R,P> imp
return defaultAction(node, p);
}
+ public R visitLambdaExpression(LambdaExpressionTree node, P p) {
+ return defaultAction(node, p);
+ }
+
public R visitParenthesized(ParenthesizedTree node, P p) {
return defaultAction(node, p);
}
@@ -232,6 +236,10 @@ public class SimpleTreeVisitor <R,P> imp
return defaultAction(node, p);
}
+ public R visitFunctionType(FunctionTypeTree node, P p) {
+ return defaultAction(node, p);
+ }
+
public R visitTypeParameter(TypeParameterTree node, P p) {
return defaultAction(node, p);
}
--- a/src/share/classes/com/sun/source/util/TreeScanner.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/source/util/TreeScanner.java Thu May 27 18:11:12 2010 +0100
@@ -284,6 +284,12 @@ public class TreeScanner<R,P> implements
return r;
}
+ public R visitLambdaExpression(LambdaExpressionTree node, P p) {
+ R r = scan(node.getParameters(), p);
+ r = scanAndReduce(node.getBody(), p, r);
+ return r;
+ }
+
public R visitParenthesized(ParenthesizedTree node, P p) {
return scan(node.getExpression(), p);
}
@@ -356,6 +362,13 @@ public class TreeScanner<R,P> implements
public R visitDisjointType(DisjointTypeTree node, P p) {
return scan(node.getTypeComponents(), p);
+ }
+
+ public R visitFunctionType(FunctionTypeTree node, P p) {
+ R r = scan(node.getArgumentTypes(), p);
+ r = scanAndReduce(node.getResultType(), p, r);
+ r = scanAndReduce(node.getThrownTypes(), p, r);
+ return r;
}
public R visitTypeParameter(TypeParameterTree node, P p) {
--- a/src/share/classes/com/sun/tools/javac/code/Flags.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/code/Flags.java Thu May 27 18:11:12 2010 +0100
@@ -235,6 +235,11 @@ public class Flags {
*/
public static final long DISJOINT = 1L<<39;
+ /**
+ * Flag that marks a method symbol representing a lambda expression
+ */
+ public static final long LAMBDA = 1L<<40;
+
/** Modifier masks.
*/
public static final int
--- a/src/share/classes/com/sun/tools/javac/code/Printer.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/code/Printer.java Thu May 27 18:11:12 2010 +0100
@@ -200,6 +200,22 @@ public abstract class Printer implements
@Override
public String visitMethodType(MethodType t, Locale locale) {
return "(" + printMethodArgs(t.argtypes, false, locale) + ")" + visit(t.restype, locale);
+ }
+
+ @Override
+ public String visitFunctionType(FunctionType t, Locale locale) {
+ StringBuilder buf = new StringBuilder();
+ buf.append("#");
+ buf.append(visit(t.restype, locale));
+ buf.append("(");
+ buf.append(printMethodArgs(t.argtypes, false, locale));
+ buf.append(")");
+ if (t.getThrownTypes().nonEmpty()) {
+ buf.append("(");
+ buf.append(visitTypes(t.thrown, locale));
+ buf.append(")");
+ }
+ return buf.toString();
}
@Override
--- a/src/share/classes/com/sun/tools/javac/code/Scope.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/code/Scope.java Thu May 27 18:11:12 2010 +0100
@@ -456,7 +456,7 @@ public class Scope {
return new DelegatedScope(next);
}
public Scope dupUnshared() {
- return new DelegatedScope(next);
+ return delegatee.dupUnshared();
}
public Scope leave() {
return next;
--- a/src/share/classes/com/sun/tools/javac/code/Source.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/code/Source.java Thu May 27 18:11:12 2010 +0100
@@ -171,6 +171,9 @@ public enum Source {
public boolean allowStringsInSwitch() {
return compareTo(JDK1_7) >= 0;
}
+ public boolean allowLambda() {
+ return compareTo(JDK1_7) >= 0;
+ }
public static SourceVersion toSourceVersion(Source source) {
switch(source) {
case JDK1_2:
--- a/src/share/classes/com/sun/tools/javac/code/Symtab.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/code/Symtab.java Thu May 27 18:11:12 2010 +0100
@@ -120,6 +120,9 @@ public class Symtab {
public final Type cloneableType;
public final Type serializableType;
public final Type methodHandleType;
+ public final Type methodTypeType;
+ public final Type methodHandleLookupType;
+ public final Type methodHandlesType;
public final Type invokeDynamicType;
public final Type throwableType;
public final Type errorType;
@@ -147,6 +150,7 @@ public class Symtab {
public final Type inheritedType;
public final Type proprietaryType;
public final Type systemType;
+ public final Type proxyHelper;
/** The symbol representing the length field of an array.
*/
@@ -426,6 +430,9 @@ public class Symtab {
throwableType = enterClass("java.lang.Throwable");
serializableType = enterClass("java.io.Serializable");
methodHandleType = enterClass("java.dyn.MethodHandle");
+ methodTypeType = enterClass("java.dyn.MethodType");
+ methodHandleLookupType = enterClass("java.dyn.MethodType.Lookup");
+ methodHandlesType = enterClass("java.dyn.MethodHandles");
invokeDynamicType = enterClass("java.dyn.InvokeDynamic");
errorType = enterClass("java.lang.Error");
illegalArgumentExceptionType = enterClass("java.lang.IllegalArgumentException");
@@ -460,6 +467,7 @@ public class Symtab {
suppressWarningsType = enterClass("java.lang.SuppressWarnings");
inheritedType = enterClass("java.lang.annotation.Inherited");
systemType = enterClass("java.lang.System");
+ proxyHelper = enterClass("com.sun.runtime.ProxyHelper");
synthesizeEmptyInterfaceIfMissing(cloneableType);
synthesizeEmptyInterfaceIfMissing(serializableType);
--- a/src/share/classes/com/sun/tools/javac/code/Type.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/code/Type.java Thu May 27 18:11:12 2010 +0100
@@ -362,7 +362,7 @@ public class Type implements PrimitiveTy
/** The underlying method type of this type.
*/
- public MethodType asMethodType() { throw new AssertionError(); }
+ public MethodType asMethodType(Types types) { throw new AssertionError(); }
/** Complete loading all classes in this type.
*/
@@ -653,6 +653,10 @@ public class Type implements PrimitiveTy
// optimization, was: allparams().nonEmpty();
}
+ public boolean isFunctionType() {
+ return false;
+ }
+
/** A cache for the rank. */
int rank_field = -1;
@@ -776,6 +780,113 @@ public class Type implements PrimitiveTy
public <R, P> R accept(TypeVisitor<R, P> v, P p) {
return v.visitArray(this, p);
+ }
+ }
+
+ public static class FunctionType extends ClassType {
+
+ public List<Type> argtypes;
+ public Type restype;
+ public List<Type> thrown;
+
+ public FunctionType(List<Type> argtypes,
+ Type restype,
+ List<Type> thrown,
+ TypeSymbol methodHandleClass) {
+ super(Type.noType, List.<Type>nil(), methodHandleClass);
+ this.argtypes = argtypes;
+ this.restype = restype;
+ this.thrown = thrown;
+ }
+
+ @Override
+ public <R,S> R accept(Type.Visitor<R,S> v, S s) {
+ return v.visitFunctionType(this, s);
+ }
+
+ public String toString() {
+ return "#" + restype + "(" + argtypes + ")" +
+ (thrown.isEmpty() ? "" : "(" + thrown + ")");
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!(obj instanceof FunctionType))
+ return false;
+ FunctionType m = (FunctionType)obj;
+ List<Type> args1 = argtypes;
+ List<Type> args2 = m.argtypes;
+ while (!args1.isEmpty() && !args2.isEmpty()) {
+ if (!args1.head.equals(args2.head))
+ return false;
+ args1 = args1.tail;
+ args2 = args2.tail;
+ }
+ if (!args1.isEmpty() || !args2.isEmpty())
+ return false;
+ return restype.equals(m.restype);
+ }
+
+ public int hashCode() {
+ int h = CLASS;
+ for (List<Type> thisargs = this.argtypes;
+ thisargs.tail != null; /*inlined: thisargs.nonEmpty()*/
+ thisargs = thisargs.tail)
+ h = (h << 5) + thisargs.head.hashCode();
+ return (h << 5) + this.restype.hashCode();
+ }
+
+ public List<Type> getParameterTypes() { return argtypes; }
+ public Type getReturnType() { return restype; }
+ public List<Type> getThrownTypes() { return thrown; }
+
+ public void setThrown(List<Type> t) {
+ thrown = t;
+ }
+
+ public boolean isErroneous() {
+ return
+ isErroneous(argtypes) ||
+ restype != null && restype.isErroneous();
+ }
+
+ @Override
+ public MethodType asMethodType(Types types) {
+ return new MethodType(argtypes, restype, thrown, types.syms.methodClass);
+ }
+
+ public Type map(Mapping f) {
+ List<Type> argtypes1 = map(argtypes, f);
+ Type restype1 = f.apply(restype);
+ List<Type> thrown1 = map(thrown, f);
+ if (argtypes1 == argtypes &&
+ restype1 == restype &&
+ thrown1 == thrown) return this;
+ else return new FunctionType(argtypes1, restype1, thrown1, tsym);
+ }
+
+ public boolean contains(Type elem) {
+ return elem == this ||
+ contains(argtypes, elem) ||
+ restype.contains(elem) ||
+ thrown.contains(elem);
+ }
+
+ public boolean isFunctionType() {
+ return true;
+ }
+
+ public void complete() {
+ //nothing to do
+ }
+
+ public List<TypeVar> getTypeVariables() {
+ return List.nil();
+ }
+
+ public TypeSymbol asElement() {
+ return null;
}
}
@@ -866,7 +977,7 @@ public class Type implements PrimitiveTy
return elem == this || contains(argtypes, elem) || restype.contains(elem);
}
- public MethodType asMethodType() { return this; }
+ public MethodType asMethodType(Types types) { return this; }
public void complete() {
for (List<Type> l = argtypes; l.nonEmpty(); l = l.tail)
@@ -1125,8 +1236,8 @@ public class Type implements PrimitiveTy
return qtype.contains(elem);
}
- public MethodType asMethodType() {
- return qtype.asMethodType();
+ public MethodType asMethodType(Types types) {
+ return qtype.asMethodType(types);
}
public void complete() {
@@ -1300,6 +1411,7 @@ public class Type implements PrimitiveTy
R visitWildcardType(WildcardType t, S s);
R visitArrayType(ArrayType t, S s);
R visitMethodType(MethodType t, S s);
+ R visitFunctionType(FunctionType t, S s);
R visitPackageType(PackageType t, S s);
R visitTypeVar(TypeVar t, S s);
R visitCapturedType(CapturedType t, S s);
--- a/src/share/classes/com/sun/tools/javac/code/Types.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/code/Types.java Thu May 27 18:11:12 2010 +0100
@@ -267,14 +267,70 @@ public class Types {
* convertions to s?
*/
public boolean isConvertible(Type t, Type s, Warner warn) {
- boolean tPrimitive = t.isPrimitive();
- boolean sPrimitive = s.isPrimitive();
- if (tPrimitive == sPrimitive)
- return isSubtypeUnchecked(t, s, warn);
- if (!allowBoxing) return false;
- return tPrimitive
- ? isSubtype(boxedClass(t).type, s)
- : isSubtype(unboxedType(t), s);
+ if (isFunctionType(t) && findSAM(s) != null) {
+ Type mtype = findSAM(s);
+ boolean isReturnOk = t.getReturnType() == syms.voidType ?
+ mtype.getReturnType() == syms.voidType :
+ isConvertible(t.getReturnType(), mtype.getReturnType(), warn);
+ boolean argsOk = isSameTypes(t.getParameterTypes(), mtype.getParameterTypes());
+ boolean thrownOk = chk.unhandled(t.getThrownTypes(), mtype.getThrownTypes()).isEmpty();
+ return isReturnOk && argsOk && thrownOk;
+ }
+ else {
+ boolean tPrimitive = t.isPrimitive();
+ boolean sPrimitive = s.isPrimitive();
+ if (tPrimitive == sPrimitive)
+ return isSubtypeUnchecked(t, s, warn);
+ if (!allowBoxing) return false;
+ return tPrimitive
+ ? isSubtype(boxedClass(t).type, s)
+ : isSubtype(unboxedType(t), s);
+ }
+ }
+
+ public Type findSAM(Type t) {
+ if (t.isInterface()) {
+ ListBuffer<Symbol> abstracts = ListBuffer.lb();
+ findSAM(t, abstracts);
+ if (abstracts.size() == 0) {
+ return null;
+ } else if (abstracts.size() == 1) {
+ return memberType(t, abstracts.first());
+ } else {
+ Type resType = Type.noType;
+ List<Type> thrownTypes = List.nil();
+ List<Type> argtypes =
+ memberType(t, abstracts.first()).getParameterTypes();
+ for (Symbol msym : abstracts.toList()) {
+ Type mtype = memberType(t, msym);
+ resType = mtype.getReturnType() == syms.voidType ?
+ syms.voidType :
+ lub(resType, mtype.getReturnType());
+ thrownTypes = chk.union(mtype.getThrownTypes(), thrownTypes);
+ }
+ return new MethodType(argtypes,
+ resType,
+ thrownTypes,
+ syms.methodClass);
+ }
+ }
+ return null;
+ }
+
+ private void findSAM(Type t, ListBuffer<Symbol> buf) {
+ if (t == Type.noType) return;
+ for (Scope.Entry e = t.tsym.members().elems ; e != null ; e = e.sibling) {
+ if (e.sym != null &&
+ e.sym.kind == Kinds.MTH &&
+ (e.sym.flags() & ABSTRACT) != 0 &&
+ (buf.isEmpty() || overrideEquivalent(e.sym.type, buf.first().type))) {
+ buf.append(e.sym);
+ }
+ }
+ findSAM(supertype(t), buf);
+ for (Type i : interfaces(t)) {
+ findSAM(i, buf);
+ }
}
/**
@@ -427,6 +483,26 @@ public class Types {
return subst(t.tsym.type, from.toList(), rewrite.toList());
else
return t;
+ }
+
+ @Override
+ public Boolean visitFunctionType(FunctionType t, Type s) {
+ if (isSameType(s, syms.objectType)) {
+ return true;
+ }
+ else if (isFunctionType(s)) {
+ FunctionType that = (FunctionType)s;
+ boolean isReturnOk = t.getReturnType() == syms.voidType ?
+ that.getReturnType() == syms.voidType :
+ 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();
+ return isReturnOk && argsOk && thrownOk;
+ }
+ else {
+ return false;
+ }
}
@Override
@@ -1280,6 +1356,11 @@ public class Types {
return t.tag == ARRAY;
}
+ public boolean isFunctionType(Type t) {
+ return (t.tag == CLASS) &&
+ ((ClassType)t).isFunctionType();
+ }
+
/**
* The element type of an array.
*/
@@ -3406,6 +3487,7 @@ public class Types {
public R visitWildcardType(WildcardType t, S s) { return visitType(t, s); }
public R visitArrayType(ArrayType t, S s) { return visitType(t, s); }
public R visitMethodType(MethodType t, S s) { return visitType(t, s); }
+ public R visitFunctionType(FunctionType t, S s) { return visitType(t, s); }
public R visitPackageType(PackageType t, S s) { return visitType(t, s); }
public R visitTypeVar(TypeVar t, S s) { return visitType(t, s); }
public R visitCapturedType(CapturedType t, S s) { return visitType(t, s); }
@@ -3455,6 +3537,10 @@ public class Types {
return visitTypeVar(t, s);
}
@Override
+ public R visitFunctionType(FunctionType t, S s) {
+ return visitClassType(t, s);
+ }
+ @Override
public R visitForAll(ForAll t, S s) {
return visit(t.qtype, s);
}
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java Thu May 27 18:11:12 2010 +0100
@@ -74,6 +74,7 @@ public class Attr extends JCTree.Visitor
final Resolve rs;
final Infer infer;
final Check chk;
+ final Flow flow;
final MemberEnter memberEnter;
final TreeMaker make;
final ConstFold cfolder;
@@ -82,6 +83,7 @@ public class Attr extends JCTree.Visitor
final Types types;
final JCDiagnostic.Factory diags;
final Annotate annotate;
+ final HashMap<JCTree, Env<AttrContext>> lambdaEnvs = new HashMap<JCTree, Env<AttrContext>>();
public static Attr instance(Context context) {
Attr instance = context.get(attrKey);
@@ -98,6 +100,7 @@ public class Attr extends JCTree.Visitor
syms = Symtab.instance(context);
rs = Resolve.instance(context);
chk = Check.instance(context);
+ flow = Flow.instance(context);
memberEnter = MemberEnter.instance(context);
make = TreeMaker.instance(context);
enter = Enter.instance(context);
@@ -1206,21 +1209,33 @@ public class Attr extends JCTree.Visitor
// Check that there is an enclosing method which is
// nested within than the enclosing class.
if (env.enclMethod == null ||
- env.enclMethod.sym.owner != env.enclClass.sym) {
+ (env.enclMethod.sym.owner != env.enclClass.sym &&
+ !env.enclMethod.sym.name.equals(names.lambda))) {
log.error(tree.pos(), "ret.outside.meth");
} else {
// Attribute return expression, if it exists, and check that
// it conforms to result type of enclosing method.
Symbol m = env.enclMethod.sym;
+ boolean isLambda = (env.enclMethod.sym.flags() & LAMBDA) != 0;
if (m.type.getReturnType().tag == VOID) {
if (tree.expr != null)
log.error(tree.expr.pos(),
"cant.ret.val.from.meth.decl.void");
} else if (tree.expr == null) {
- log.error(tree.pos(), "missing.ret.val");
+ if (!isLambda) {
+ log.error(tree.pos(), "missing.ret.val");
+ }
+ else {
+ ((MethodType)m.type).restype = syms.voidType;
+ }
} else {
- attribExpr(tree.expr, env, m.type.getReturnType());
+ attribExpr(tree.expr, env, isLambda ? Type.noType : m.type.getReturnType());
+ if (isLambda) {
+ ((MethodType)m.type).restype = m.type.getReturnType() == Type.noType ?
+ (tree.expr.type == syms.botType ? syms.objectType : tree.expr.type) :
+ condType1(tree.pos(), null, m.type.getReturnType(), tree.expr.type);
+ }
}
}
result = null;
@@ -1345,6 +1360,7 @@ public class Attr extends JCTree.Visitor
// Attribute the arguments, yielding list of argument types, ...
argtypes = attribArgs(tree.args, localEnv);
typeargtypes = attribAnyTypes(tree.typeargs, localEnv);
+
// ... and attribute the method using as a prototype a methodtype
// whose formal argument types is exactly the list of actual
@@ -1808,6 +1824,77 @@ public class Attr extends JCTree.Visitor
if (!types.isReifiable(elemtype))
log.error(tree.pos(), "generic.array.creation");
result = check(tree, owntype, VAL, pkind, pt);
+ }
+
+ /** An environment in which to evaluate a lambda.
+ * This environment is a method environment nested into a class environment.
+ * The compiler generates synthetic symbols for both envs.
+ */
+ Env<AttrContext> lambdaEnvironment(JCLambda tree) {
+ long flags = LAMBDA | (Resolve.isStatic(env) ?
+ STATIC :
+ 0);
+
+ ClassSymbol lambdaClassSym = new ClassSymbol(SYNTHETIC, names.empty, null, env.info.scope.owner);
+ lambdaClassSym.type = new ClassType(env.enclClass.type, List.<Type>nil(), lambdaClassSym);
+ Env<AttrContext> outerEnv = env.dup(breakTree).dup(tree, env.info.dup(new Scope(lambdaClassSym)));
+ outerEnv.outer = env;
+ ((ClassType)lambdaClassSym.type).supertype_field = syms.methodHandleType;
+ outerEnv.enclClass = make.ClassDef(make.Modifiers(SYNTHETIC), names.empty, List.<JCTypeParameter>nil(), null, null, null);
+ outerEnv.enclClass.sym = lambdaClassSym;
+ outerEnv.enclClass.type = lambdaClassSym.type;
+ lambdaClassSym.members_field = outerEnv.info.scope;
+ lambdaEnvs.put(tree, outerEnv);
+ Env<AttrContext> newEnv = outerEnv.dup(tree, outerEnv.info.dup(outerEnv.info.scope.dupUnshared()));
+
+ VarSymbol thisSym =
+ new VarSymbol(FINAL | HASINIT, names._this, lambdaClassSym.type, lambdaClassSym);
+
+ newEnv.info.scope.enter(thisSym);
+
+ newEnv.outer = outerEnv;
+ MethodSymbol lambdaSym = new MethodSymbol(flags, names.lambda, null, outerEnv.info.scope.owner);
+ lambdaSym.type = new MethodType(null, Type.noType, null, syms.methodClass);
+ newEnv.info.scope.owner = lambdaSym;
+ JCBlock body = tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
+ make.Block(0, List.<JCStatement>of(make.Return((JCExpression)tree.body))) :
+ (JCBlock)tree.body;
+ newEnv.enclMethod = make.MethodDef(make.Modifiers(SYNTHETIC), lambdaSym.name, null, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null);
+ newEnv.enclMethod.sym = lambdaSym;
+ newEnv.enclClass.defs = List.<JCTree>of(newEnv.enclMethod);
+ tree.sym = lambdaSym;
+ return newEnv;
+ }
+
+ @Override
+ public void visitLambda(JCLambda that) {
+ Env<AttrContext> localEnv = lambdaEnvironment(that);
+ attribStats(that.params, localEnv);
+ ListBuffer<Type> argtypes = ListBuffer.lb();
+ for (JCTree arg : that.params) {
+ argtypes.append(arg.type);
+ }
+ ((MethodType)localEnv.info.scope.owner.type).argtypes = argtypes.toList();
+ Type resType = null;
+ if (that.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
+ resType = attribExpr(that.getBody(), localEnv);
+ }
+ else {
+ JCBlock body = (JCBlock)that.body;
+ attribStats(body.stats, localEnv);
+ resType = localEnv.info.scope.owner.type.getReturnType();
+ if (resType == null || resType == Type.noType) { //if EXEC
+ resType = syms.voidType;
+ }
+ }
+ if (resType == that.sym.owner.type) {
+ 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);
+ flow.analyzeLambda(that, make);
+ that.sym.type = that.type.asMethodType(types);
+ result = that.type = check(that, that.type, VAL, pkind, pt);
}
public void visitParens(JCParens tree) {
@@ -2747,6 +2834,15 @@ public class Attr extends JCTree.Visitor
tree.type = result = check(tree, types.lub(componentTypes), TYP, pkind, pt);
}
+ @Override
+ public void visitFunctionType(JCFunctionType tree) {
+ //TODO: add proper checking
+ Type resType = attribType(tree.resultType, env);
+ List<Type> argtypes = attribAnyTypes(tree.argumentTypes, env);
+ List<Type> thrown = attribTypes(tree.thrown, env);
+ result = tree.type = new FunctionType(argtypes, resType, thrown, syms.methodHandleType.tsym);
+ }
+
public void visitTypeParameter(JCTypeParameter tree) {
TypeVar a = (TypeVar)tree.type;
Set<Type> boundSet = new HashSet<Type>();
--- a/src/share/classes/com/sun/tools/javac/comp/Check.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/Check.java Thu May 27 18:11:12 2010 +0100
@@ -1064,7 +1064,7 @@ public class Check {
/** Form the union of two type set lists.
*/
- List<Type> union(List<Type> ts1, List<Type> ts2) {
+ public List<Type> union(List<Type> ts1, List<Type> ts2) {
List<Type> ts = ts1;
for (List<Type> l = ts2; l.nonEmpty(); l = l.tail)
ts = incl(l.head, ts);
@@ -1130,7 +1130,7 @@ public class Check {
* @param thrown The list of thrown exceptions.
* @param handled The list of handled exceptions.
*/
- List<Type> unhandled(List<Type> thrown, List<Type> handled) {
+ public List<Type> unhandled(List<Type> thrown, List<Type> handled) {
List<Type> unhandled = List.nil();
for (List<Type> l = thrown; l.nonEmpty(); l = l.tail)
if (!isHandled(l.head, handled)) unhandled = unhandled.prepend(l.head);
--- a/src/share/classes/com/sun/tools/javac/comp/Flow.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/Flow.java Thu May 27 18:11:12 2010 +0100
@@ -187,6 +187,7 @@ public class Flow extends TreeScanner {
private TreeMaker make;
private Lint lint;
private final boolean allowRethrowAnalysis;
+ boolean daEnabled = true;
public static Flow instance(Context context) {
Flow instance = context.get(flowKey);
@@ -332,7 +333,7 @@ public class Flow extends TreeScanner {
* I.e. is symbol either a local or a blank final variable?
*/
boolean trackable(VarSymbol sym) {
- return
+ return daEnabled &&
(sym.owner.kind == MTH ||
((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
classDef.sym.isEnclosedBy((ClassSymbol)sym.owner)));
@@ -1209,6 +1210,59 @@ public class Flow extends TreeScanner {
public void visitNewArray(JCNewArray tree) {
scanExprs(tree.dims);
scanExprs(tree.elems);
+ }
+
+ public void analyzeLambda(JCLambda tree, TreeMaker make) {
+ boolean prevDaEnabled = daEnabled;
+ try {
+ daEnabled = false;
+ analyzeTree(tree, make);
+ }
+ finally {
+ daEnabled = prevDaEnabled;
+ }
+ }
+
+ @Override
+ public void visitLambda(JCLambda tree) {
+ List<Type> prevCaught = caught;
+ List<Type> prevThrown = thrown;
+ Bits prevUninits = uninits;
+ Bits prevInits = inits;
+ ListBuffer<PendingExit> prevPending = pendingExits;
+ boolean prevAlive = alive;
+ try {
+ caught = List.of(syms.throwableType); //inhibit exception checking
+ thrown = List.nil();
+ uninits = uninits.dup();
+ inits = inits.dup();
+ pendingExits = new ListBuffer<PendingExit>();
+ for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
+ JCVariableDecl def = l.head;
+ scan(def);
+ if (daEnabled) {
+ inits.incl(def.sym.adr);
+ uninits.excl(def.sym.adr);
+ }
+ }
+ alive = true;
+ scanStat(tree.body);
+ if (tree.getBodyKind() == JCLambda.BodyKind.STATEMENT &&
+ alive && tree.type.getReturnType().tag != VOID) {
+ log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
+ }
+ if (tree.type.getThrownTypes() == null) {
+ tree.type.setThrown(thrown);
+ }
+ }
+ finally {
+ caught = prevCaught;
+ thrown = prevThrown;
+ uninits = prevUninits;
+ inits = prevInits;
+ alive = prevAlive;
+ pendingExits = prevPending;
+ }
}
public void visitAssert(JCAssert tree) {
--- a/src/share/classes/com/sun/tools/javac/comp/Lower.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/Lower.java Thu May 27 18:11:12 2010 +0100
@@ -124,6 +124,10 @@ public class Lower extends TreeTranslato
*/
Map<JCTree, Integer> endPositions;
+ /** A hash table mapping class trees to a ist of translated lambda defs.
+ */
+ Map<ClassSymbol, List<JCMethodDecl>> translatedLambdas = new HashMap<ClassSymbol, List<JCMethodDecl>>();
+
/**************************************************************************
* Global mappings
*************************************************************************/
@@ -164,6 +168,13 @@ public class Lower extends TreeTranslato
public void visitClassDef(JCClassDecl tree) {
classdefs.put(tree.sym, tree);
super.visitClassDef(tree);
+ }
+
+ /** All encountered class defs are entered into classdefs table.
+ */
+ public void visitLambda(JCLambda tree) {
+ classdefs.put((ClassSymbol)tree.sym.owner, attr.lambdaEnvs.get(tree).enclClass);
+ super.visitLambda(tree);
}
}
ClassMap classMap = new ClassMap();
@@ -1679,6 +1690,12 @@ public class Lower extends TreeTranslato
return make.App(make.Select(left, funcsym), args);
}
+ private JCNewArray makeArray(Type elemType, List<JCExpression> elems) {
+ Type arrType = new ArrayType(elemType, syms.arrayClass);
+ return (JCNewArray)make.NewArray(make.QualIdent(elemType.tsym),
+ List.<JCExpression>nil(), elems).setType(arrType);
+ }
+
/** The Name Of The variable to cache T.class values.
* @param sig The signature of type T.
*/
@@ -1950,7 +1967,7 @@ public class Lower extends TreeTranslato
/** Visitor method: Translate a single node, boxing or unboxing if needed.
*/
public <T extends JCTree> T translate(T tree, Type type) {
- return (tree == null) ? null : boxIfNeeded(translate(tree), type);
+ return (tree == null) ? null : unlambdaIfNeeded(boxIfNeeded(translate(tree), type), type);
}
/** Visitor method: Translate tree.
@@ -2012,7 +2029,7 @@ public class Lower extends TreeTranslato
currentClass = tree.sym;
currentMethodSym = null;
classdefs.put(currentClass, tree);
-
+ translatedLambdas.put(currentClass, List.<JCMethodDecl>nil());
proxies = proxies.dup(currentClass);
List<VarSymbol> prevOuterThisStack = outerThisStack;
@@ -2065,6 +2082,13 @@ public class Lower extends TreeTranslato
if (currentClass.hasOuterInstance()) {
tree.defs = tree.defs.prepend(otdef);
enterSynthetic(tree.pos(), otdef.sym, currentClass.members());
+ }
+
+ if (translatedLambdas.get(currentClass).nonEmpty()) {
+ for (JCMethodDecl lambda : translatedLambdas.get(currentClass)) {
+ tree.defs = tree.defs.prepend(lambda);
+ enterSynthetic(tree.pos(), lambda.sym, currentClass.members());
+ }
}
proxies = proxies.leave();
@@ -2533,6 +2557,12 @@ public class Lower extends TreeTranslato
public void visitApply(JCMethodInvocation tree) {
Symbol meth = TreeInfo.symbol(tree.meth);
+ if (meth.name == names.empty &&
+ meth.owner == syms.methodHandleType.tsym &&
+ (meth.flags() & LAMBDA) != 0) {
+ visitLambdaCall(tree, meth);
+ return;
+ }
List<Type> argtypes = meth.type.getParameterTypes();
if (allowEnums &&
meth.name==names.init &&
@@ -2593,7 +2623,7 @@ public class Lower extends TreeTranslato
} else {
// We are seeing a normal method invocation; translate this as usual.
tree.meth = translate(tree.meth);
-
+
// If the translated method itself is an Apply tree, we are
// seeing an access method invocation. In this case, append
// the method arguments to the arguments of the access method.
@@ -2605,6 +2635,19 @@ public class Lower extends TreeTranslato
}
}
result = tree;
+ }
+
+ void visitLambdaCall(JCMethodInvocation tree, Symbol meth) {
+ JCExpression translatedCall = makeCall(((JCFieldAccess)tree.meth).selected,
+ names.invokeVarargs,
+ List.<JCExpression>of(makeArray(syms.objectType, tree.args)));
+ Type expectedType = meth.type.getReturnType();
+ translatedCall = (JCExpression)convert(translatedCall,
+ expectedType.isPrimitive() ?
+ types.boxedClass(expectedType).type :
+ expectedType);
+ result = translate(translatedCall, expectedType);
+ return;
}
List<JCExpression> boxArgs(List<Type> parameters, List<JCExpression> _args, Type varargsElement) {
@@ -2699,6 +2742,19 @@ public class Lower extends TreeTranslato
tree.type,
List.<Type>nil());
return make.App(make.Select(tree, valueSym));
+ }
+
+ @SuppressWarnings("unchecked") // XXX unchecked
+ <T extends JCTree> T unlambdaIfNeeded(T tree, Type type) {
+ if (types.isSameType(tree.type, syms.methodHandleType) &&
+ types.findSAM(type) != null) {
+ List<JCExpression> args = List.of((JCExpression)tree, classOfType(type, tree.pos()));
+ JCMethodInvocation proxyCall = makeCall(make.QualIdent(syms.proxyHelper.tsym), names.makeProxy, args).setType(syms.objectType);
+ return (T)convert(proxyCall, type);
+ }
+ else {
+ return tree;
+ }
}
/** Visitor method for parenthesized expressions.
@@ -3338,6 +3394,139 @@ public class Lower extends TreeTranslato
result = tree;
}
+ Name lambdaName() {
+ return names.lambda.append(names.fromString("$" + translatedLambdas.get(currentClass).size()));
+ }
+
+ public void visitLambda(JCLambda tree) {
+ MethodSymbol lambdaSym = new MethodSymbol(SYNTHETIC | STATIC, lambdaName(), null, currentClass);
+ MethodType lambdaType = (MethodType)types.erasure(tree.sym.type);
+ lambdaSym.type = lambdaType;
+
+ //compute synthetic params
+ ListBuffer<JCVariableDecl> syntheticParams = ListBuffer.lb();
+ List<VarSymbol> freevars = List.nil();
+ //add MethodHandle param
+ syntheticParams.append(make.Param(names._this, syms.methodHandleType, lambdaSym));
+ if (!tree.sym.isStatic()) {
+ //add this$0
+ syntheticParams.append(make.Param(outerThisName(currentClass.type, lambdaSym), currentClass.type, lambdaSym));
+ }
+ //add freevars
+ freevars = freevars((ClassSymbol)tree.sym.owner);
+ for (VarSymbol fv : freevars) {
+ JCVariableDecl proxy = make.Param(proxyName(fv.name), fv.type, lambdaSym);
+ proxy.sym.flags_field |= FINAL | SYNTHETIC;
+ syntheticParams.append(proxy);
+ }
+
+ //prepend synthetic args to translated lambda method signature
+ lambdaType.argtypes = lambdaType.argtypes.prependList(TreeInfo.types(syntheticParams.toList()));
+
+ //create method declaration hoisting the lambda body
+ JCBlock body = tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
+ make.Block(0, List.<JCStatement>of(make.Return((JCExpression)tree.body))) :
+ (JCBlock)tree.body;
+ JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(STATIC),
+ lambdaSym.name,
+ make.QualIdent(lambdaType.getReturnType().tsym),
+ List.<JCTypeParameter>nil(),
+ tree.params.prependList(syntheticParams.toList()),
+ tree.sym.type.getThrownTypes() == null ?
+ List.<JCExpression>nil() :
+ make.Types(tree.sym.type.getThrownTypes()),
+ body,
+ null);
+ lambdaDecl.sym = lambdaSym;
+ lambdaDecl.type = lambdaType;
+
+ //save current translation context
+
+ List<VarSymbol> prevOuterThisStack = outerThisStack;
+ ClassSymbol prevClass = currentClass;
+ Scope prevProxies = proxies;
+
+ //lower translated lambda method
+ try {
+ ListBuffer<JCVariableDecl> syntheticTransParams = ListBuffer.lb();
+ currentClass = (ClassSymbol)tree.sym.owner;
+ proxies = proxies.dupUnshared();
+ if (!tree.sym.isStatic()) {
+ JCVariableDecl _this$0 = outerThisDef(tree.pos, tree.sym.owner);
+ outerThisStack =
+ outerThisStack.prepend(_this$0.sym);
+ syntheticTransParams.append(_this$0);
+ }
+ List<JCVariableDecl> fvdefs = freevarDefs(tree.pos,
+ freevars((ClassSymbol)tree.sym.owner),
+ tree.sym.owner);
+ syntheticTransParams.appendList(fvdefs);
+ JCMethodDecl transLambda = translate(lambdaDecl);
+ patchLambda(transLambda, syntheticTransParams.toList(), syntheticParams.toList().tail);
+ translatedLambdas.put(prevClass, translatedLambdas.get(prevClass).prepend(transLambda));
+ }
+ finally {
+ currentClass = prevClass;
+ outerThisStack = prevOuterThisStack;
+ proxies = prevProxies;
+ }
+
+ //generate method handle and pre-initialize synthetic arguments
+ VarSymbol handleSym =
+ new VarSymbol(SYNTHETIC, names.fromString("i" + target.syntheticNameChar()), syms.methodHandleType, lambdaSym);
+ JCVariableDecl handleDecl = make.VarDef(handleSym, makeMethodHandle(lambdaSym));
+ JCExpression handleRef = make.Ident(handleSym);
+ ListBuffer<JCExpression> syntheticInits = ListBuffer.lb();
+ syntheticInits.append(handleRef);
+ if (!tree.sym.isStatic()) {
+ syntheticInits.append(makeThis(tree.pos(), currentClass));
+ }
+ for (VarSymbol fv : freevars) {
+ syntheticInits.append(make.Ident(fv));
+ }
+ JCExpression insertArgumentsArgs = makeArray(syms.objectType, syntheticInits.toList());
+ JCExpression insertArgumentsCall =
+ makeCall(make.QualIdent(syms.methodHandlesType.tsym), names.insertArguments, List.of(handleRef, makeLit(syms.intType, 0), insertArgumentsArgs));
+ result = make.LetExpr(handleDecl, insertArgumentsCall).setType(syms.methodHandleType);
+ }
+
+ void patchLambda(JCTree tree, final List<JCVariableDecl> from, final List<JCVariableDecl> to) {
+ class LambdaPatcher extends TreeScanner {
+ HashMap<Symbol, Symbol> map = new HashMap<Symbol, Symbol>();
+ LambdaPatcher() {
+ List<JCVariableDecl> to2 = to;
+ for (JCVariableDecl v : from) {
+ map.put(v.sym, to2.head.sym);
+ to2 = to2.tail;
+ }
+ }
+ @Override
+ public void visitIdent(JCIdent ident) {
+ if (map.containsKey(ident.sym)) {
+ ident.sym = map.get(ident.sym);
+ ident.type = ident.sym.type;
+ ident.name = ident.sym.name;
+ }
+ }
+ }
+ new LambdaPatcher().scan(tree);
+ }
+
+ JCExpression makeMethodHandle(MethodSymbol msym) {
+ String sig = writer.typeSig(msym.type).toString();
+ ListBuffer<JCExpression> args1 = ListBuffer.lb();
+ args1.append(make.Literal(sig).setType(syms.stringType));
+ args1.append(makeNull());
+
+ ListBuffer<JCExpression> args2 = ListBuffer.lb();
+ args2.append(make.ClassLiteral(currentClass).setType(syms.classType.tsym.erasure(types)));
+ args2.append(make.Literal(msym.name.toString()).setType(syms.stringType));
+ args2.append(makeCall(make.QualIdent(syms.methodTypeType.tsym), names.fromMethodDescriptorString, args1.toList()));
+
+ JCExpression rec = makeCall(make.QualIdent(syms.methodHandlesType.tsym), names.lookup, List.<JCExpression>nil());
+ return makeCall(rec, names.findStatic, args2.toList());
+ }
+
public void visitSelect(JCFieldAccess tree) {
// need to special case-access of the form C.super.x
// these will always need an access method.
--- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java Thu May 27 18:11:12 2010 +0100
@@ -903,27 +903,37 @@ public class Resolve {
List<Type> argtypes,
List<Type> typeargtypes) {
assert allowInvokedynamic;
- assert site == syms.invokeDynamicType || (site == syms.methodHandleType && name == names.invoke);
+ assert needsImplicitResolution(site, name);
ClassSymbol c = (ClassSymbol) site.tsym;
Scope implicit = c.members().next;
if (implicit == null) {
c.members().next = implicit = new Scope(c);
}
Type restype;
- if (typeargtypes.isEmpty()) {
- restype = syms.objectType;
- } else {
- restype = typeargtypes.head;
- if (!typeargtypes.tail.isEmpty())
- return methodNotFound;
+ List<Type> thrown = List.nil();
+ if (types.isFunctionType(site)) {
+ restype = site.getReturnType();
+ thrown = site.getThrownTypes();
+ }
+ else {
+ if (typeargtypes.isEmpty()) {
+ restype = syms.objectType;
+ } else {
+ restype = typeargtypes.head;
+ if (!typeargtypes.tail.isEmpty())
+ return methodNotFound;
+ }
}
List<Type> paramtypes = Type.map(argtypes, implicitArgType);
MethodType mtype = new MethodType(paramtypes,
restype,
- List.<Type>nil(),
+ thrown,
syms.methodClass);
- int flags = PUBLIC | ABSTRACT;
+ long flags = PUBLIC | ABSTRACT;
if (site == syms.invokeDynamicType) flags |= STATIC;
+ else if (types.isFunctionType(site)) {
+ flags |= LAMBDA;
+ }
Symbol m = null;
for (Scope.Entry e = implicit.lookup(name);
e.scope != null;
@@ -1340,8 +1350,7 @@ public class Resolve {
}
if (sym.kind >= AMBIGUOUS &&
allowInvokedynamic &&
- (site == syms.invokeDynamicType ||
- site == syms.methodHandleType && name == names.invoke)) {
+ needsImplicitResolution(site, name)) {
// lookup failed; supply an exactly-typed implicit method
sym = findImplicitMethod(env, site, name, argtypes, typeargtypes);
env.info.varArgs = false;
@@ -1354,6 +1363,12 @@ public class Resolve {
env.info.varArgs = errPhase.isVarargsRequired;
}
return sym;
+ }
+
+ boolean needsImplicitResolution(Type site, Name name) {
+ return site == syms.invokeDynamicType ||
+ (site == syms.methodHandleType && name == names.invoke) ||
+ (types.isFunctionType(site) && name == names.empty);
}
/** Resolve a qualified method identifier, throw a fatal error if not
@@ -1775,6 +1790,12 @@ public class Resolve {
if (name == names.error)
return null;
+ if (name == names.empty &&
+ !types.isFunctionType(site)) {
+ return diags.create(dkind, false, log.currentSource(), pos,
+ "lambda.call.non.func.type", site);
+ }
+
if (isOperator(name)) {
return diags.create(dkind, false, log.currentSource(), pos,
"operator.cant.be.applied", name, argtypes);
--- a/src/share/classes/com/sun/tools/javac/comp/TransTypes.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/TransTypes.java Thu May 27 18:11:12 2010 +0100
@@ -123,6 +123,10 @@ public class TransTypes extends TreeTran
* @param target The target type.
*/
JCExpression coerce(JCExpression tree, Type target) {
+ if (types.isSameType(tree.type, syms.methodHandleType) &&
+ types.findSAM(target) != null) {
+ return tree;
+ }
Type btarget = target.baseType();
if (tree.type.isPrimitive() == target.isPrimitive()) {
return types.isAssignable(tree.type, btarget, Warner.noWarnings)
@@ -444,12 +448,12 @@ public class TransTypes extends TreeTran
result = tree;
}
- JCMethodDecl currentMethod = null;
+ Symbol currentMethod = null;
public void visitMethodDef(JCMethodDecl tree) {
tree.sym.typeAnnotations = tree.sym.typeAnnotations;
- JCMethodDecl previousMethod = currentMethod;
+ Symbol previousMethod = currentMethod;
try {
- currentMethod = tree;
+ currentMethod = tree.sym;
tree.restype = translate(tree.restype, null);
tree.typarams = List.nil();
tree.params = translateVarDefs(tree.params);
@@ -513,6 +517,20 @@ public class TransTypes extends TreeTran
result = tree;
}
+ public void visitLambda(JCLambda tree) {
+ Symbol prevMethod = currentMethod;
+ Type prevPt = pt;
+ try {
+ currentMethod = tree.sym;
+ pt = null;
+ super.visitLambda(tree);
+ }
+ finally {
+ currentMethod = prevMethod;
+ pt = prevPt;
+ }
+ }
+
public void visitSwitch(JCSwitch tree) {
Type selsuper = types.supertype(tree.selector.type);
boolean enumSwitch = selsuper != null &&
@@ -556,7 +574,7 @@ public class TransTypes extends TreeTran
}
public void visitReturn(JCReturn tree) {
- tree.expr = translate(tree.expr, currentMethod.sym.erasure(types).getReturnType());
+ tree.expr = translate(tree.expr, currentMethod.erasure(types).getReturnType());
result = tree;
}
@@ -738,6 +756,11 @@ public class TransTypes extends TreeTran
result = clazz;
}
+ @Override
+ public void visitFunctionType(JCFunctionType that) {
+ result = make.QualIdent(syms.methodHandleType.tsym).setType(syms.methodHandleType).setPos(that.pos);
+ }
+
/**************************************************************************
* utility methods
*************************************************************************/
--- a/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Thu May 27 18:11:12 2010 +0100
@@ -918,7 +918,7 @@ public class ClassReader implements Comp
for (int j = 0; j < nexceptions; j++)
thrown = thrown.prepend(readClassSymbol(nextChar()).type);
if (sym.type.getThrownTypes().isEmpty())
- sym.type.asMethodType().thrown = thrown.reverse();
+ sym.type.asMethodType(types).thrown = thrown.reverse();
}
},
@@ -1017,7 +1017,7 @@ public class ClassReader implements Comp
sym.type = readType(nextChar());
//- System.err.println(" # " + sym.type);
if (sym.kind == MTH && sym.type.getThrownTypes().isEmpty())
- sym.type.asMethodType().thrown = thrown;
+ sym.type.asMethodType(types).thrown = thrown;
}
}
@@ -1174,10 +1174,10 @@ public class ClassReader implements Comp
if (nt == null)
return null;
- MethodType type = nt.type.asMethodType();
+ MethodType type = nt.type.asMethodType(types);
for (Scope.Entry e = scope.lookup(nt.name); e.scope != null; e = e.next())
- if (e.sym.kind == MTH && isSameBinaryType(e.sym.type.asMethodType(), type))
+ if (e.sym.kind == MTH && isSameBinaryType(e.sym.type.asMethodType(types), type))
return (MethodSymbol)e.sym;
if (nt.name != names.init)
--- a/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Thu May 27 18:11:12 2010 +0100
@@ -416,7 +416,7 @@ public class ClassWriter extends ClassFi
/** Return signature of given type
*/
- Name typeSig(Type type) {
+ public Name typeSig(Type type) {
assert sigbuf.length == 0;
//- System.out.println(" ? " + type);
assembleSig(type);
--- a/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Thu May 27 18:11:12 2010 +0100
@@ -29,6 +29,7 @@ import java.util.*;
import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.main.OptionName;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.List;
import static com.sun.tools.javac.util.ListBuffer.lb;
@@ -134,6 +135,9 @@ public class JavacParser implements Pars
this.allowDiamond = source.allowDiamond();
this.allowMulticatch = source.allowMulticatch();
this.allowTypeAnnotations = source.allowTypeAnnotations();
+ this.allowLambda = source.allowLambda();
+ this.allowFunctionTypes = source.allowLambda() &&
+ fac.options.get("allowFunctionTypes") != null;
this.keepDocComments = keepDocComments;
if (keepDocComments)
docComments = new HashMap<JCTree,String>();
@@ -185,6 +189,14 @@ public class JavacParser implements Pars
/** Switch: should we recognize type annotations?
*/
boolean allowTypeAnnotations;
+
+ /** Switch: should we recognize lambda expressions?
+ */
+ boolean allowLambda;
+
+ /** Switch: should we recognize function types?
+ */
+ boolean allowFunctionTypes;
/** Switch: should we keep docComments?
*/
@@ -896,10 +908,13 @@ public class JavacParser implements Pars
* | "." ( CLASS | THIS | [TypeArguments] SUPER Arguments | NEW [TypeArguments] InnerCreator )
* ]
* | BasicType BracketsOpt "." CLASS
+ * | "#" "(" Arguments ")" "(" Expression ")"
+ * | "#" "(" Arguments ")" Block
* PrefixOp = "++" | "--" | "!" | "~" | "+" | "-"
* PostfixOp = "++" | "--"
* Type3 = Ident { "." Ident } [TypeArguments] {TypeSelector} BracketsOpt
* | BasicType
+ * | "#" Type3 "(" {VarDecl} ")" ["(" Type3 {["," Type3]}]
* TypeNoParams3 = Ident { "." Ident } BracketsOpt
* Selector = "." [TypeArguments] Ident [Arguments]
* | "." THIS
@@ -935,6 +950,10 @@ public class JavacParser implements Pars
return F.at(pos).Unary(unoptag(token), t);
}
} else return illegal();
+ break;
+ case HASH:
+ S.nextToken();
+ t = lambdaOrFunctionType();
break;
case LPAREN:
if (typeArgs == null && (mode & EXPR) != 0) {
@@ -1145,6 +1164,11 @@ public class JavacParser implements Pars
t = innerCreator(pos1, typeArgs, t);
typeArgs = null;
break loop;
+ case LPAREN:
+ //creates lambda call --- standard apply
+ checkLambda();
+ t = arguments(typeArgs, toP(F.at(S.pos()).Select(t, names.empty)));
+ break loop;
}
}
// typeArgs saved for next loop iteration.
@@ -1218,24 +1242,31 @@ public class JavacParser implements Pars
} else if (S.token() == DOT) {
S.nextToken();
typeArgs = typeArgumentsOpt(EXPR);
- if (S.token() == SUPER && (mode & EXPR) != 0) {
- mode = EXPR;
- t = to(F.at(pos1).Select(t, names._super));
- S.nextToken();
- t = arguments(typeArgs, t);
- typeArgs = null;
- } else if (S.token() == NEW && (mode & EXPR) != 0) {
- if (typeArgs != null) return illegal();
- mode = EXPR;
- int pos2 = S.pos();
- S.nextToken();
- if (S.token() == LT) typeArgs = typeArguments();
- t = innerCreator(pos2, typeArgs, t);
- typeArgs = null;
- } else {
- t = toP(F.at(pos1).Select(t, ident()));
- t = argumentsOpt(typeArgs, typeArgumentsOpt(t));
- typeArgs = null;
+ if (S.token() == LPAREN) {
+ //creates lambda call --- standard apply
+ checkLambda();
+ t = arguments(typeArgs, toP(F.at(S.pos()).Select(t, names.empty)));
+ }
+ else {
+ if (S.token() == SUPER && (mode & EXPR) != 0) {
+ mode = EXPR;
+ t = to(F.at(pos1).Select(t, names._super));
+ S.nextToken();
+ t = arguments(typeArgs, t);
+ typeArgs = null;
+ } else if (S.token() == NEW && (mode & EXPR) != 0) {
+ if (typeArgs != null) return illegal();
+ mode = EXPR;
+ int pos2 = S.pos();
+ S.nextToken();
+ if (S.token() == LT) typeArgs = typeArguments();
+ t = innerCreator(pos2, typeArgs, t);
+ typeArgs = null;
+ } else {
+ t = toP(F.at(pos1).Select(t, ident()));
+ t = argumentsOpt(typeArgs, typeArgumentsOpt(t));
+ typeArgs = null;
+ }
}
} else {
if (!annos.isEmpty()) {
@@ -1255,6 +1286,53 @@ public class JavacParser implements Pars
}
return toP(t);
+ }
+
+ JCExpression lambdaOrFunctionType() {
+ return (mode & EXPR) != 0 ?
+ lambdaExpressionOrStatement() :
+ (mode & TYPE) != 0 ?
+ functionType() :
+ illegal();
+ }
+
+ JCExpression lambdaExpressionOrStatement() {
+ checkLambda();
+ int pos = S.pos();
+ List<JCVariableDecl> args = formalParameters();
+ return S.token() == LBRACE ?
+ lambdaExpression(args, pos) :
+ S.token() == LPAREN ?
+ lambdaStatement(args, pos) :
+ illegal();
+ }
+
+ JCExpression lambdaExpression(List<JCVariableDecl> args, int pos) {
+ JCBlock block = block();
+ return toP(F.at(pos).Lambda(args, block));
+ }
+
+ JCExpression lambdaStatement(List<JCVariableDecl> args, int pos) {
+ accept(LPAREN);
+ JCTree expr = parseExpression();
+ accept(RPAREN);
+ return toP(F.at(pos).Lambda(args, expr));
+ }
+
+ JCExpression functionType() {
+ checkFunctionTypes();
+ JCExpression retType = parseType();
+ accept(LPAREN);
+ List<JCExpression> args = typeList();
+ accept(RPAREN);
+ List<JCExpression> thrown = List.nil();
+ if (S.token() == LPAREN) {
+ S.nextToken();
+ accept(THROWS);
+ thrown = qualidentList();
+ accept(RPAREN);
+ }
+ return toP(F.at(S.pos()).FunctionType(args, retType, thrown));
}
/** SuperSuffix = Arguments | "." [TypeArguments] Ident [Arguments]
@@ -1754,6 +1832,7 @@ public class JavacParser implements Pars
stats.append(parseStatement());
break;
case MONKEYS_AT:
+ case HASH:
case FINAL: {
String dc = S.docComment();
JCModifiers mods = modifiersOpt();
@@ -3216,6 +3295,18 @@ public class JavacParser implements Pars
if (!allowMulticatch) {
log.error(S.pos(), "multicatch.not.supported.in.source", source.name);
allowMulticatch = true;
- }
+ }
+ }
+ void checkLambda() {
+ if (!allowLambda) {
+ log.error(S.pos(), "lambda.not.supported.in.source", source.name);
+ allowLambda = true;
+ }
+ }
+ void checkFunctionTypes() {
+ if (!allowFunctionTypes) {
+ log.error(S.pos(), "func.types.not.supported.in.source", source.name);
+ allowFunctionTypes = true;
+ }
}
}
--- a/src/share/classes/com/sun/tools/javac/parser/Scanner.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/parser/Scanner.java Thu May 27 18:11:12 2010 +0100
@@ -1024,7 +1024,7 @@ public class Scanner implements Lexer {
lexError(pos, "unclosed.bytecode.ident");
}
} else {
- lexError("illegal.char", String.valueOf((int)'#'));
+ token = HASH;
}
return;
default:
--- a/src/share/classes/com/sun/tools/javac/parser/Token.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/parser/Token.java Thu May 27 18:11:12 2010 +0100
@@ -110,6 +110,7 @@ public enum Token implements Formattable
SEMI(";"),
COMMA(","),
DOT("."),
+ HASH("#"),
ELLIPSIS("..."),
EQ("="),
GT(">"),
--- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties Thu May 27 18:11:12 2010 +0100
@@ -1096,6 +1096,12 @@ compiler.err.cant.resolve.location.args.
symbol: {0} <{2}>{1}({3})\n\
location: {4} {5}
+compiler.err.lambda.call.non.func.type=\
+ lambda invocation syntax cannot be used on non-lambda type {0}
+
+compiler.err.cannot.infer.lambda.return.type=\
+ return type of the lambda expression cannot be inferred because of a cyclic reference to ''this''
+
## The following are all possible string for "kindname".
## They should be called whatever the JLS calls them after it been translated
## to the appropriate language.
@@ -1247,6 +1253,14 @@ compiler.err.string.switch.not.supported
strings in switch are not supported in -source {0}\n\
(use -source 7 or higher to enable strings in switch)
+compiler.err.lambda.not.supported.in.source=\
+ lambda expressions are not supported in -source {0}\n\
+(use -source 7 or higher to enable strings in switch)
+
+compiler.err.func.types.not.supported.in.source=\
+ lambda expressions are not supported in -source {0}\n\
+(use -source 7 or higher to enable strings in switch and -XDallowFunctionTypes)
+
########################################
# Diagnostics for where clause implementation
# used by the RichDiagnosticFormatter.
--- a/src/share/classes/com/sun/tools/javac/tree/JCTree.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/tree/JCTree.java Thu May 27 18:11:12 2010 +0100
@@ -192,9 +192,13 @@ public abstract class JCTree implements
*/
public static final int NEWARRAY = NEWCLASS + 1;
+ /** Lambda expression, of type NewArray.
+ */
+ public static final int LAMBDA = NEWARRAY + 1;
+
/** Parenthesized subexpressions, of type Parens.
*/
- public static final int PARENS = NEWARRAY + 1;
+ public static final int PARENS = LAMBDA + 1;
/** Assignment expressions, of type Assign.
*/
@@ -240,9 +244,13 @@ public abstract class JCTree implements
*/
public static final int TYPEDISJOINT = TYPEAPPLY + 1;
+ /** Function types, of type FunctionType.
+ */
+ public static final int TYPEFUNCTION = TYPEDISJOINT + 1;
+
/** Formal type parameters, of type TypeParameter.
*/
- public static final int TYPEPARAMETER = TYPEDISJOINT + 1;
+ public static final int TYPEPARAMETER = TYPEFUNCTION + 1;
/** Type argument.
*/
@@ -1415,6 +1423,62 @@ public abstract class JCTree implements
}
}
+ /** A lambda expression.
+ * @param parameters the lambda's formal parameters.
+ * @param stats the statements in the body of the lambda.
+ * @param result the result expression of the lambda, or null if there is none.
+ */
+ public static class JCLambda extends JCExpression implements LambdaExpressionTree {
+
+ public enum BodyKind {
+ EXPRESSION,
+ STATEMENT;
+ }
+ public List<JCVariableDecl> params;
+ public JCTree body;
+ public Symbol sym;
+
+ public JCLambda(List<JCVariableDecl> params,
+ JCTree body) {
+ this.params = params;
+ this.body = body;
+ }
+ @Override
+ public int getTag() {
+ return LAMBDA;
+ }
+ @Override
+ public void accept(Visitor v) {
+ v.visitLambda(this);
+ }
+ @Override
+ public <R, D> R accept(TreeVisitor<R, D> v, D d) {
+ return v.visitLambdaExpression(this, d);
+ }
+ public Kind getKind() {
+ return Kind.LAMBDA_EXPRESSION;
+ }
+ public JCTree getBody() {
+ return body;
+ }
+ public java.util.List<? extends VariableTree> getParameters() {
+ return params;
+ }
+ @Override
+ public JCLambda setType(Type type) {
+ super.setType(type);
+ return this;
+ }
+ public BodyKind getBodyKind() {
+ if (body.getTag() == BLOCK) {
+ return BodyKind.STATEMENT;
+ }
+ else {
+ return BodyKind.EXPRESSION;
+ }
+ }
+ }
+
/**
* A parenthesized subexpression ( ... )
*/
@@ -1891,6 +1955,49 @@ public abstract class JCTree implements
@Override
public int getTag() {
return TYPEDISJOINT;
+ }
+ }
+
+ /** A function type.
+ * @param argumentTypes the types of the function arguments.
+ * @param resultType the type of the result of the function.
+ * @param thrown the list of checked excpetions thrown by the function.
+ */
+ public static class JCFunctionType extends JCExpression implements FunctionTypeTree {
+ public List<JCExpression> argumentTypes;
+ public JCExpression resultType;
+ public List<JCExpression> thrown;
+
+ public JCFunctionType(List<JCExpression> argumentTypes,
+ JCExpression resultType,
+ List<JCExpression> thrown) {
+ this.argumentTypes = argumentTypes;
+ this.resultType = resultType;
+ this.thrown = thrown;
+ }
+ @Override
+ public int getTag() {
+ return TYPEFUNCTION;
+ }
+ @Override
+ public void accept(Visitor v) {
+ v.visitFunctionType(this);
+ }
+ @Override
+ public <R, D> R accept(TreeVisitor<R, D> v, D d) {
+ return v.visitFunctionType(this, d);
+ }
+ public java.util.List<? extends Tree> getArgumentTypes() {
+ return argumentTypes;
+ }
+ public Tree getResultType() {
+ return resultType;
+ }
+ public java.util.List<? extends ExpressionTree> getThrownTypes() {
+ return thrown;
+ }
+ public Kind getKind() {
+ return Kind.FUNCTION_TYPE;
}
}
@@ -2238,6 +2345,7 @@ public abstract class JCTree implements
public void visitApply(JCMethodInvocation that) { visitTree(that); }
public void visitNewClass(JCNewClass that) { visitTree(that); }
public void visitNewArray(JCNewArray that) { visitTree(that); }
+ public void visitLambda(JCLambda that) { visitTree(that); }
public void visitParens(JCParens that) { visitTree(that); }
public void visitAssign(JCAssign that) { visitTree(that); }
public void visitAssignop(JCAssignOp that) { visitTree(that); }
@@ -2253,6 +2361,7 @@ public abstract class JCTree implements
public void visitTypeArray(JCArrayTypeTree that) { visitTree(that); }
public void visitTypeApply(JCTypeApply that) { visitTree(that); }
public void visitTypeDisjoint(JCTypeDisjoint that) { visitTree(that); }
+ public void visitFunctionType(JCFunctionType that) { visitTree(that); }
public void visitTypeParameter(JCTypeParameter that) { visitTree(that); }
public void visitWildcard(JCWildcard that) { visitTree(that); }
public void visitTypeBoundKind(TypeBoundKind that) { visitTree(that); }
--- a/src/share/classes/com/sun/tools/javac/tree/Pretty.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/tree/Pretty.java Thu May 27 18:11:12 2010 +0100
@@ -907,6 +907,23 @@ public class Pretty extends JCTree.Visit
print("{");
printExprs(tree.elems);
print("}");
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ public void visitLambda(JCLambda tree) {
+ try {
+ print("#(");
+ printExprs(tree.params);
+ print(")");
+ if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
+ print("(");
+ }
+ printStat(tree.body);
+ if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
+ print(")");
}
} catch (IOException e) {
throw new UncheckedIOException(e);
@@ -1190,6 +1207,22 @@ public class Pretty extends JCTree.Visit
}
}
+ public void visitFunctionType(JCFunctionType tree) {
+ try {
+ print("#");
+ print("(");
+ printExprs(tree.argumentTypes);
+ print(")");
+ if (tree.thrown.nonEmpty()) {
+ print("(");
+ printExprs(tree.thrown);
+ print(")");
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
public void visitTypeParameter(JCTypeParameter tree) {
try {
print(tree.name);
--- a/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java Thu May 27 18:11:12 2010 +0100
@@ -279,6 +279,13 @@ public class TreeCopier<P> implements Tr
return M.at(t.pos).NewClass(encl, typeargs, clazz, args, def);
}
+ public JCTree visitLambdaExpression(LambdaExpressionTree node, P p) {
+ JCLambda t = (JCLambda) node;
+ List<JCVariableDecl> params = copy(t.params, p);
+ JCTree body = copy(t.body, p);
+ return M.at(t.pos).Lambda(params, body);
+ }
+
public JCTree visitParenthesized(ParenthesizedTree node, P p) {
JCParens t = (JCParens) node;
JCExpression expr = copy(t.expr, p);
@@ -349,6 +356,14 @@ public class TreeCopier<P> implements Tr
JCTypeDisjoint t = (JCTypeDisjoint) node;
List<JCExpression> components = copy(t.components, p);
return M.at(t.pos).TypeDisjoint(components);
+ }
+
+ public JCTree visitFunctionType(FunctionTypeTree node, P p) {
+ JCFunctionType t = (JCFunctionType) node;
+ List<JCExpression> argtypes = copy(t.argumentTypes, p);
+ JCExpression restype = copy(t.resultType, p);
+ List<JCExpression> thrown = copy(t.thrown, p);
+ return M.at(t.pos).FunctionType(argtypes, restype, thrown);
}
public JCTree visitArrayType(ArrayTypeTree node, P p) {
--- a/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java Thu May 27 18:11:12 2010 +0100
@@ -360,6 +360,14 @@ public class TreeMaker implements JCTree
return tree;
}
+ public JCLambda Lambda(List<JCVariableDecl> params,
+ JCTree body)
+ {
+ JCLambda tree = new JCLambda(params, body);
+ tree.pos = pos;
+ return tree;
+ }
+
public JCParens Parens(JCExpression expr) {
JCParens tree = new JCParens(expr);
tree.pos = pos;
@@ -446,6 +454,12 @@ public class TreeMaker implements JCTree
public JCTypeDisjoint TypeDisjoint(List<JCExpression> components) {
JCTypeDisjoint tree = new JCTypeDisjoint(components);
+ tree.pos = pos;
+ return tree;
+ }
+
+ public JCFunctionType FunctionType(List<JCExpression> argtypes, JCExpression restype, List<JCExpression> thrown) {
+ JCFunctionType tree = new JCFunctionType(argtypes, restype, thrown);
tree.pos = pos;
return tree;
}
--- a/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java Thu May 27 18:11:12 2010 +0100
@@ -215,6 +215,11 @@ public class TreeScanner extends Visitor
scan(tree.elems);
}
+ public void visitLambda(JCLambda tree) {
+ scan(tree.body);
+ scan(tree.params);
+ }
+
public void visitParens(JCParens tree) {
scan(tree.expr);
}
@@ -268,6 +273,12 @@ public class TreeScanner extends Visitor
public void visitTypeArray(JCArrayTypeTree tree) {
scan(tree.elemtype);
+ }
+
+ public void visitFunctionType(JCFunctionType tree) {
+ scan(tree.argumentTypes);
+ scan(tree.resultType);
+ scan(tree.thrown);
}
public void visitTypeApply(JCTypeApply tree) {
--- a/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java Thu May 27 18:11:12 2010 +0100
@@ -293,6 +293,12 @@ public class TreeTranslator extends JCTr
result = tree;
}
+ public void visitLambda(JCLambda tree) {
+ tree.params = translate(tree.params);
+ tree.body = translate(tree.body);
+ result = tree;
+ }
+
public void visitParens(JCParens tree) {
tree.expr = translate(tree.expr);
result = tree;
@@ -369,6 +375,13 @@ public class TreeTranslator extends JCTr
public void visitTypeDisjoint(JCTypeDisjoint tree) {
tree.components = translate(tree.components);
+ result = tree;
+ }
+
+ public void visitFunctionType(JCFunctionType tree) {
+ tree.argumentTypes = translate(tree.argumentTypes);
+ tree.resultType = translate(tree.resultType);
+ tree.thrown = translate(tree.thrown);
result = tree;
}
--- a/src/share/classes/com/sun/tools/javac/util/Names.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/util/Names.java Thu May 27 18:11:12 2010 +0100
@@ -107,6 +107,7 @@ public class Names {
public final Name EnclosingMethod;
public final Name desiredAssertionStatus;
public final Name append;
+ public final Name lambda;
public final Name family;
public final Name forName;
public final Name toString;
@@ -116,6 +117,13 @@ public class Names {
public final Name getMessage;
public final Name getClass;
public final Name invoke;
+ public final Name invokeVarargs;
+ public final Name makeProxy;
+ public final Name newProxyInstance;
+ public final Name lookup;
+ public final Name findStatic;
+ public final Name insertArguments;
+ public final Name fromMethodDescriptorString;
public final Name TYPE;
public final Name TYPE_USE;
public final Name TYPE_PARAMETER;
@@ -219,6 +227,7 @@ public class Names {
desiredAssertionStatus = fromString("desiredAssertionStatus");
append = fromString("append");
+ lambda = fromString("lambda");
family = fromString("family");
forName = fromString("forName");
toString = fromString("toString");
@@ -228,6 +237,13 @@ public class Names {
getMessage = fromString("getMessage");
getClass = fromString("getClass");
invoke = fromString("invoke");
+ invokeVarargs = fromString("invokeVarargs");
+ makeProxy = fromString("makeProxy");
+ newProxyInstance = fromString("newProxyInstance");
+ lookup = fromString("lookup");
+ fromMethodDescriptorString = fromString("fromMethodDescriptorString");
+ findStatic = fromString("findStatic");
+ insertArguments = fromString("insertArguments");
TYPE = fromString("TYPE");
TYPE_USE = fromString("TYPE_USE");
--- a/src/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java Thu May 20 16:00:35 2010 -0700
+++ b/src/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java Thu May 27 18:11:12 2010 +0100
@@ -466,6 +466,14 @@ public class RichDiagnosticFormatter ext
}
@Override
+ public Void visitFunctionType(FunctionType t, Void ignored) {
+ visit(t.argtypes);
+ visit(t.restype);
+ visit(t.thrown);
+ return null;
+ }
+
+ @Override
public Void visitErrorType(ErrorType t, Void ignored) {
Type ot = t.getOriginalType();
if (ot != null)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/bin/java.sh-template Thu May 27 18:11:12 2010 +0100
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+#
+# 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. Sun designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Sun 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 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.
+#
+
+mydir="`dirname $0`"
+mylib="`dirname $mydir`"/lib
+cp="$mylib/javacrt.jar":"`pwd`"
+javaOpts="-XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles -XX:+EnableInvokeDynamic"
+
+"#TARGET_JAVA#" -cp "$cp" ${javaOpts} $*
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/runtime/ProxyHelper.java Thu May 27 18:11:12 2010 +0100
@@ -0,0 +1,47 @@
+/*
+ * 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 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.
+ */
+
+package com.sun.runtime;
+
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationHandler;
+import java.dyn.MethodHandle;
+
+/**
+ *
+ * @author mcimadamore
+ */
+public class ProxyHelper {
+ @SuppressWarnings("unchecked")
+ public static <T> T makeProxy(final MethodHandle mh, Class<T> sam) {
+ return (T)Proxy.newProxyInstance(sam.getClassLoader(), new Class<?>[]{sam}, new InvocationHandler() {
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ return mh.invokeVarargs(args);
+ }
+ });
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/source/tree/FunctionTypeTree.java Thu May 27 18:11:12 2010 +0100
@@ -0,0 +1,39 @@
+/*
+ * 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 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.
+ */
+
+package com.sun.source.tree;
+
+import java.util.List;
+
+/**
+ * A tree node for a function type.
+ *
+ * @author mcimadamore
+ */
+public interface FunctionTypeTree extends Tree {
+ List<? extends Tree> getArgumentTypes();
+ List<? extends Tree> getThrownTypes();
+ Tree getResultType();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/source/tree/LambdaExpressionTree.java Thu May 27 18:11:12 2010 +0100
@@ -0,0 +1,38 @@
+/*
+ * 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 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.
+ */
+
+package com.sun.source.tree;
+
+import java.util.List;
+
+/**
+ * A tree node for a lambda expression.
+ *
+ * @author mcimadamore
+ */
+public interface LambdaExpressionTree extends ExpressionTree {
+ List<? extends VariableTree> getParameters();
+ Tree getBody();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaCapture01.java Thu May 27 18:11:12 2010 +0100
@@ -0,0 +1,105 @@
+/*
+ * 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 basic test for capture of non-mutable locals
+ * @author Brian Goetz
+ * @author Maurizio Cimadamore
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles LambdaConv01
+ */
+
+public class LambdaCapture01 {
+
+ static int assertionCount = 0;
+
+ static void assertTrue(boolean cond) {
+ assertionCount++;
+ if (!cond)
+ throw new AssertionError();
+ }
+
+ interface Tester {
+ void test();
+ }
+
+ 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);
+ }
+
+ public int n = 5;
+
+ //Simple local capture
+ void test1() {
+ final int N = 1;
+ int x = LambdaCapture01.<Integer,Integer>exec(#(Integer x)(x + N), 3);
+ assertTrue(4 == x);
+ }
+
+ //Local capture with multiple scopes (anon class)
+ void test2() {
+ final int N = 1;
+ new Tester() {
+ public void test() {
+ final int M = 2;
+ int x = LambdaCapture01.<Integer,Integer>exec(#(Integer x)(x + N + M), 3);
+ assertTrue(6 == x);
+ }
+ }.test();
+ }
+
+ //Local capture with multiple scopes (local class)
+ void test3() {
+ final int N = 1;
+ class MyTester implements Tester {
+ public void test() {
+ final int M = 2;
+ int x = LambdaCapture01.<Integer,Integer>exec(#(Integer x)(x + N + M), 3);
+ assertTrue(6 == x);
+ }
+ }
+ new MyTester().test();
+ }
+
+ //access to field from enclosing scope
+ void test4() {
+ final int N = 4;
+ int x1 = LambdaCapture01.<Integer,Integer>exec(#(Integer x)(x + n + N), 3);
+ assertTrue(12 == x1);
+ int x2 = LambdaCapture01.<Integer,Integer>exec(#(Integer x)(x + LambdaCapture01.this.n + N), 3);
+ assertTrue(12 == x2);
+ }
+
+ public static void main(String[] args) {
+ LambdaCapture01 t = new LambdaCapture01();
+ t.test1();
+ t.test2();
+ t.test3();
+ t.test4();
+ assertTrue(assertionCount == 5);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaConv01.java Thu May 27 18:11:12 2010 +0100
@@ -0,0 +1,143 @@
+/*
+ * 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 basic test for lambda conversion
+ * @author Brian Goetz
+ * @author Maurizio Cimadamore
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles LambdaConv01
+ */
+
+public class LambdaConv01 {
+
+ static int assertionCount = 0;
+
+ static void assertTrue(boolean cond) {
+ assertionCount++;
+ if (!cond)
+ throw new AssertionError();
+ }
+
+ interface IntToInt {
+ public int foo(int x);
+ }
+
+ interface IntToVoid {
+ public void foo(int x);
+ }
+
+ interface VoidToInt {
+ public int foo();
+ }
+
+ 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 {
+ //Assignment conversion:
+ VoidToInt f1 = #()(3);
+ assertTrue(3 == f1.foo());
+ //Covariant returns:
+ TU<Number, Integer> f2 = #(Integer x)(x);
+ assertTrue(3 == f2.foo(3));
+ //Method resolution with boxing:
+ int x = LambdaConv01.<Integer,Integer>exec(#(Integer x)(x), 3);
+ assertTrue(3 == x);
+ //Runtime exception transparency:
+ try {
+ LambdaConv01.<Integer,Object>exec(#(Object x)(x.hashCode()), null);
+ }
+ catch (RuntimeException e) {
+ assertTrue(true);
+ }
+ }
+
+ {
+ //Assignment conversion:
+ VoidToInt f1 = #()(3);
+ assertTrue(3 == f1.foo());
+ //Covariant returns:
+ TU<Number, Integer> f2 = #(Integer x)(x);
+ assertTrue(3 == f2.foo(3));
+ //Method resolution with boxing:
+ int x = LambdaConv01.<Integer,Integer>exec(#(Integer x)(x), 3);
+ assertTrue(3 == x);
+ //Runtime exception transparency:
+ try {
+ LambdaConv01.<Integer,Object>exec(#(Object x)(x.hashCode()), null);
+ }
+ catch (RuntimeException e) {
+ assertTrue(true);
+ }
+ }
+
+ public static void test1() {
+ //Assignment conversion:
+ VoidToInt f1 = #()(3);
+ assertTrue(3 == f1.foo());
+ //Covariant returns:
+ TU<Number, Integer> f2 = #(Integer x)(x);
+ assertTrue(3 == f2.foo(3));
+ //Method resolution with boxing:
+ int x = LambdaConv01.<Integer,Integer>exec(#(Integer x)(x), 3);
+ assertTrue(3 == x);
+ //Runtime exception transparency:
+ try {
+ LambdaConv01.<Integer,Object>exec(#(Object x)(x.hashCode()), null);
+ }
+ catch (RuntimeException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void test2() {
+ //Assignment conversion:
+ VoidToInt f1 = #()(3);
+ assertTrue(3 == f1.foo());
+ //Covariant returns:
+ TU<Number, Integer> f2 = #(Integer x)(x);
+ assertTrue(3 == f2.foo(3));
+ //Method resolution with boxing:
+ int x = LambdaConv01.<Integer,Integer>exec(#(Integer x)(x), 3);
+ assertTrue(3 == x);
+ //Runtime exception transparency:
+ try {
+ LambdaConv01.<Integer,Object>exec(#(Object x)(x.hashCode()), null);
+ }
+ catch (RuntimeException e) {
+ assertTrue(true);
+ }
+ }
+
+ public static void main(String[] args) {
+ test1();
+ new LambdaConv01().test2();
+ assertTrue(assertionCount == 16);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaExpr01.java Thu May 27 18:11:12 2010 +0100
@@ -0,0 +1,99 @@
+/*
+ * 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 basic test for simple lambda expressions in multiple scopes
+ * @author Brian Goetz
+ * @author Maurizio Cimadamore
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles LambdaExpr01
+ */
+
+public class LambdaExpr01 {
+
+ static int assertionCount = 0;
+
+ static void assertTrue(boolean cond) {
+ assertionCount++;
+ if (!cond)
+ throw new AssertionError();
+ }
+
+ static {
+ int i1 = #()(3).();
+ assertTrue(3 == i1);
+ Integer i2 = #()(3).();
+ assertTrue(3 == i2);
+ int i3 = #(int x)( x + 1 ).(3);
+ assertTrue(4 == i3);
+ int i4 = #(Number x)(x.intValue()).(new Float(3.0f));
+ assertTrue(3 == i4);
+ Object o = #()(3);
+ assertTrue(o != null);
+ }
+
+ {
+ int i1 = #()(3).();
+ assertTrue(3 == i1);
+ Integer i2 = #()(3).();
+ assertTrue(3 == i2);
+ int i3 = #(int x)( x + 1 ).(3);
+ assertTrue(4 == i3);
+ int i4 = #(Number x)(x.intValue()).(new Float(3.0f));
+ assertTrue(3 == i4);
+ Object o = #()(3);
+ assertTrue(o != null);
+ }
+
+ static void test1() {
+ int i1 = #()(3).();
+ assertTrue(3 == i1);
+ Integer i2 = #()(3).();
+ assertTrue(3 == i2);
+ int i3 = #(int x)( x + 1 ).(3);
+ assertTrue(4 == i3);
+ int i4 = #(Number x)(x.intValue()).(new Float(3.0f));
+ assertTrue(3 == i4);
+ Object o = #()(3);
+ assertTrue(o != null);
+ }
+
+ void test2() {
+ int i1 = #()(3).();
+ assertTrue(3 == i1);
+ Integer i2 = #()(3).();
+ assertTrue(3 == i2);
+ int i3 = #(int x)( x + 1 ).(3);
+ assertTrue(4 == i3);
+ int i4 = #(Number x)(x.intValue()).(new Float(3.0f));
+ assertTrue(3 == i4);
+ Object o = #()(3);
+ assertTrue(o != null);
+ }
+
+ public static void main(String[] args) {
+ test1();
+ new LambdaExpr01().test2();
+ assertTrue(assertionCount == 20);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaExpr02.java Thu May 27 18:11:12 2010 +0100
@@ -0,0 +1,99 @@
+/*
+ * 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 basic test for simple lambda expressions in multiple scopes
+ * @author Brian Goetz
+ * @author Maurizio Cimadamore
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles LambdaExpr02
+ */
+
+public class LambdaExpr02 {
+
+ static int assertionCount = 0;
+
+ static void assertTrue(boolean cond) {
+ assertionCount++;
+ if (!cond)
+ throw new AssertionError();
+ }
+
+ static {
+ int i1 = #(){ return 3; }.();
+ assertTrue(3 == i1);
+ Integer i2 = #(){ return 3; }.();
+ assertTrue(3 == i2);
+ int i3 = #(int x){ return x + 1; }.(3);
+ assertTrue(4 == i3);
+ int i4 = #(Number x){ return x.intValue(); }.(new Float(3.0f));
+ assertTrue(3 == i4);
+ Object o = #(){ return 3; };
+ assertTrue(o != null);
+ }
+
+ {
+ int i1 = #(){ return 3; }.();
+ assertTrue(3 == i1);
+ Integer i2 = #(){ return 3; }.();
+ assertTrue(3 == i2);
+ int i3 = #(int x){ return x + 1; }.(3);
+ assertTrue(4 == i3);
+ int i4 = #(Number x){ return x.intValue(); }.(new Float(3.0f));
+ assertTrue(3 == i4);
+ Object o = #(){ return 3; };
+ assertTrue(o != null);
+ }
+
+ static void test1() {
+ int i1 = #(){ return 3; }.();
+ assertTrue(3 == i1);
+ Integer i2 = #(){ return 3; }.();
+ assertTrue(3 == i2);
+ int i3 = #(int x){ return x + 1; }.(3);
+ assertTrue(4 == i3);
+ int i4 = #(Number x){ return x.intValue(); }.(new Float(3.0f));
+ assertTrue(3 == i4);
+ Object o = #(){ return 3; };
+ assertTrue(o != null);
+ }
+
+ void test2() {
+ int i1 = #(){ return 3; }.();
+ assertTrue(3 == i1);
+ Integer i2 = #(){ return 3; }.();
+ assertTrue(3 == i2);
+ int i3 = #(int x){ return x + 1; }.(3);
+ assertTrue(4 == i3);
+ int i4 = #(Number x){ return x.intValue(); }.(new Float(3.0f));
+ assertTrue(3 == i4);
+ Object o = #(){ return 3; };
+ assertTrue(o != null);
+ }
+
+ public static void main(String[] args) {
+ test1();
+ new LambdaExpr02().test2();
+ assertTrue(assertionCount == 20);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaScope01.java Thu May 27 18:11:12 2010 +0100
@@ -0,0 +1,73 @@
+/*
+ * 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 basic test for capture of non-mutable locals
+ * @author Brian Goetz
+ * @author Maurizio Cimadamore
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles LambdaScope01
+ */
+
+public class LambdaScope01 {
+
+ 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);
+ }
+
+ public int n = 5;
+
+ public int hashCode() {
+ throw new RuntimeException();
+ }
+
+ public void test1() {
+ int x = LambdaScope01.<Integer,Integer>exec(#(Integer x)(x * hashCode()), 3);
+ assertTrue(true); //should not throw
+ }
+
+ public void test2() {
+ final int n = 10;
+ int x = LambdaScope01.<Integer,Integer>exec(#(Integer x)(x + n), 3);
+ assertTrue(13 == x);
+ }
+
+ public static void main(String[] args) {
+ LambdaScope01 t = new LambdaScope01();
+ t.test1();
+ t.test2();
+ assertTrue(assertionCount == 2);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/NakedThis.java Thu May 27 18:11:12 2010 +0100
@@ -0,0 +1,35 @@
+/*
+ * 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 basic test for capture of non-mutable locals
+ * @author Brian Goetz
+ * @author Maurizio Cimadamore
+ * @compile/fail/ref=NakedThis.out -XDrawDiagnostics NakedThis.java
+ */
+
+class NakedThis {
+ Object x1 = #(int x)(this);
+ Object x2 = #(int x)(NakedThis.this);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/NakedThis.out Thu May 27 18:11:12 2010 +0100
@@ -0,0 +1,2 @@
+NakedThis.java:33:16: compiler.err.cannot.infer.lambda.return.type
+1 error