changeset 553:7704dcd17e0b

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.
author mcimadamore
date Thu, 27 May 2010 18:11:12 +0100
parents 67cac01ed62a
children 317bac39b8a4
files 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
diffstat 45 files changed, 1784 insertions(+), 67 deletions(-) [+]
line wrap: on
line diff
--- 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 @@
         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}"/>
+         <build-classes includes="${javac.includes}"/>
     </target>
 
-    <target name="build-javac" depends="build-classes-javac">
+    <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">
@@ -479,6 +493,22 @@
         </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>
+
     <target name="-def-build-jar">
         <macrodef name="build-jar">
             <attribute name="name"/>
--- /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} $*
--- 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 @@
    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
--- /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();
+}
--- 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 @@
         NEW_ARRAY(NewArrayTree.class),
 
         /**
+         * Used for instances of {@link LambdaExpressionTree}.
+         */
+        LAMBDA_EXPRESSION(LambdaExpressionTree.class),
+
+        /**
          * Used for instances of {@link NewClassTree}.
          */
         NEW_CLASS(NewClassTree.class),
@@ -239,6 +244,11 @@
         DISJOINT_TYPE(DisjointTypeTree.class),
 
         /**
+         * Used for instances of {@link FunctionTypeTree}.
+         */
+        FUNCTION_TYPE(FunctionTypeTree.class),
+
+        /**
          * Used for instances of {@link TypeCastTree}.
          */
         TYPE_CAST(TypeCastTree.class),
--- 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 @@
     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 @@
     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 @@
         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 @@
         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 @@
         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);
     }
@@ -358,6 +364,13 @@
         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) {
         R r = scan(node.getAnnotations(), p);
         r = scanAndReduce(node.getBounds(), p, r);
--- 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 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
@@ -203,6 +203,22 @@
     }
 
     @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
     public String visitPackageType(PackageType t, Locale locale) {
         return t.tsym.getQualifiedName().toString();
     }
--- 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 @@
             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 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 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 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 @@
         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 @@
         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 @@
 
     /** 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 @@
             // optimization, was: allparams().nonEmpty();
         }
 
+        public boolean isFunctionType() {
+            return false;
+        }
+
         /** A cache for the rank. */
         int rank_field = -1;
 
@@ -779,6 +783,113 @@
         }
     }
 
+    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;
+        }
+    }
+
     public static class MethodType extends Type
                     implements Cloneable, ExecutableType {
 
@@ -866,7 +977,7 @@
             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 @@
             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 @@
         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 @@
      * 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);
+        }
     }
 
     /**
@@ -430,6 +486,26 @@
             }
 
             @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
             public Boolean visitClassType(ClassType t, Type s) {
                 Type sup = asSuper(t, s.tsym);
                 return sup != null
@@ -1280,6 +1356,11 @@
         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 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 @@
             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 @@
     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 @@
     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 @@
         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 @@
         // 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;
@@ -1346,6 +1361,7 @@
             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
             // arguments (this will also set the method symbol).
@@ -1810,6 +1826,77 @@
         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) {
         Type owntype = attribTree(tree.expr, env, pkind, pt);
         result = check(tree, owntype, pkind, pkind, pt);
@@ -2747,6 +2834,15 @@
         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 @@
 
     /** 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 @@
      *  @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 @@
     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 @@
      *  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)));
@@ -1210,6 +1211,59 @@
         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) {
         Bits initsExit = inits.dup();
--- 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 @@
      */
     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
  *************************************************************************/
@@ -165,6 +169,13 @@
             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 @@
             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 @@
     /** 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 @@
         currentClass = tree.sym;
         currentMethodSym = null;
         classdefs.put(currentClass, tree);
-
+        translatedLambdas.put(currentClass, List.<JCMethodDecl>nil());
         proxies = proxies.dup(currentClass);
         List<VarSymbol> prevOuterThisStack = outerThisStack;
 
@@ -2067,6 +2084,13 @@
             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();
         outerThisStack = prevOuterThisStack;
 
@@ -2533,6 +2557,12 @@
 
     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 @@
         } 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.
@@ -2607,6 +2637,19 @@
         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) {
         List<JCExpression> args = _args;
         if (parameters.isEmpty()) return args;
@@ -2701,6 +2744,19 @@
         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.
      *  If the subexpression has changed, omit the parens.
      */
