changeset 557:d74a4b240764

The following issues have been addressed: *) fixed type-inference issues w.r.t. wildcard types *) fixed SAM conversion issues (now Object members are ignored as per strawman) *) fixed minor parser issues (wrong start position of lambdas)/ambiguities *) improved translation of nested lambda expression/lambda expression nested in inner classes/inner classes nested in lambda *) minor attribution fixes: added check for lambda method call, improved check for return expression in lambda context *) better diagnostic support
author mcimadamore
date Fri, 04 Jun 2010 12:34:09 +0100
parents 81966684ef23
children 1f2a6005435d
files src/share/classes/com/sun/tools/javac/code/Flags.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/Enter.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/parser/JavacParser.java src/share/classes/com/sun/tools/javac/resources/compiler.properties test/tools/javac/lambda/BadAccess.java test/tools/javac/lambda/BadAccess.out test/tools/javac/lambda/BadLambdaCall.java test/tools/javac/lambda/BadLambdaCall.out test/tools/javac/lambda/BadReturn.java test/tools/javac/lambda/BadReturn.out test/tools/javac/lambda/LambdaCapture02.java test/tools/javac/lambda/LambdaCapture03.java test/tools/javac/lambda/LambdaCapture04.java test/tools/javac/lambda/LambdaCapture05.java test/tools/javac/lambda/LambdaConv05.java test/tools/javac/lambda/LambdaScope02.java test/tools/javac/lambda/NakedThis.out
diffstat 21 files changed, 1004 insertions(+), 137 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/code/Flags.java	Fri May 28 17:19:22 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Flags.java	Fri Jun 04 12:34:09 2010 +0100
@@ -240,6 +240,11 @@
      */
     public static final long LAMBDA = 1L<<40;
 
+    /**
+     * Flag that marks a lambda expression symbol that requires access to enclosing class
+     */
+    public static final long OUTER_ACCESS = 1L<<41;
+
     /** Modifier masks.
      */
     public static final int
--- a/src/share/classes/com/sun/tools/javac/code/Types.java	Fri May 28 17:19:22 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Types.java	Fri Jun 04 12:34:09 2010 +0100
@@ -280,7 +280,8 @@
                 isSameType(mtype.getReturnType(), syms.voidType)) :
                 isConvertible(t.getReturnType(), mtype.getReturnType(), warn);
             boolean argsOk = t.getParameterTypes().size() == mtype.getParameterTypes().size() &&
-                    isSameTypes(t.getParameterTypes(), mtype.getParameterTypes());
+                containsType(mtype.getParameterTypes(), t.getParameterTypes());
+                    
             boolean thrownOk = chk.unhandled(t.getThrownTypes(), mtype.getThrownTypes()).isEmpty();
             return isReturnOk && argsOk && thrownOk;
         }
@@ -331,6 +332,7 @@
             if (e.sym != null && 
                     e.sym.kind == Kinds.MTH &&
                     (e.sym.flags() & ABSTRACT) != 0 &&
+                    !overridesObjectMethod(e.sym, t.tsym) &&
                     (buf.isEmpty() || overrideEquivalent(e.sym.type, buf.first().type))) {
                 buf.append(e.sym);
             }
@@ -340,6 +342,15 @@
             findSAM(i, buf);
         }
     }
+    //where
+    private boolean overridesObjectMethod(Symbol msym, TypeSymbol tsym) {
+        for (Scope.Entry e = syms.objectType.tsym.members().lookup(msym.name) ; e.scope != null ; e = e.next()) {
+            if (msym.overrides(e.sym, tsym, this, true)) {
+                return true;
+            }
+        }
+        return false;
+    }
 
     /**
      * Is t a subtype of or convertiable via boxing/unboxing
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Fri May 28 17:19:22 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Jun 04 12:34:09 2010 +0100
@@ -1036,7 +1036,7 @@
                               Type condtype,
                               Type thentype,
                               Type elsetype) {
-            Type ctype = condType1(pos, condtype, thentype, elsetype);
+            Type ctype = unionType(pos, condtype, thentype, elsetype, "neither.conditional.subtype");
 
             // If condition and both arms are numeric constants,
             // evaluate at compile-time.
@@ -1057,8 +1057,8 @@
          *  @param thentype The type of the expression's then-part.
          *  @param elsetype The type of the expression's else-part.
          */
