8153884: Expression lambda erroneously compatible with void-returning descriptor

Fix lambda compatibility check for void returning expressions

Reviewed-by: vromero
This commit is contained in:
Maurizio Cimadamore 2016-05-16 13:05:42 +01:00
parent eef5821303
commit 7fa26cbc1e
8 changed files with 76 additions and 7 deletions

View File

@ -2678,17 +2678,31 @@ public class Attr extends JCTree.Visitor {
class ExpressionLambdaReturnContext extends FunctionalReturnContext {
JCExpression expr;
boolean expStmtExpected;
ExpressionLambdaReturnContext(JCExpression expr, CheckContext enclosingContext) {
super(enclosingContext);
this.expr = expr;
}
@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);
}
}
}

View File

@ -779,6 +779,10 @@ compiler.misc.incompatible.ret.type.in.lambda=\
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\

View File

@ -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))

View File

@ -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; }
}

View File

@ -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() { }
}

View File

@ -0,0 +1,2 @@
T8153884.java:10:32: compiler.err.prob.found.req: (compiler.misc.stat.expr.expected)
1 error

View File

@ -4,6 +4,6 @@ LambdaExpr10.java:23:40: compiler.err.prob.found.req: (compiler.misc.not.a.funct
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

View File

@ -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