changeset 1232:2a25ce881443

Bug fixes: *) Missing synthetic cast in desugared code leading to verifier errors *) Bad generated code for void-compatible lambdas *) Attribution should compute the instantiated method/constructor type of a given member reference *) Check for break/continue inside lambda body misses some cases
author mcimadamore
date Tue, 22 Nov 2011 13:39:42 +0000
parents 402a2c7d0c68
children 230445847204
files 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/LambdaToInnerClass.java src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java src/share/classes/com/sun/tools/javac/comp/LambdaTranslator.java src/share/classes/com/sun/tools/javac/comp/Resolve.java src/share/classes/com/sun/tools/javac/comp/TransTypes.java test/tools/javac/lambda/BadBreakContinue.java test/tools/javac/lambda/BadBreakContinue.out test/tools/javac/lambda/LambdaConv20.java test/tools/javac/lambda/LambdaConv21.java test/tools/javac/lambda/MethodReference31.java test/tools/javac/lambda/MethodReference32.java test/tools/javac/lambda/MethodReference32.out
diffstat 14 files changed, 550 insertions(+), 66 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Nov 10 23:02:59 2011 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Nov 22 13:39:42 2011 +0000
@@ -1376,11 +1376,14 @@
             boolean seenLambda = false;
             LOOP:
             while (env1 != null) {
-                seenLambda |= env1.info.lambdaAttr;
+                seenLambda |= env1.tree.getTag() == JCTree.LAMBDA;
                 switch (env1.tree.getTag()) {
                 case JCTree.LABELLED:
                     JCLabeledStatement labelled = (JCLabeledStatement)env1.tree;
                     if (label == labelled.label) {
+                        if (seenLambda) {
+                            badLambdaJump(pos, tag);
+                        }
                         // If jump is a continue, check that target is a loop.
                         if (tag == JCTree.CONTINUE) {
                             if (labelled.body.getTag() != JCTree.DOLOOP &&
@@ -1390,14 +1393,8 @@
                                 log.error(pos, "not.loop.label", label);
                             // Found labelled statement target, now go inwards
                             // to next non-labelled tree.
-                            if (seenLambda) {
-                                log.error(pos, "cont.inside.lambda");
-                            }
                             return TreeInfo.referencedStatement(labelled);
                         } else {
-                            if (seenLambda) {
-                                log.error(pos, "break.inside.lambda");
-                            }
                             return labelled;
                         }
                     }
@@ -1406,10 +1403,20 @@
                 case JCTree.WHILELOOP:
                 case JCTree.FORLOOP:
                 case JCTree.FOREACHLOOP:
-                    if (label == null) return env1.tree;
+                    if (label == null) {
+                        if (seenLambda) {
+                            badLambdaJump(pos, tag);
+                        }
+                        return env1.tree;
+                    }
                     break;
                 case JCTree.SWITCH:
-                    if (label == null && tag == JCTree.BREAK) return env1.tree;
+                    if (label == null && tag == JCTree.BREAK) {
+                        if (seenLambda) {
+                            badLambdaJump(pos, tag);
+                        }
+                        return env1.tree;
+                    }
                     break;
                 case JCTree.METHODDEF:
                 case JCTree.CLASSDEF:
@@ -1430,6 +1437,12 @@
                     "break.outside.switch.loop");
             return null;
         }
+        //where
+            private void badLambdaJump(DiagnosticPosition pos, int tag) {
+                log.error(pos, tag == JCTree.CONTINUE ?
+                                    "cont.inside.lambda" :
+                                    "break.inside.lambda");
+            }
 
     public void visitReturn(JCReturn tree) {
         // Check that there is an enclosing method which is
@@ -2628,17 +2641,20 @@
         }
 
         tree.sym = refSym;
-        Type mtype = types.memberType(tree.expr.type, tree.sym);
+        
+        boolean isUnbound = (!refSym.isStatic() && !refSym.isConstructor() &&
+                    TreeInfo.isStaticSelector(tree.getQualifierExpression(), names));
+        
+        Type refType = checkReference(tree.expr.type, refSym, localEnv, tree.args, argtypes, typeargtypes, isUnbound);
         Type returnType = tree.getMode() == ReferenceMode.INVOKE ?
-                mtype.getReturnType() : tree.expr.type;
+                refType.getReturnType() : tree.expr.type;
 
         if (tree.args != null) {
             //if method ref has explict param types, perform an explicit
             //applicability check; this amounts at checking that types in the
             //SAM desctiptor are method-compatible with the resolved signature
             List<Type> paramsToCheck = samDesc.getParameterTypes();
-            if (!refSym.isStatic() && !refSym.isConstructor() &&
-                    TreeInfo.isStaticSelector(tree.getQualifierExpression(), names)) {
+            if (isUnbound) {
                 //if this is an unbound reference, we need to drop the first parameter
                 //(which should be a subtype of the receiver expression)
                 if (paramsToCheck.isEmpty() ||
@@ -2647,7 +2663,7 @@
                 }
                 paramsToCheck = paramsToCheck.tail;
             }
-            if (!rs.argumentsAcceptable(localEnv, mtype, paramsToCheck, allowBoxing, (refSym.flags() & VARARGS) != 0, Warner.noWarnings)) {
+            if (!rs.argumentsAcceptable(localEnv, refType, paramsToCheck, allowBoxing, (refSym.flags() & VARARGS) != 0, Warner.noWarnings)) {
                 throw new Infer.InferenceException(diags).setMessage("infer.incompatible.arg.types.in.lambda");
             }
         }
@@ -2655,9 +2671,17 @@
         //go ahead with standard SAM compatibility check - note that param check
         //is a no-op (as this has been taken care during method applicability)
         checkSAMCompatible(inferenceContext, to, List.of(returnType),
-                samDesc.getParameterTypes(), mtype.getThrownTypes(), allowBoxing, true);
+                samDesc.getParameterTypes(), refType.getThrownTypes(), allowBoxing, true);
         return tree.targetType = to;
     }
+    //where
+        private Type checkReference(Type site, Symbol sym, Env<AttrContext> env, List<JCExpression> argtrees,
+                                    List<Type> argtypes, List<Type> typeargtypes, boolean isUnbound) {
+            if (isUnbound && argtrees == null) {
+                argtypes = argtypes.tail;
+            }
+            return checkMethod(site, sym, env, argtrees, argtypes, typeargtypes, env.info.varArgs);
+        }
 
     /**
      * SAM compatibility. Check that given return types, thrown types, parameter types
--- a/src/share/classes/com/sun/tools/javac/comp/Check.java	Thu Nov 10 23:02:59 2011 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/Check.java	Tue Nov 22 13:39:42 2011 +0000
@@ -901,6 +901,8 @@
             case JCTree.NEWCLASS:
                 ((JCNewClass) tree).varargsElement = elemtype;
                 break;
+            case JCTree.REFERENCE:
+                break;
             default:
                 throw new AssertionError(""+tree);
         }
--- a/src/share/classes/com/sun/tools/javac/comp/LambdaToInnerClass.java	Thu Nov 10 23:02:59 2011 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToInnerClass.java	Tue Nov 22 13:39:42 2011 +0000
@@ -124,7 +124,7 @@
         }
         samMethodDecl.params = params.toList();
 
-        samMethodDecl.body = translate(makeLambdaBody(tree, localContext.translatedSym.type.getReturnType()));
+        samMethodDecl.body = translate(makeLambdaBody(tree, samMethodDecl));
         localContext.lambdaClassSym.members().enter(samConstrDecl.sym);
         localContext.lambdaClassSym.members().enter(samMethodDecl.sym);
 
@@ -232,13 +232,15 @@
             ref_call = make.NewClass(rec, null, tree.getQualifierExpression(), convertArgs(refSym, args.toList()), null)
                     .setType(tree.getQualifierExpression().type);
             ((JCNewClass)ref_call).constructor = refSym;
+            ((JCNewClass)ref_call).constructorType = refSym.erasure(types);
         } else {
             JCExpression meth = rec == null ?
                     make.Ident(refSym) :
                     make.Select(rec, refSym);
-            ref_call = make.Apply(List.<JCExpression>nil(), meth,
+            ref_call = make.Apply(List.<JCExpression>nil(), meth.setType(refSym.erasure(types)),
                     convertArgs(refSym, args.toList()), false)
-                    .setType(localContext.translatedSym.type.getReturnType());
+                    .setType(refSym.erasure(types).getReturnType());
+            ref_call = transTypes.coerce(ref_call, localContext.translatedSym.type.getReturnType());
         }
         setVarargsIfNeeded(ref_call, refSym);
         
--- a/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Thu Nov 10 23:02:59 2011 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Tue Nov 22 13:39:42 2011 +0000
@@ -102,7 +102,7 @@
         localContext.translatedSym.type = lambdaType = types.createMethodTypeWithParameters(lambdaType, TreeInfo.types(syntheticParams.toList()));
 
         //create method declaration hoisting the lambda body
-        JCBlock body = translate(makeLambdaBody(tree, lambdaType.getReturnType()));
+        
         JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(STATIC | SYNTHETIC),
                 localContext.translatedSym.name,
                 make.QualIdent(lambdaType.getReturnType().tsym),
@@ -111,12 +111,14 @@
                 lambdaType.getThrownTypes() == null ?
                     List.<JCExpression>nil() :
                     make.Types(lambdaType.getThrownTypes()),
-                body,
+                null,
                 null);
         lambdaDecl.sym = (MethodSymbol)localContext.translatedSym;
         lambdaDecl.type = lambdaType;
-
+        
         //translate lambda body
+        lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl));
+        
         trans_static = trans_static.prepend(lambdaDecl);
 
         //Step Two:
@@ -359,12 +361,13 @@
             //create the qualifier expression
             JCFieldAccess select = make.Select(qualifier, tree.sym.name);
             select.sym = tree.sym;
-            select.type = localContext.generatedRefSig();
+            select.type = tree.sym.erasure(types);
 
             //create the method call expression
-            JCMethodInvocation apply = make.Apply(List.<JCExpression>nil(), select,
-                    convertArgs(tree.sym, args.toList()), false);
-            apply.type = samDesc.getReturnType();
+            JCExpression apply = make.Apply(List.<JCExpression>nil(), select,
+                    convertArgs(tree.sym, args.toList()), false).setType(tree.sym.erasure(types).getReturnType());
+
+            apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType());
             setVarargsIfNeeded(apply, tree.sym);
 
             //the body is either a return expression containing a method call,
@@ -385,7 +388,7 @@
                                                 convertArgs(tree.sym, args.toList()),
                                                 null);
             newClass.constructor = tree.sym;
-            newClass.constructorType = types.memberType(tree.sym.owner.type, tree.sym);
+            newClass.constructorType = tree.sym.erasure(types);
             newClass.type = tree.getQualifierExpression().type;
             setVarargsIfNeeded(newClass, tree.sym);
 
--- a/src/share/classes/com/sun/tools/javac/comp/LambdaTranslator.java	Thu Nov 10 23:02:59 2011 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/LambdaTranslator.java	Tue Nov 22 13:39:42 2011 +0000
@@ -216,37 +216,72 @@
     // </editor-fold>
 
     // <editor-fold defaultstate="collapsed" desc="Translation helper methods">
-    /**
-     * Generate desugared code for the lambda body; for expression lambdas
-     * a synthetic return statement might be added (if lambda can complete
-     * normally). Also, a return statement is added if the return type of
-     * he SAM descriptor is 'java.lang.Void' and the lambda expression is 'void'.
-     */
-    JCBlock makeLambdaBody(JCLambda tree, Type restype) {
-        JCReturn defaultRet = null;
-        if (tree.canCompleteNormally &&
-                types.isSameType(restype, types.boxedClass(syms.voidType).type)) {
-            //there's no return statement and the lambda (possibly inferred)
-            //return type is java.lang.Void; sets the NEEDS_RETURN flag in
-            //order to tell code generation to emit a synthetic return statement
-            defaultRet = make.Return(make.Literal(TypeTags.BOT, null).setType(syms.botType));
+    JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) {
+        return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
+                makeLambdaExpressionBody(tree, lambdaMethodDecl) :
+                makeLambdaStatementBody(tree, lambdaMethodDecl);
+    }
+    
+    JCBlock makeLambdaExpressionBody(JCLambda lambda, JCMethodDecl lambdaMethodDecl) {
+        Type restype = lambdaMethodDecl.type.getReturnType();
+        boolean isLambda_void = lambda.body.type.tag == TypeTags.VOID;
+        boolean isTarget_void = restype.tag == TypeTags.VOID;
+        boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
+        if (isTarget_void) {
+            //target is void:
+            // BODY;
+            JCStatement stat = make.Exec((JCExpression)lambda.body);
+            return make.Block(0, List.<JCStatement>of(stat));
+        } else if (isLambda_void && isTarget_Void) {
+            //void to Void conversion:
+            // BODY; return null;
+            ListBuffer<JCStatement> stats = ListBuffer.lb();
+            stats.append(make.Exec((JCExpression)lambda.body));
+            stats.append(make.Return(make.Literal(TypeTags.BOT, null).setType(syms.botType)));
+            return make.Block(0, stats.toList());
+        } else {
+            //non-void to non-void conversion:
+            // return (TYPE)BODY;
+            JCExpression retExpr = transTypes.coerce((JCExpression)lambda.body, restype);
+            return make.Block(0, List.<JCStatement>of(make.Return(retExpr)));
         }
-        JCBlock body = null;
-        if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION &&
-                tree.body.type != syms.voidType) {
-            body = make.Block(0, List.<JCStatement>of(make.Return((JCExpression)tree.body)));
-        } else {
-            switch (tree.body.getTag()) {
-                case JCTree.BLOCK: body = (JCBlock)tree.body; break;
-                default:
-                    JCStatement stat = make.Exec((JCExpression)tree.body);
-                    body = make.Block(0, List.<JCStatement>of(stat));
+    }
+    
+    JCBlock makeLambdaStatementBody(JCLambda lambda, final JCMethodDecl lambdaMethodDecl) {
+        final Type restype = lambdaMethodDecl.type.getReturnType();
+        final boolean isTarget_void = restype.tag == TypeTags.VOID;
+        boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
+        
+        class LambdaBodyTranslator extends TreeTranslator {
+            @Override
+            public void visitReturn(JCReturn tree) {
+                boolean isLambda_void = tree.expr == null;
+                if (isTarget_void && !isLambda_void) {
+                    //Void to void conversion:
+                    // { TYPE $loc = RET-EXPR; return; }
+                    VarSymbol loc = makeSyntheticVar(0, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym);
+                    JCVariableDecl varDef = make.VarDef(loc, tree.expr);
+                    result = make.Block(0, List.<JCStatement>of(varDef, make.Return(null)));
+                    return;
+                } else if (!isTarget_void || !isLambda_void) {
+                    //non-void to non-void conversion:
+                    // return (TYPE)RET-EXPR;
+                    tree.expr = transTypes.coerce(tree.expr, restype);
+                    result = tree;
+                } else {
+                    result = tree;
+                }
+                
             }
         }
-        if (defaultRet != null) {
-            body.stats = body.stats.append(defaultRet);
+        
+        JCBlock block = new LambdaBodyTranslator().translate((JCBlock)lambda.body);
+        if (lambda.canCompleteNormally && isTarget_Void) {
+            //there's no return statement and the lambda (possibly inferred)
+            //return type is java.lang.Void; emit a synthetic return statement
+            block.stats = block.stats.append(make.Return(make.Literal(TypeTags.BOT, null).setType(syms.botType)));
         }
-        return body;
+        return block;
     }
     
     /**
--- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Thu Nov 10 23:02:59 2011 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Tue Nov 22 13:39:42 2011 +0000
@@ -2014,6 +2014,9 @@
             if (argtypes.nonEmpty() &&
                     ((isMethodRef && types.isSubtypeUnchecked(argtypes.head, site) ||
                     (isConstructorRef && types.asEnclosingSuper(site, argtypes.head.tsym) != null)))) {
+                boolean prevVarargs = env.info.varArgs;
+                env.info.varArgs = false;
+                
                 Symbol sym2 = methodNotFound;
                 sym2 = findMemberReference(pos, env, site, name,
                                            argtypes.tail, typeargtypes,
@@ -2022,6 +2025,8 @@
                 if (sym2.kind == MTH) {
                     bestSoFar = bestSoFar.kind == MTH ?
                         ambiguityError(bestSoFar, sym2) : sym2;
+                } else {
+                    env.info.varArgs = prevVarargs;
                 }
             }
         } else {
@@ -2062,10 +2067,10 @@
                 sym = name.equals(names.init) ?
                     findConstructor(pos, env, site, argtypes, typeargtypes,
                                     steps.head.isBoxingRequired(),
-                                    steps.head.isVarargsRequired()) :
+                                    env.info.varArgs = steps.head.isVarargsRequired()) :
                     findMethod(env, site, name, argtypes, typeargtypes,
                                steps.head.isBoxingRequired(),
-                               steps.head.isVarargsRequired(), false);
+                               env.info.varArgs = steps.head.isVarargsRequired(), false);
                 currentResolutionContext.resolutionCache.put(steps.head, sym);
                 steps = steps.tail;
             }
--- a/src/share/classes/com/sun/tools/javac/comp/TransTypes.java	Thu Nov 10 23:02:59 2011 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/TransTypes.java	Tue Nov 22 13:39:42 2011 +0000
@@ -552,16 +552,15 @@
 
     public void visitLambda(JCLambda tree) {
         JCTree prevMethod = currentMethod;
-        Type prevPt = pt;
         try {
-            currentMethod = tree;
-            pt = null;
+            currentMethod = null;
+            tree.params = translate(tree.params);
+            tree.body = translate(tree.body, null);
             tree.type = erasure(tree.type);
-            super.visitLambda(tree);
+            result = tree;
         }
         finally {
             currentMethod = prevMethod;
-            pt = prevPt;
         }
     }
 
@@ -616,10 +615,7 @@
     }
 
     public void visitReturn(JCReturn tree) {
-        Type methType = tree.getTag() == JCTree.LAMBDA ?
-                types.findDescriptor(((JCLambda)currentMethod).targetType) :
-                currentMethod.type;
-        tree.expr = translate(tree.expr, types.erasure(methType).getReturnType());
+        tree.expr = translate(tree.expr, currentMethod != null ? types.erasure(currentMethod.type).getReturnType() : null);
         result = tree;
     }
 
--- a/test/tools/javac/lambda/BadBreakContinue.java	Thu Nov 10 23:02:59 2011 +0000
+++ b/test/tools/javac/lambda/BadBreakContinue.java	Tue Nov 22 13:39:42 2011 +0000
@@ -41,7 +41,7 @@
         SAM s3_2 = ()-> { continue; };
     };
 
-    void test() {
+    void testLabelled() {
         loop: while (true) {
             SAM s1 = ()-> { break loop; };
             SAM s2 = ()-> { continue loop; };
@@ -51,4 +51,15 @@
             };
         }
     }
+    
+    void testNonLabelled() {
+        while (true) {
+            SAM s1 = ()-> { break; };
+            SAM s2 = ()-> { continue; };
+            SAM s3 = ()-> {
+                SAM s3_1 = ()-> { break; };
+                SAM s3_2 = ()-> { continue; };
+            };
+        }
+    }
 }
--- a/test/tools/javac/lambda/BadBreakContinue.out	Thu Nov 10 23:02:59 2011 +0000
+++ b/test/tools/javac/lambda/BadBreakContinue.out	Tue Nov 22 13:39:42 2011 +0000
@@ -6,4 +6,8 @@
 BadBreakContinue.java:47:29: compiler.err.cont.inside.lambda
 BadBreakContinue.java:49:35: compiler.err.break.inside.lambda
 BadBreakContinue.java:50:35: compiler.err.cont.inside.lambda
-8 errors
+BadBreakContinue.java:57:29: compiler.err.break.inside.lambda
+BadBreakContinue.java:58:29: compiler.err.cont.inside.lambda
+BadBreakContinue.java:60:35: compiler.err.break.inside.lambda
+BadBreakContinue.java:61:35: compiler.err.cont.inside.lambda
+12 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaConv20.java	Tue Nov 22 13:39:42 2011 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary check that synthetic casts are added when erased type of lambda body
+ *          ends up being too general 
+ * @run main LambdaConv20
+ */
+
+import java.util.*;
+
+public class LambdaConv20 {
+    
+    static int assertionCount = 0;
+
+    static void assertTrue(boolean cond) {
+        assertionCount++;
+        if (!cond)
+            throw new AssertionError();
+    }
+
+    interface SAM<X> {
+        X m(List<X> l);
+    }
+    
+    public static void main(String[] args) {
+        SAM<Integer> si1 = l -> l.get(0);
+        assertTrue(si1.m(Arrays.asList(1)) == 1);
+        SAM<Integer> si2 = l -> { return l.get(0); };
+        assertTrue(si2.m(Arrays.asList(1)) == 1);
+        assertTrue(assertionCount == 2);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaConv21.java	Tue Nov 22 13:39:42 2011 +0000
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary check that code generation handles void-compatibility correctly
+ * @run main LambdaConv21
+ */
+
+public class LambdaConv21 {
+    
+    static int assertionCount = 0;
+
+    static void assertTrue(boolean cond) {
+        assertionCount++;
+        if (!cond)
+            throw new AssertionError();
+    }
+
+    interface SAM_void<X> {
+        void m();
+    }
+    
+    interface SAM_Void<X> {
+        void m();
+    }
+    
+    static void m_void() { assertTrue(true); }
+    
+    static Void m_Void() { assertTrue(true); return null; }
+    
+    public static void main(String[] args) {
+        testExpressionLambda();
+        testStatementLambda();
+        assertTrue(assertionCount == 10);
+    }
+    
+    static void testExpressionLambda() {
+        SAM_void s1 = ()->m_void();
+        s1.m();
+        SAM_Void s2 = ()->m_void();
+        s2.m();
+        SAM_void s3 = ()->m_Void();
+        s3.m();
+        SAM_Void s4 = ()->m_Void();
+        s4.m();
+    }
+    
+    static void testStatementLambda() {
+        SAM_void s1 = ()-> { m_void(); };
+        s1.m();
+        SAM_Void s2 = ()-> { m_void(); };
+        s2.m();
+        SAM_void s3 = ()-> { return m_Void(); };
+        s3.m();
+        SAM_Void s4 = ()-> { return m_Void(); };
+        s4.m();
+        SAM_void s5 = ()-> { m_Void(); };
+        s5.m();
+        SAM_Void s6 = ()-> { m_Void(); };
+        s6.m();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/MethodReference31.java	Tue Nov 22 13:39:42 2011 +0000
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary check that boxing of return-type works as expected
+ */
+
+public class MethodReference31 {
+    
+    static class Success extends RuntimeException { }
+    
+    static int assertionCount = 0;
+
+    static void assertTrue(boolean cond) {
+        assertionCount++;
+        if (!cond)
+            throw new AssertionError();
+    }
+
+    interface SAM<X> {
+        X m();
+    }
+
+    interface SAM_byte {
+        byte m();
+    }
+
+    interface SAM_short {
+        short m();
+    }
+
+    interface SAM_int {
+        int m();
+    }
+
+    interface SAM_long {
+        long m();
+    }
+
+    interface SAM_float {
+        float m();
+    }
+
+    interface SAM_double {
+        double m();
+    }
+    
+    static <Z> Z test() {
+        assertTrue(true);
+        throw new Success();
+    }
+    
+    static byte test_byte() {
+        assertTrue(true);
+        return 0;
+    }
+    
+    static short test_short() {
+        assertTrue(true);
+        return 0;
+    }
+    
+    static int test_int() {
+        assertTrue(true);
+        return 0;
+    }
+    
+    static long test_long() {
+        assertTrue(true);
+        return 0;
+    }
+    
+    static float test_float() {
+        assertTrue(true);
+        return 0;
+    }
+
+    static double test_double() {
+        assertTrue(true);
+        return 0;
+    }
+
+    static void testByte() {
+        SAM<Byte> s1 = MethodReference31#test_byte;
+        s1.m();
+        SAM_byte s2 = MethodReference31#test_byte;
+        s2.m();
+        SAM<Byte> s3 = MethodReference31#<Byte>test;
+        try {
+            s3.m();
+        }
+        catch (RuntimeException ex) { }
+        SAM_byte s4 = MethodReference31#<Byte>test;
+        try {
+            s4.m();
+        }
+        catch (RuntimeException ex) { }
+    }
+    
+    static void testShort() {
+        SAM<Short> s1 = MethodReference31#test_short;
+        s1.m();
+        SAM_short s2 = MethodReference31#test_short;
+        s2.m();
+        SAM<Short> s3 = MethodReference31#<Short>test;
+        try {
+            s3.m();
+        }
+        catch (RuntimeException ex) { }
+        SAM_short s4 = MethodReference31#<Short>test;
+        try {
+            s4.m();
+        }
+        catch (RuntimeException ex) { }
+    }
+    
+    static void testInteger() {
+        SAM<Integer> s1 = MethodReference31#test_int;
+        s1.m();
+        SAM_int s2 = MethodReference31#test_int;
+        s2.m();
+        SAM<Integer> s3 = MethodReference31#<Integer>test;
+        try {
+            s3.m();
+        }
+        catch (RuntimeException ex) { }
+        SAM_int s4 = MethodReference31#<Integer>test;
+        try {
+            s4.m();
+        }
+        catch (RuntimeException ex) { }
+    }
+    
+    static void testLong() {
+        SAM<Long> s1 = MethodReference31#test_long;
+        s1.m();
+        SAM_long s2 = MethodReference31#test_long;
+        s2.m();
+        SAM<Long> s3 = MethodReference31#<Long>test;
+        try {
+            s3.m();
+        }
+        catch (RuntimeException ex) { }
+        SAM_long s4 = MethodReference31#<Long>test;
+        try {
+            s4.m();
+        }
+        catch (RuntimeException ex) { }
+    }
+    
+    static void testFloat() {
+        SAM<Float> s1 = MethodReference31#test_float;
+        s1.m();
+        SAM_float s2 = MethodReference31#test_float;
+        s2.m();
+        SAM<Float> s3 = MethodReference31#<Float>test;
+        try {
+            s3.m();
+        }
+        catch (RuntimeException ex) { }
+        SAM_float s4 = MethodReference31#<Float>test;
+        try {
+            s4.m();
+        }
+        catch (RuntimeException ex) { }
+    }
+    
+    static void testDouble() {
+        SAM<Double> s1 = MethodReference31#test_double;
+        s1.m();
+        SAM_double s2 = MethodReference31#test_double;
+        s2.m();
+        SAM<Double> s3 = MethodReference31#<Double>test;
+        try {
+            s3.m();
+        }
+        catch (RuntimeException ex) { }
+        SAM_double s4 = MethodReference31#<Double>test;
+        try {
+            s4.m();
+        }
+        catch (RuntimeException ex) { }
+    }
+    
+    public static void main(String[] args) {
+        testByte();
+        testShort();
+        testInteger();
+        testLong();
+        testFloat();
+        testDouble();
+        assertTrue(assertionCount == 24);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/MethodReference32.java	Tue Nov 22 13:39:42 2011 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary check that varargs warnings are generated during SAM conversion
+ * @compile/fail/ref=MethodReference32.out -Xlint:unchecked -Werror -XDrawDiagnostics MethodReference32.java
+ */
+
+import java.util.*;
+
+class MethodReference32 {
+
+    interface SAM {
+        MethodReference32 m(List<Integer> l1, List<Integer> l2);
+    }
+
+    MethodReference32 meth(List<Integer>... lli) { return null; }
+    MethodReference32(List<Integer>... lli) { }
+
+    SAM s1 = this#meth;
+    SAM s2 = MethodReference32#new;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/MethodReference32.out	Tue Nov 22 13:39:42 2011 +0000
@@ -0,0 +1,7 @@
+MethodReference32.java:38:45: compiler.warn.unchecked.varargs.non.reifiable.type: java.util.List<java.lang.Integer>
+MethodReference32.java:39:40: compiler.warn.unchecked.varargs.non.reifiable.type: java.util.List<java.lang.Integer>
+MethodReference32.java:41:14: compiler.warn.unchecked.generic.array.creation: java.util.List<java.lang.Integer>[]
+MethodReference32.java:42:14: compiler.warn.unchecked.generic.array.creation: java.util.List<java.lang.Integer>[]
+- compiler.err.warnings.and.werror
+1 error
+4 warnings