-        private Type condType1(DiagnosticPosition pos, Type condtype,
-                               Type thentype, Type elsetype) {
+        private Type unionType(DiagnosticPosition pos, Type condtype,
+                               Type thentype, Type elsetype, String diagKey) {
             // If same type, that is the result
             if (types.isSameType(thentype, elsetype))
                 return thentype.baseType();
@@ -1105,7 +1105,7 @@
                 return thentype.baseType();
 
             if (!allowBoxing || thentype.tag == VOID || elsetype.tag == VOID) {
-                log.error(pos, "neither.conditional.subtype",
+                log.error(pos, diagKey,
                           thentype, elsetype);
                 return thentype.baseType();
             }
@@ -1232,9 +1232,13 @@
             } else {
                 attribExpr(tree.expr, env, isLambda ? Type.noType : m.type.getReturnType());
                 if (isLambda) {
+                    if (tree.getExpression().type.tag == VOID) {
+                        log.error(tree.expr.pos(),
+                                  "cant.ret.void.expr");
+                    }
                     ((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);
+                        unionType(tree.pos(), null, m.type.getReturnType(), tree.expr.type, "incompatibles.ret.types.in.lambda");
                 }
             }
         }
@@ -1826,45 +1830,71 @@
         result = check(tree, owntype, VAL, pkind, pt);
     }
 
-    /** An environment in which to evaluate a lambda.
+    /**
+     * 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.
+     * The compiler generates synthetic symbols for both envs. 'Fake' AST must
+     * also be generated as they are required during lowering (in order to find
+     * free-variables used within a lambda expression).
      */
-    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)));
+    Env<AttrContext> lambdaEnvironment(JCLambda tree) {        
+        long flags = lambdaFlags(env);
+        //create synthetic outer class symbol hoisting the lambda
+        ClassSymbol lambdaClassSym = 
+                new ClassSymbol(flags, names.empty, null, env.info.scope.owner);
+        lambdaClassSym.type = new ClassType(env.enclClass.type,
+                List.<Type>nil(),
+                lambdaClassSym);
+        Env<AttrContext> outerEnv =
+                env.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 = make.ClassDef(make.Modifiers(flags),
+                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);
+        //create synthetic lambda symbol
+        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;
+        JCMethodDecl lambda = make.MethodDef(make.Modifiers(flags),
+                lambdaSym.name,
+                null, // missing restype
+                List.<JCTypeParameter>nil(),
+                List.<JCVariableDecl>nil(),
+                List.<JCExpression>nil(),
+                body,
+                null); // missing defaultValue
+        tree.sym = lambdaSym;
+        Env<AttrContext> newEnv = memberEnter.methodEnv(lambda, outerEnv);
+        newEnv.info.scope.owner = lambda.sym = lambdaSym;
         newEnv.enclClass.defs = List.<JCTree>of(newEnv.enclMethod);
-        tree.sym = lambdaSym;
+        //add 'this'
+        VarSymbol thisSym = new VarSymbol(FINAL | HASINIT,
+                names._this,
+                lambdaClassSym.type,
+                lambdaClassSym);
+        newEnv.info.scope.enter(thisSym);
         return newEnv;
     }
+    //where
+    private long lambdaFlags(Env<AttrContext> env) {
+        Symbol owner = env.info.scope.owner;
+        //a lambda definied in a static conext is static
+        boolean needsOuterAccess = (owner.flags() & LAMBDA) != 0 ?
+            (owner.flags() & OUTER_ACCESS) != 0 :
+            !Resolve.isStatic(env);
+        return LAMBDA | SYNTHETIC |
+                (needsOuterAccess ? OUTER_ACCESS : 0);
+    }
 
     @Override
     public void visitLambda(JCLambda that) {
@@ -2114,9 +2144,12 @@
             if (v.owner.kind == MTH &&
                 v.owner != env.info.scope.owner &&
                 (v.flags_field & FINAL) == 0) {
+                String subkey = (env.info.scope.owner.flags() & LAMBDA) != 0 ?
+                    "lambda" :
+                    "icls";
                 log.error(tree.pos(),
-                          "local.var.accessed.from.icls.needs.final",
-                          v);
+                          "local.var.accessed.from.inner.ctx.needs.final",
+                          v, diags.fragment(subkey));
             }
 
             // If we are expecting a variable (as opposed to a value), check
--- a/src/share/classes/com/sun/tools/javac/comp/Enter.java	Fri May 28 17:19:22 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Enter.java	Fri Jun 04 12:34:09 2010 +0100
@@ -397,8 +397,9 @@
             // which contains this class in a non-static context
             // (its "enclosing instance class"), provided such a class exists.
             Symbol owner1 = owner;
