8153884: Expression lambda erroneously compatible with void-returning descriptor
authormcimadamore
Mon, 16 May 2016 13:05:42 +0100
changeset 38508 03c87ceca5fd
parent 38507 d48ba9db4b7d
child 38509 01582f186579
8153884: Expression lambda erroneously compatible with void-returning descriptor Summary: Fix lambda compatibility check for void returning expressions Reviewed-by: vromero
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
langtools/test/tools/javac/Diagnostics/compressed/T8012003b.out
langtools/test/tools/javac/diags/examples/StatExprExpected.java
langtools/test/tools/javac/lambda/8153884/T8153884.java
langtools/test/tools/javac/lambda/8153884/T8153884.out
langtools/test/tools/javac/lambda/LambdaExpr10.out
langtools/test/tools/javac/lambda/LambdaExprNotVoid.out
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Mon May 16 12:03:41 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Mon May 16 13:05:42 2016 +0100
@@ -2678,6 +2678,7 @@
         class ExpressionLambdaReturnContext extends FunctionalReturnContext {
 
             JCExpression expr;
+            boolean expStmtExpected;
 
             ExpressionLambdaReturnContext(JCExpression expr, CheckContext enclosingContext) {
                 super(enclosingContext);
@@ -2685,10 +2686,23 @@
             }
 
             @Override
+            public void report(DiagnosticPosition pos, JCDiagnostic details) {
+                if (expStmtExpected) {
+                    enclosingContext.report(pos, diags.fragment(Fragments.StatExprExpected));
+                } else {
+                    super.report(pos, details);
+                }
+            }
+
+            @Override
             public boolean compatible(Type found, Type req, Warner warn) {
                 //a void return is compatible with an expression statement lambda
-                return TreeInfo.isExpressionStatement(expr) && req.hasTag(VOID) ||
-                        super.compatible(found, req, warn);
+                if (req.hasTag(VOID)) {
+                    expStmtExpected = true;
+                    return TreeInfo.isExpressionStatement(expr);
+                } else {
+                    return super.compatible(found, req, warn);
+                }
             }
         }
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Mon May 16 12:03:41 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Mon May 16 13:05:42 2016 +0100
@@ -779,6 +779,10 @@
     bad return type in lambda expression\n\
     {0}
 
+compiler.misc.stat.expr.expected=\
+    lambda body is not compatible with a void functional interface\n\
+    (consider using a block lambda body, or use a statement expression instead)
+
 # 0: type
 compiler.misc.incompatible.ret.type.in.mref=\
     bad return type in method reference\n\
--- a/langtools/test/tools/javac/Diagnostics/compressed/T8012003b.out	Mon May 16 12:03:41 2016 +0100
+++ b/langtools/test/tools/javac/Diagnostics/compressed/T8012003b.out	Mon May 16 13:05:42 2016 +0100
@@ -1,5 +1,5 @@
 T8012003b.java:30:12: compiler.err.prob.found.req: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.cant.apply.symbol: kindname.method, g, java.lang.String, compiler.misc.no.args, kindname.class, T8012003b, (compiler.misc.arg.length.mismatch)))
-T8012003b.java:31:16: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: int, void))
+T8012003b.java:31:16: compiler.err.prob.found.req: (compiler.misc.stat.expr.expected)
 T8012003b.java:32:22: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.conditional.target.cant.be.void))
 T8012003b.java:33:12: compiler.err.prob.found.req: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Integer, java.lang.String)))
 T8012003b.java:34:12: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.mref: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Integer))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/StatExprExpected.java	Mon May 16 13:05:42 2016 +0100
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.prob.found.req
+// key: compiler.misc.stat.expr.expected
+
+class StatExprExpected {
+    void test() {
+        Runnable r = () -> (foo());
+    }
+
+    int foo() { return 1; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8153884/T8153884.java	Mon May 16 13:05:42 2016 +0100
@@ -0,0 +1,14 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8153884
+ * @summary Expression lambda erroneously compatible with void-returning descriptor
+ * @compile/fail/ref=T8153884.out -XDrawDiagnostics T8153884.java
+ */
+
+class T8153884 {
+    void test() {
+        Runnable r = () -> (foo());
+    }
+
+    void foo() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8153884/T8153884.out	Mon May 16 13:05:42 2016 +0100
@@ -0,0 +1,2 @@
+T8153884.java:10:32: compiler.err.prob.found.req: (compiler.misc.stat.expr.expected)
+1 error
--- a/langtools/test/tools/javac/lambda/LambdaExpr10.out	Mon May 16 12:03:41 2016 +0100
+++ b/langtools/test/tools/javac/lambda/LambdaExpr10.out	Mon May 16 13:05:42 2016 +0100
@@ -4,6 +4,6 @@
 LambdaExpr10.java:24:46: compiler.err.prob.found.req: (compiler.misc.not.a.functional.intf: java.lang.Object)
 LambdaExpr10.java:28:29: compiler.err.prob.found.req: (compiler.misc.not.a.functional.intf: java.lang.Object)
 LambdaExpr10.java:29:33: compiler.err.prob.found.req: (compiler.misc.not.a.functional.intf: java.lang.Object)
-LambdaExpr10.java:33:35: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: java.lang.Object, void))
-LambdaExpr10.java:34:49: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: java.lang.Object, void))
+LambdaExpr10.java:33:35: compiler.err.prob.found.req: (compiler.misc.stat.expr.expected)
+LambdaExpr10.java:34:49: compiler.err.prob.found.req: (compiler.misc.stat.expr.expected)
 8 errors
--- a/langtools/test/tools/javac/lambda/LambdaExprNotVoid.out	Mon May 16 12:03:41 2016 +0100
+++ b/langtools/test/tools/javac/lambda/LambdaExprNotVoid.out	Mon May 16 13:05:42 2016 +0100
@@ -1,3 +1,3 @@
-LambdaExprNotVoid.java:14:21: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: int, void))
-LambdaExprNotVoid.java:15:21: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: int, void))
+LambdaExprNotVoid.java:14:21: compiler.err.prob.found.req: (compiler.misc.stat.expr.expected)
+LambdaExprNotVoid.java:15:21: compiler.err.prob.found.req: (compiler.misc.stat.expr.expected)
 2 errors