@@ -3338,6 +3394,139 @@
         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 @@
                               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 @@
         }
         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;
@@ -1356,6 +1365,12 @@
         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
      *  found.
      *  @param pos       The position to use for error reporting.
@@ -1775,6 +1790,12 @@
             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 @@
      *  @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 @@
         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 @@
         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 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 @@
         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 @@
                     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 @@
                         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 @@
         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 @@
 
     /** 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 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 @@
         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>();
@@ -186,6 +190,14 @@
      */
     boolean allowTypeAnnotations;
 
+    /** Switch: should we recognize lambda expressions?
+     */
+    boolean allowLambda;
+
+    /** Switch: should we recognize function types?
+     */
+    boolean allowFunctionTypes;
+
     /** Switch: should we keep docComments?
      */
     boolean keepDocComments;
@@ -896,10 +908,13 @@
      *                   | "." ( 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
@@ -936,6 +951,10 @@
                 }
             } else return illegal();
             break;
+        case HASH:
+            S.nextToken();
+            t = lambdaOrFunctionType();
+            break;
         case LPAREN:
             if (typeArgs == null && (mode & EXPR) != 0) {
                 S.nextToken();
@@ -1145,6 +1164,11 @@
                             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 @@
             } 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()) {
@@ -1257,6 +1288,53 @@
         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]
      */
     JCExpression superSuffix(List<JCExpression> typeArgs, JCExpression t) {
@@ -1754,6 +1832,7 @@
                 stats.append(parseStatement());
                 break;
             case MONKEYS_AT:
+            case HASH:
             case FINAL: {
                 String dc = S.docComment();
                 JCModifiers mods = modifiersOpt();
@@ -3216,6 +3295,18 @@
         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 @@
                             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 @@
     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 @@
     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 @@
     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 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 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 @@
         }
     }
 
+    /** 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 ( ... )
      */
@@ -1894,6 +1958,49 @@
         }
     }
 
+    /** 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;
+        }
+    }
+
     /**
      * A formal class parameter.
      * @param name name
@@ -2238,6 +2345,7 @@
         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 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
@@ -913,6 +913,23 @@
         }
     }
 
+    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);
+        }
+    }
+
     public void visitParens(JCParens tree) {
         try {
             print("(");
@@ -1190,6 +1207,22 @@
         }
     }
 
+    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 @@
         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);
@@ -351,6 +358,14 @@
         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) {
         JCArrayTypeTree t = (JCArrayTypeTree) node;
         JCExpression elemtype = copy(t.elemtype, 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 @@
         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;
@@ -450,6 +458,12 @@
         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;
+    }
+
     public JCTypeParameter TypeParameter(Name name, List<JCExpression> bounds) {
         return TypeParameter(name, bounds, List.<JCTypeAnnotation>nil());
     }
--- 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 @@
         scan(tree.elems);
     }
 
+    public void visitLambda(JCLambda tree) {
+        scan(tree.body);
+        scan(tree.params);
+    }
+
     public void visitParens(JCParens tree) {
         scan(tree.expr);
     }
@@ -270,6 +275,12 @@
         scan(tree.elemtype);
     }
 
+    public void visitFunctionType(JCFunctionType tree) {
+        scan(tree.argumentTypes);
+        scan(tree.resultType);
+        scan(tree.thrown);
+    }
+
     public void visitTypeApply(JCTypeApply tree) {
         scan(tree.clazz);
         scan(tree.arguments);
--- 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 @@
         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;
@@ -372,6 +378,13 @@
         result = tree;
     }
 
+    public void visitFunctionType(JCFunctionType tree) {
+        tree.argumentTypes = translate(tree.argumentTypes);
+        tree.resultType = translate(tree.resultType);
+        tree.thrown = translate(tree.thrown);
+        result = tree;
+    }
+
     public void visitTypeParameter(JCTypeParameter tree) {
         tree.annotations = translate(tree.annotations);
         tree.bounds = translate(tree.bounds);
--- 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 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 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 @@
         desiredAssertionStatus = fromString("desiredAssertionStatus");
 
         append = fromString("append");
+        lambda = fromString("lambda");
         family = fromString("family");
         forName = fromString("forName");
         toString = fromString("toString");
@@ -228,6 +237,13 @@
         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 @@
         }
 
         @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/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