-            while ((owner1.kind & (VAR | MTH)) != 0 &&
-                   (owner1.flags_field & STATIC) == 0) {
+            while (((owner1.kind & (VAR | MTH)) != 0 &&
+                   (owner1.flags_field & STATIC) == 0) ||
+                   (owner1.flags_field & LAMBDA) != 0) {
                 owner1 = owner1.owner;
             }
             if (owner1.kind == TYP) {
--- a/src/share/classes/com/sun/tools/javac/comp/Lower.java	Fri May 28 17:19:22 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Lower.java	Fri Jun 04 12:34:09 2010 +0100
@@ -112,6 +112,10 @@
      */
     ClassSymbol currentClass;
 
+    /** Stack of nested lambda expressions
+     */
+    Stack<MethodSymbol> lambdaStack;
+
     /** A queue of all translated classes.
      */
     ListBuffer<JCTree> translated;
@@ -124,9 +128,9 @@
      */
     Map<JCTree, Integer> endPositions;
 
-    /** A hash table mapping class trees to a ist of translated lambda defs.
+    /** A list of translated lambda expressions
      */
-    Map<ClassSymbol, List<JCMethodDecl>> translatedLambdas = new HashMap<ClassSymbol, List<JCMethodDecl>>();
+    List<JCMethodDecl> translatedLambdas;
 
 /**************************************************************************
  * Global mappings
@@ -332,7 +336,12 @@
                 fvs = collector.fvs;
                 freevarCache.put(c, fvs);
             }
-            return fvs;
+            //if the enclosing class is a synthetic lambda symbol
+            //append enclosing freevars to current freevars
+            //(nested lambdas cannot refer each other scopes)
+            return (c.owner.flags() & LAMBDA) != 0 ?
+                fvs.appendList(freevars(c.owner.enclClass())) :
+                fvs;
         } else {
             return List.nil();
         }
@@ -999,7 +1008,8 @@
     JCExpression access(Symbol sym, JCExpression tree, JCExpression enclOp, boolean refSuper) {
         // Access a free variable via its proxy, or its proxy's proxy
         while (sym.kind == VAR && sym.owner.kind == MTH &&
-            sym.owner.enclClass() != currentClass) {
+            ((!lambdaStack.isEmpty() && lambdaStack.peek() != sym.owner) ||
+            sym.owner.enclClass() != currentClass)) {
             // A constant is replaced by its constant value.
             Object cv = ((VarSymbol)sym).getConstValue();
             if (cv != null) {
@@ -1049,11 +1059,12 @@
                 boolean accReq = protAccess || needsPrivateAccess(sym);
 
                 // A base has to be supplied for
-                //  - simple identifiers accessing variables in outer classes.
+                //  - simple identifiers accessing variables in outer classes OR
+                //    in current class when we are translating a lambda expr
                 boolean baseReq =
                     base == null &&
                     sym.owner != syms.predefClass &&
-                    !sym.isMemberOf(currentClass, types);
+                    (!sym.isMemberOf(currentClass, types) || !lambdaStack.isEmpty());
 
                 if (accReq || baseReq) {
                     make.at(tree.pos);
@@ -1323,6 +1334,25 @@
         return result;
     }
 
+    /** The name of a this$n field
+     *  @param type   The class referenced by the this$n field
+     */
+    Name outerThisLambda(Symbol lambdaSym, LambdaThisKind kind) {
+        Name result = names.fromString(kind.kindName + target.syntheticNameChar() + lambdaStack.indexOf(lambdaSym));
+        return result;
+    }
+
+    enum LambdaThisKind {
+        CURRENT_LAMBDA("lambda"),
+        ENCLOSING_CLASS("encl");
+
+        String kindName;
+
+        LambdaThisKind(String kindName) {
+            this.kindName = kindName;
+        }
+    }
+
     /** Definition for this$n field.
      *  @param pos        The source code position of the definition.
      *  @param owner      The class in which the definition goes.
@@ -1362,7 +1392,8 @@
      *  @param c             The qualifier class.
      */
     JCExpression makeThis(DiagnosticPosition pos, TypeSymbol c) {
-        if (currentClass == c) {
+        //during lambda translation always call makeOutherThis
+        if (currentClass == c && lambdaStack.isEmpty()) {
             // in this case, `this' works fine
             return make.at(pos).This(c.erasure(types));
         } else {
@@ -1420,12 +1451,18 @@
      */
     JCExpression makeOwnerThis(DiagnosticPosition pos, Symbol sym, boolean preciseMatch) {
         Symbol c = sym.owner;
-        if (preciseMatch ? sym.isMemberOf(currentClass, types)
-                         : currentClass.isSubClass(sym.owner, types)) {
+        if ((preciseMatch ? sym.isMemberOf(currentClass, types)
+                         : currentClass.isSubClass(sym.owner, types)) &&
+                         lambdaStack.isEmpty()) {
             // in this case, `this' works fine
             return make.at(pos).This(c.erasure(types));
+        } else if ((sym.owner.type == syms.objectType ||
+                sym.owner.type == syms.methodHandleType) &&
+                !lambdaStack.isEmpty()) {
+            // when in lambda translation resolve Object symbols to 'fake' MethodHandle param
+            return make.at(pos).Ident(proxies.lookup(outerThisLambda(lambdaStack.peek(), LambdaThisKind.CURRENT_LAMBDA)).sym);
         } else {
-            // need to go via this$n
+            // need to go via this$n (also applies when in lambda translation)
             return makeOwnerThisN(pos, sym, preciseMatch);
         }
     }
@@ -2026,10 +2063,13 @@
     public void visitClassDef(JCClassDecl tree) {
         ClassSymbol currentClassPrev = currentClass;
         MethodSymbol currentMethodSymPrev = currentMethodSym;
+        Stack<MethodSymbol> prevLambdaStack = lambdaStack;
+        List<JCMethodDecl> prevTranslatedLambdas = translatedLambdas;
         currentClass = tree.sym;
         currentMethodSym = null;
+        lambdaStack = new Stack<MethodSymbol>();
+        translatedLambdas = List.nil();
         classdefs.put(currentClass, tree);
-        translatedLambdas.put(currentClass, List.<JCMethodDecl>nil());
         proxies = proxies.dup(currentClass);
         List<VarSymbol> prevOuterThisStack = outerThisStack;
 
@@ -2084,8 +2124,9 @@
             enterSynthetic(tree.pos(), otdef.sym, currentClass.members());
         }
 
-        if (translatedLambdas.get(currentClass).nonEmpty()) {
-            for (JCMethodDecl lambda : translatedLambdas.get(currentClass)) {
+        //append translated lambdas to lowered defs
+        if (translatedLambdas.nonEmpty()) {
+            for (JCMethodDecl lambda : translatedLambdas) {
                 tree.defs = tree.defs.prepend(lambda);
                 enterSynthetic(tree.pos(), lambda.sym, currentClass.members());
             }
@@ -2099,6 +2140,8 @@
 
         currentClass = currentClassPrev;
         currentMethodSym = currentMethodSymPrev;
+        lambdaStack = prevLambdaStack;
+        translatedLambdas = prevTranslatedLambdas;
 
         // Return empty block {} as a placeholder for an inner class.
         result = make_at(tree.pos()).Block(0, List.<JCStatement>nil());
@@ -3110,7 +3153,7 @@
                 new MethodSymbol((tree.mods.flags&STATIC) | BLOCK,
                                  names.empty, null,
                                  currentClass);
-        }
+        }        
         if (tree.init != null) tree.init = translate(tree.init, tree.type);
         result = tree;
         currentMethodSym = oldMethodSym;
@@ -3397,123 +3440,182 @@
     }
 
     Name lambdaName() {
-        return names.lambda.append(names.fromString("$" + translatedLambdas.get(currentClass).size()));
+        return names.lambda.append(names.fromString("$" + translatedLambdas.size()));
     }
 
+    Name lambdaThisName(LambdaThisKind thisKind) {
+        return names.fromString(thisKind.kindName + target.syntheticNameChar() + lambdaStack.size());
+    }
+
     public void visitLambda(JCLambda tree) {
-        MethodSymbol lambdaSym = new MethodSymbol(SYNTHETIC | STATIC, lambdaName(), null, currentClass);
+        MethodSymbol lambdaSym = new MethodSymbol(LAMBDA | 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;
-
+        ListBuffer<VarSymbol> freevars = ListBuffer.lb();
+        
         //save current translation context
-
         List<VarSymbol> prevOuterThisStack = outerThisStack;
-        ClassSymbol prevClass = currentClass;
-        Scope prevProxies = proxies;
-
-        //lower translated lambda method
+
+        boolean needsOuterAccess = (tree.sym.flags() & OUTER_ACCESS) != 0;
+
         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);
+            proxies = proxies.dup();
+            //compute synthetic params
+            ListBuffer<JCVariableDecl> syntheticParams = ListBuffer.lb();
+
+            //add MethodHandle param
+            VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
+                    lambdaThisName(LambdaThisKind.CURRENT_LAMBDA),
+                    syms.methodHandleType, lambdaSym);
+            syntheticParams.append(make.VarDef(_this, null));
+            proxies.enter(_this); //make MethodHandle 'this' available as proxy
+
+            //add encl$n if needed
+            if (needsOuterAccess) {
+                VarSymbol _this$0 = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
+                        lambdaThisName(LambdaThisKind.ENCLOSING_CLASS),
+                        currentClass.type, lambdaSym);
+                outerThisStack = outerThisStack.prepend(_this$0);
+                syntheticParams.append(make.VarDef(_this$0, null));
             }
-            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));
+
+            //add freevars
+            for (VarSymbol fv : freevars((ClassSymbol)tree.sym.owner)) {
+                freevars.append(fv);
+                VarSymbol arg = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
+                        proxyName(fv.name),
+                        fv.type,
+                        lambdaSym);
+                proxies.enter(arg); //make freevars available as proxies
+                syntheticParams.append(make.at(tree.pos).VarDef(arg, null));
+            }
+
+            //add other arguments
+            for (JCVariableDecl param : tree.params) {
+                syntheticParams.append(make.at(tree.pos).VarDef(param.sym, null));
+            }
+
+            //prepend synthetic args to translated lambda method signature
+            lambdaType.argtypes = TreeInfo.types(syntheticParams.toList());
+
+            //replace synthetic symbol occurrences
+            patchLambda(tree, tree.sym, lambdaSym, _this);
+
+            //create method declaration hoisting the lambda body
+            JCBlock body = makeLambdaBody(tree);
+            JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(STATIC | SYNTHETIC),
+                    lambdaSym.name,
+                    make.QualIdent(lambdaType.getReturnType().tsym),
+                    List.<JCTypeParameter>nil(),
+                    syntheticParams.toList(),
+                    tree.sym.type.getThrownTypes() == null ?
+                        List.<JCExpression>nil() :
+                        make.Types(tree.sym.type.getThrownTypes()),
+                    body,
+                    null);
+            lambdaDecl.sym = lambdaSym;
+            lambdaDecl.type = lambdaType;
+
+            //translate lambda body
+            lambdaStack.push(lambdaSym);
+            translatedLambdas = translatedLambdas.prepend(lambdaDecl);
+            translate(lambdaDecl);
         }
         finally {
-            currentClass = prevClass;
+            proxies = proxies.leave();
+            lambdaStack.pop();
             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);
+        VarSymbol handleSym = new VarSymbol(SYNTHETIC,
+                names.fromString("i" + target.syntheticNameChar()),
+                syms.methodHandleType,
+                lambdaStack.isEmpty() ?
+                    currentMethodSym :
+                    lambdaStack.peek());
         JCVariableDecl handleDecl =  make.VarDef(handleSym, makeMethodHandle(lambdaSym));
         JCExpression handleRef = make.Ident(handleSym);
         ListBuffer<JCExpression> syntheticInits = ListBuffer.lb();
+
+        //append MethodHandle reference
         syntheticInits.append(handleRef);
-        if (!tree.sym.isStatic()) {
+
+        //append reference to outer class (if needed)
+        if (needsOuterAccess) {
             syntheticInits.append(makeThis(tree.pos(), currentClass));
         }
+
+        //add free variables
         for (VarSymbol fv : freevars) {
-            syntheticInits.append(make.Ident(fv));
+            syntheticInits.append(boxIfNeeded(loadFreevar(tree.pos(), fv),syms.objectType));
         }
+
+        //generate insertArguments() call
         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) {
+    JCBlock makeLambdaBody(JCLambda tree) {
+        if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION &&
+                tree.body.type != syms.voidType) {
+            return make.Block(0, List.<JCStatement>of(make.Return((JCExpression)tree.body)));
+        } else {
+            switch (tree.body.getTag()) {
+                case JCTree.BLOCK: return (JCBlock)tree.body;
+                default:
+                    JCStatement stat = make.Exec((JCExpression)tree.body);
+                    return make.Block(0, List.<JCStatement>of(stat));
+            }
+        }
+    }
+
+    /*
+     * Patch a lambda expression; this is done by replacing all instances of
+     * synthetic symbols for lowered ones. Reference to 'fake' lambda this are
+     * also handled accordingly.
+     */
+    void patchLambda(JCTree tree, final Symbol oldOwner, final Symbol newOwner, final Symbol _this) {
         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 visitClassDef(JCClassDecl tree) {
+                if (tree.sym.owner == oldOwner) {
+                    tree.sym.owner = newOwner;
                 }
+                super.visitClassDef(tree);
             }
             @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;
+            public void visitVarDef(JCVariableDecl tree) {
+                if (tree.sym.owner == oldOwner) {
+                    tree.sym.owner = newOwner;
+                }
+                super.visitVarDef(tree);
+            }
+            @Override
+            public void visitLambda(JCLambda tree) {
+                if (tree.sym.owner.owner == oldOwner) {
+                    tree.sym.owner.owner = newOwner;
+                }
+                super.visitLambda(tree);
+            }
+            @Override
+            public void visitIdent(JCIdent tree) {
+                //replace occurrences of synthetic 'this'
+                //with the special lambda MethodHandle parameter
+                if (tree.sym.name == names._this &&
+                        tree.sym.owner == oldOwner.owner) {
+                    tree.name = _this.name;
+                    tree.sym = _this;
+                    tree.type = _this.type;
                 }
             }
         }
         new LambdaPatcher().scan(tree);
     }
-
+    
     JCExpression makeMethodHandle(MethodSymbol msym) {
         String sig = writer.typeSig(msym.type).toString();
         ListBuffer<JCExpression> args1 = ListBuffer.lb();
--- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri May 28 17:19:22 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Jun 04 12:34:09 2010 +0100
@@ -911,11 +911,14 @@
         }
         Type restype;
         List<Type> thrown = List.nil();
+        List<Type> paramtypes;
         if (types.isFunctionType(site)) {
+            paramtypes = site.getParameterTypes();
             restype = site.getReturnType();
             thrown = site.getThrownTypes();
         }
         else {
+            paramtypes = Type.map(argtypes, implicitArgType);
             if (typeargtypes.isEmpty()) {
                 restype = syms.objectType;
             } else {
@@ -924,7 +927,7 @@
                     return methodNotFound;
             }
         }
-        List<Type> paramtypes = Type.map(argtypes, implicitArgType);
+        
         MethodType mtype = new MethodType(paramtypes,
                                           restype,
                                           thrown,
@@ -951,8 +954,12 @@
             m = new MethodSymbol(flags, name, mtype, c);
             implicit.enter(m);
         }
+        boolean argsOk = argumentsAcceptable(argtypes, types.memberType(site, m).getParameterTypes(),
+                                   true, false, Warner.noWarnings);
+        if (types.isFunctionType(site) && !argsOk)
+            return wrongMethod.setWrongSym(m);
         assert argumentsAcceptable(argtypes, types.memberType(site, m).getParameterTypes(),
-                                   false, false, Warner.noWarnings);
+                                   true, false, Warner.noWarnings);
         assert null != instantiate(env, site, m, argtypes, typeargtypes, false, false, Warner.noWarnings);
         return m;
     }
@@ -1353,9 +1360,12 @@
             needsImplicitResolution(site, name)) {
             // lookup failed; supply an exactly-typed implicit method
             sym = findImplicitMethod(env, site, name, argtypes, typeargtypes);
+            if (sym.kind >= AMBIGUOUS) {
+                sym = access(sym, pos, site, name, true, argtypes, typeargtypes);
+            }
             env.info.varArgs = false;
         }
-        if (sym.kind >= AMBIGUOUS) {//if nothing is found return the 'first' error
+        else if (sym.kind >= AMBIGUOUS) {//if nothing is found return the 'first' error
             MethodResolutionPhase errPhase =
                     firstErroneousResolutionPhase();
             sym = access(methodResolutionCache.get(errPhase),
@@ -1889,6 +1899,13 @@
                 return diags.create(dkind, false, log.currentSource(),
                         pos, "operator.cant.be.applied", name, argtypes);
             }
+            else if (types.isFunctionType(site) &&
+                    name == names.empty) {
+                return diags.create(dkind, false, log.currentSource(), pos,
+                          "cant.apply.lambda",
+                          methodArguments(site.getParameterTypes()),
+                          methodArguments(argtypes));
+            }
             else {
                 Symbol ws = sym.asMemberOf(site, types);
                 return diags.create(dkind, false, log.currentSource(), pos,
--- a/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Fri May 28 17:19:22 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Fri Jun 04 12:34:09 2010 +0100
@@ -952,8 +952,9 @@
             } else return illegal();
             break;
         case HASH:
+            int prevPos = S.pos();
             S.nextToken();
-            t = lambdaOrFunctionType();
+            t = lambdaOrFunctionType(prevPos);
             break;
         case LPAREN:
             if (typeArgs == null && (mode & EXPR) != 0) {
@@ -1288,16 +1289,15 @@
         return toP(t);
     }
 
-    JCExpression lambdaOrFunctionType() {
+    JCExpression lambdaOrFunctionType(int pos) {
         return S.token() == LPAREN ?
-            lambdaExpressionOrStatement() :            
+            lambdaExpressionOrStatement(pos) :
             functionType();
     }
 
-    JCExpression lambdaExpressionOrStatement() {
+    JCExpression lambdaExpressionOrStatement(int pos) {
         mode = EXPR;
         checkLambda();
-        int pos = S.pos();
         List<JCVariableDecl> args = formalParameters();
         return S.token() == LBRACE ?
             lambdaExpression(args, pos) :
@@ -1328,7 +1328,8 @@
             typeList();
         accept(RPAREN);
         List<JCExpression> thrown = List.nil();
-        if (S.token() == LPAREN) {
+        if (S.token() == LPAREN &&
+                S.peekToken() == THROWS) {
             S.nextToken();
             accept(THROWS);
             thrown = qualidentList();
--- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Fri May 28 17:19:22 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Fri Jun 04 12:34:09 2010 +0100
@@ -89,6 +89,10 @@
     required: {2}\n\
     found: {3}\n\
     reason: {6}
+compiler.err.cant.apply.lambda=\
+    lambda expression cannot be applied to given types\n\
+    required: {0}\n\
+    found: {1}
 compiler.err.cant.assign.val.to.final.var=\
     cannot assign a value to final variable {0}
 compiler.err.cant.deref=\
@@ -101,6 +105,8 @@
     cannot reference {0} before supertype constructor has been called
 compiler.err.cant.ret.val.from.meth.decl.void=\
     cannot return a value from method whose result type is void
+compiler.err.cant.ret.void.expr=\
+    cannot return an expression whose type is void
 compiler.err.cant.select.static.class.from.param.type=\
     cannot select a static class from a parameterized type
 compiler.err.cant.inherit.diff.arg=\
@@ -265,8 +271,15 @@
 
 compiler.err.label.already.in.use=\
     label {0} already in use
-compiler.err.local.var.accessed.from.icls.needs.final=\
-    local variable {0} is accessed from within inner class; needs to be declared final
+
+compiler.err.local.var.accessed.from.inner.ctx.needs.final=\
+    local variable {0} is accessed from within {1}; needs to be declared final
+#where {1} is either
+compiler.misc.icls=\
+    an inner class
+compiler.misc.lambda=\
+    a lambda expression
+
 compiler.err.local.enum=\
     enum types must not be local
 compiler.err.cannot.create.array.with.type.arguments=\
@@ -327,6 +340,10 @@
 incompatible types for ?: neither is a subtype of the other\n\
 second operand: {0}\n\
 third operand : {1}
+compiler.err.incompatibles.ret.types.in.lambda=\
+incompatible return types in lambda expression: neither is a subtype of the other\n\
+expected type: {0}\n\
+found : {1}
 compiler.err.new.not.allowed.in.annotation=\
     ''new'' not allowed in an annotation
 compiler.err.no.annotation.member=\
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/BadAccess.java	Fri Jun 04 12:34:09 2010 +0100
@@ -0,0 +1,48 @@
+/*
+ * 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 check that non-static variables are not accessible from static lambdas
+ *          and that lambda can access only final locals
+ * @author  Maurizio Cimadamore
+ * @compile/fail/ref=BadAccess.out -XDrawDiagnostics BadAccess.java
+ */
+
+public class BadAccess {
+
+    int i;
+    static int I;
+
+    static void test1() {
+        int l = 0;
+        final int L = 0;
+        Object o = #()(i + I + l + L);
+    }
+
+    void test2() {
+        int l = 0;
+        final int L = 0;
+        Object o = #()(i + I + l + L);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/BadAccess.out	Fri Jun 04 12:34:09 2010 +0100
@@ -0,0 +1,4 @@
+BadAccess.java:40:24: compiler.err.non-static.cant.be.ref: kindname.variable, i
+BadAccess.java:40:32: compiler.err.local.var.accessed.from.inner.ctx.needs.final: l, (compiler.misc.lambda)
+BadAccess.java:46:32: compiler.err.local.var.accessed.from.inner.ctx.needs.final: l, (compiler.misc.lambda)
+3 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/BadLambdaCall.java	Fri Jun 04 12:34:09 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.
+ *
+ * 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 test for capture in nested lambda expressions
+ * @author  Maurizio Cimadamore
+ * @compile/fail/ref=BadLambdaCall.out -XDrawDiagnostics BadLambdaCall.java
+ */
+
+class BadLambdaCall {
+    void test(final int a0) {
+        #(){ }.(1); //too many args
+        #(int x){ }.(); //not enough args
+        #(int x){ }.(1,2); //not enough args
+        #(int x){ }.(""); //type mismatch
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/BadLambdaCall.out	Fri Jun 04 12:34:09 2010 +0100
@@ -0,0 +1,5 @@
+BadLambdaCall.java:33:16: compiler.err.cant.apply.lambda: compiler.misc.no.args, int
+BadLambdaCall.java:34:21: compiler.err.cant.apply.lambda: int, compiler.misc.no.args
+BadLambdaCall.java:35:21: compiler.err.cant.apply.lambda: int, int,int
+BadLambdaCall.java:36:21: compiler.err.cant.apply.lambda: int, java.lang.String
+4 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/BadReturn.java	Fri Jun 04 12:34:09 2010 +0100
@@ -0,0 +1,55 @@
+/*
+ * 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 check that incompatible return types in lambdas are flagged with error
+ * @author  Maurizio Cimadamore
+ * @compile/fail/ref=BadReturn.out -XDrawDiagnostics BadReturn.java
+ */
+
+class BadReturn {
+
+    static void testNeg1() {
+        Object o = #(){
+            if (true) {
+                return "";
+            } else {
+                return System.out.println("");
+            }};
+    }
+
+    static void testNeg2() {
+        Object o = #(){ return System.out.println(""); };
+    }
+
+    static void testPos() {
+        Comparable<?> o = #() {
+            if (false) {
+                return 10;
+            }
+            else {
+                return true;
+            }}.();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/BadReturn.out	Fri Jun 04 12:34:09 2010 +0100
@@ -0,0 +1,4 @@
+BadReturn.java:38:42: compiler.err.cant.ret.void.expr
+BadReturn.java:38:17: compiler.err.incompatibles.ret.types.in.lambda: java.lang.String, void
+BadReturn.java:43:50: compiler.err.cant.ret.void.expr
+3 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaCapture02.java	Fri Jun 04 12:34:09 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 LambdaCapture02
+ */
+
+public class LambdaCapture02 {
+
+    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 Integer n = 5;
+
+    //Simple local capture
+    void test1() {
+        final Integer N = 1;
+        int x = LambdaCapture02.<Integer,Integer>exec(#(Integer x)(x + N), 3);
+        assertTrue(4 == x);
+    }
+
+    //Local capture with multiple scopes (anon class)
+    void test2() {
+        final Integer N = 1;
+        new Tester() {
+            public void test() {
+                final Integer M = 2;
+                int x = LambdaCapture02.<Integer,Integer>exec(#(Integer x)(x + N + M), 3);
+                assertTrue(6 == x);
+            }
+        }.test();
+    }
+
+    //Local capture with multiple scopes (local class)
+    void test3() {
+        final Integer N = 1;
+        class MyTester implements Tester {
+            public void test() {
+                final Integer M = 2;
+                int x = LambdaCapture02.<Integer,Integer>exec(#(Integer x)(x + N + M), 3);
+                assertTrue(6 == x);
+            }
+        }
+        new MyTester().test();
+    }
+
+    //access to field from enclosing scope
+    void test4() {
+        final Integer N = 4;
+        int x1 = LambdaCapture02.<Integer,Integer>exec(#(Integer x)(x + n + N), 3);
+        assertTrue(12 == x1);
+        int x2 = LambdaCapture02.<Integer,Integer>exec(#(Integer x)(x + LambdaCapture02.this.n + N), 3);
+        assertTrue(12 == x2);
+    }
+
+    public static void main(String[] args) {
+        LambdaCapture02 t = new LambdaCapture02();
+        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/LambdaCapture03.java	Fri Jun 04 12:34:09 2010 +0100
@@ -0,0 +1,97 @@
+/*
+ * 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 test for capture of non-mutable locals/outer fields in multiple scopes
+ * @author  Maurizio Cimadamore
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles LambdaCapture03
+ */
+
+public class LambdaCapture03 {
+
+    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);
+    }
+
+    Integer n1 = 10;
+
+    void test1() {
+        final Integer N1 = 1;
+        class A {
+            Integer n2 = 20;
+            void test() {
+                  final Integer N2 = 2;
+                  class B {
+                       void test() {
+                           final Integer N3 = 3;
+                           int x = LambdaCapture03.exec(#(Integer x)(x + n1 + n2 + N1 + N2 + N3), 30);
+                           assertTrue(x == 66);
+                       }
+                  }
+                  new B().test();
+            }
+        }
+        new A().test();
+    }
+
+    void test2() {
+        final Integer N1 = 1;
+        new Tester() {
+            Integer n2 = 20;
+            public void test() {
+                final Integer N2 = 2;
+                new Tester() {
+                    public void test() {
+                        final Integer N3 = 3;
+                        int x = LambdaCapture03.exec(#(Integer x)(x + n1 + n2 + N1 + N2 + N3), 30);
+                        assertTrue(x == 66);
+                    }
+                }.test();
+            }
+        }.test();
+    }
+
+    public static void main(String[] args) {
+        LambdaCapture03 t = new LambdaCapture03();
+        t.test1();
+        t.test2();
+        assertTrue(assertionCount == 2);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaCapture04.java	Fri Jun 04 12:34:09 2010 +0100
@@ -0,0 +1,139 @@
+/*
+ * 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 test for capture of non-mutable locals/outer fields in multiple scopes
+ * @author  Maurizio Cimadamore
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles LambdaCapture04
+ */
+
+public class LambdaCapture04 {
+
+    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);
+    }
+
+    Integer n1 = 10;
+
+    void test1() {
+        final Integer N1 = 1;
+        class A {
+            Integer n2 = 20;
+            void test() {
+                  final Integer N2 = 2;
+                  class B {
+                       void test() {
+                           final Integer N3 = 3;
+                           #(final Integer x)(new Tester() { public void test() { assertTrue(x + n1 + n2 + N1 + N2 + N3 == 66); } }.test()).(30);
+                       }
+                  }
+                  new B().test();
+            }
+        }
+        new A().test();
+    }
+
+    void test2() {
+        final Integer N1 = 1;
+        class A {
+            Integer n2 = 20;
+            void test() {
+                  final Integer N2 = 2;
+                  class B {
+                       void test() {
+                           final Integer N3 = 3;
+                           #(final Integer x){
+                               class LocTester implements Tester {
+                                   public void test() { assertTrue(x + n1 + n2 + N1 + N2 + N3 == 66); }
+                               };
+                               new LocTester().test();}.(30);
+                       }
+                  }
+                  new B().test();
+            }
+        }
+        new A().test();
+    }
+
+    void test3() {
+        final Integer N1 = 1;
+        new Tester() {
+            Integer n2 = 20;
+            public void test() {
+                final Integer N2 = 2;
+                new Tester() {
+                    public void test() {
+                        final Integer N3 = 3;
+                        #(final Integer x)(new Tester() { public void test() { assertTrue(x + n1 + n2 + N1 + N2 + N3 == 66); } }.test()).(30);
+                    }
+                }.test();
+            }
+        }.test();
+    }
+
+    void test4() {
+        final Integer N1 = 1;
+        new Tester() {
+            Integer n2 = 20;
+            public void test() {
+                final Integer N2 = 2;
+                new Tester() {
+                    public void test() {
+                        final Integer N3 = 3;
+                        #(final Integer x){
+                            class LocTester implements Tester {
+                                public void test() { assertTrue(x + n1 + n2 + N1 + N2 + N3 == 66); }
+                            };
+                            new LocTester().test();}.(30);
+                    }
+                }.test();
+            }
+        }.test();
+    }
+
+    public static void main(String[] args) {
+        LambdaCapture04 t = new LambdaCapture04();
+        t.test1();
+        t.test2();
+        t.test3();
+        t.test4();
+        assertTrue(assertionCount == 4);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaCapture05.java	Fri Jun 04 12:34:09 2010 +0100
@@ -0,0 +1,67 @@
+/*
+ * 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 test for capture in nested lambda expressions
+ * @author  Maurizio Cimadamore
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles LambdaCapture05
+ */
+
+public class LambdaCapture05 {
+
+    static int assertionCount = 0;
+
+    static void assertTrue(boolean cond) {
+        assertionCount++;
+        if (!cond)
+            throw new AssertionError();
+    }
+
+    int i = 40;
+
+    void test1(final int a0) {
+        #(final int a1){
+            final Integer x2 = 10; #(final int a2) {
+                final Integer x3 = 20;
+                #(final int a3)(assertTrue(106 == (a0 + a1 + a2 + a3 + x2 + x3 + i))).(3);
+            }.(2);
+        }.(1);
+    }
+
+    static void test2(final int a0) {
+        #(final int a1){
+            final Integer x2 = 10; #(final int a2) {
+                final Integer x3 = 20;
+                #(final int a3)(assertTrue(66 == (a0 + a1 + a2 + a3 + x2 + x3))).(3);
+            }.(2);
+        }.(1);
+    }
+
+    public static void main(String[] args) {
+        LambdaCapture05 t = new LambdaCapture05();
+        t.test1(30);
+        test2(30);
+        assertTrue(assertionCount == 2);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaConv05.java	Fri Jun 04 12:34:09 2010 +0100
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @summary function type and method type inference
+ * @author  Alex Buckley
+ * @author  Maurizio Cimadamore
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles LambdaConv05
+ */
+
+import java.util.*;
+
+public class LambdaConv05 {
+
+    static void assertTrue(boolean cond) {
+        if (!cond)
+            throw new AssertionError();
+    }
+
+    int count = 0;
+
+    void sort(List<String> data) {
+      Collections.sort(data,
+                       #(String a, String b) { LambdaConv05.this.count++; return a.length()-b.length(); });
+    }
+
+    public static void main(String[] args) {
+        ArrayList<String> arr = new ArrayList<>();
+        arr.add("Three");
+        arr.add("Four");
+        arr.add("One");
+        LambdaConv05 sorter = new LambdaConv05();
+        sorter.sort(arr);
+        assertTrue(arr.get(0).equals("One"));
+        assertTrue(arr.get(1).equals("Four"));
+        assertTrue(arr.get(2).equals("Three"));
+        assertTrue(sorter.count == 2);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaScope02.java	Fri Jun 04 12:34:09 2010 +0100
@@ -0,0 +1,58 @@
+/*
+ * 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 check that MethodHandle members are accessible as expected
+ * @author  Maurizio Cimadamore
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles LambdaScope02
+ */
+
+public class LambdaScope02 {
+
+    static int assertionCount = 0;
+
+    static void assertTrue(boolean cond) {
+        assertionCount++;
+        if (!cond)
+            throw new AssertionError();
+    }
+
+    static void test1() {
+        final String sig = "(java.dyn.MethodHandle)void";
+        #() {assertTrue(this.type().toString().equals(sig));}.();
+        #() {assertTrue(type().toString().equals(sig));}.();
+    }
+
+    void test2() {
+        final String sig = "(java.dyn.MethodHandle,LambdaScope02)void";
+        #() {assertTrue(this.type().toString().equals(sig));}.();
+        #() {assertTrue(type().toString().equals(sig));}.();
+    }
+
+    public static void main(String[] args) {
+        test1();
+        new LambdaScope02().test2();
+        assertTrue(assertionCount == 4);
+    }
+}
--- a/test/tools/javac/lambda/NakedThis.out	Fri May 28 17:19:22 2010 +0100
+++ b/test/tools/javac/lambda/NakedThis.out	Fri Jun 04 12:34:09 2010 +0100
@@ -1,2 +1,2 @@
-NakedThis.java:33:16: compiler.err.cannot.infer.lambda.return.type
+NakedThis.java:33:15: compiler.err.cannot.infer.lambda.return.type
 1 error