8004105: Expression statement lambdas should be void-compatible
Summary: Fix lambda compatibility rules as per latest EDR
Reviewed-by: jjg
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Thu Nov 29 09:41:48 2012 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Fri Nov 30 15:14:12 2012 +0000
@@ -2244,9 +2244,13 @@
//with the target-type, it will be recovered anyway in Attr.checkId
needsRecovery = false;
+ FunctionalReturnContext funcContext = that.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
+ new ExpressionLambdaReturnContext((JCExpression)that.getBody(), resultInfo.checkContext) :
+ new FunctionalReturnContext(resultInfo.checkContext);
+
ResultInfo bodyResultInfo = lambdaType.getReturnType() == Type.recoveryType ?
recoveryInfo :
- new ResultInfo(VAL, lambdaType.getReturnType(), new LambdaReturnContext(resultInfo.checkContext));
+ new ResultInfo(VAL, lambdaType.getReturnType(), funcContext);
localEnv.info.returnResult = bodyResultInfo;
if (that.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
@@ -2327,8 +2331,9 @@
* type according to both the inherited context and the assignment
* context.
*/
- class LambdaReturnContext extends Check.NestedCheckContext {
- public LambdaReturnContext(CheckContext enclosingContext) {
+ class FunctionalReturnContext extends Check.NestedCheckContext {
+
+ FunctionalReturnContext(CheckContext enclosingContext) {
super(enclosingContext);
}
@@ -2344,6 +2349,23 @@
}
}
+ class ExpressionLambdaReturnContext extends FunctionalReturnContext {
+
+ JCExpression expr;
+
+ ExpressionLambdaReturnContext(JCExpression expr, CheckContext enclosingContext) {
+ super(enclosingContext);
+ this.expr = expr;
+ }
+
+ @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);
+ }
+ }
+
/**
* Lambda compatibility. Check that given return types, thrown types, parameter types
* are compatible with the expected functional interface descriptor. This means that:
@@ -2560,7 +2582,7 @@
if (!returnType.hasTag(VOID) && !resType.hasTag(VOID)) {
if (resType.isErroneous() ||
- new LambdaReturnContext(checkContext).compatible(resType, returnType, types.noWarnings)) {
+ new FunctionalReturnContext(checkContext).compatible(resType, returnType, types.noWarnings)) {
incompatibleReturnType = null;
}
}
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Thu Nov 29 09:41:48 2012 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Fri Nov 30 15:14:12 2012 +0000
@@ -3171,21 +3171,12 @@
/** Check that given tree is a legal expression statement.
*/
protected JCExpression checkExprStat(JCExpression t) {
- switch(t.getTag()) {
- case PREINC: case PREDEC:
- case POSTINC: case POSTDEC:
- case ASSIGN:
- case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG:
- case SL_ASG: case SR_ASG: case USR_ASG:
- case PLUS_ASG: case MINUS_ASG:
- case MUL_ASG: case DIV_ASG: case MOD_ASG:
- case APPLY: case NEWCLASS:
- case ERRONEOUS:
- return t;
- default:
+ if (!TreeInfo.isExpressionStatement(t)) {
JCExpression ret = F.at(t.pos).Erroneous(List.<JCTree>of(t));
error(ret, "not.stmt");
return ret;
+ } else {
+ return t;
}
}
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java Thu Nov 29 09:41:48 2012 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java Fri Nov 30 15:14:12 2012 +0000
@@ -267,6 +267,25 @@
return lambda.params.isEmpty() ||
lambda.params.head.vartype != null;
}
+
+ /** Return true if the tree corresponds to an expression statement */
+ public static boolean isExpressionStatement(JCExpression tree) {
+ switch(tree.getTag()) {
+ case PREINC: case PREDEC:
+ case POSTINC: case POSTDEC:
+ case ASSIGN:
+ case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG:
+ case SL_ASG: case SR_ASG: case USR_ASG:
+ case PLUS_ASG: case MINUS_ASG:
+ case MUL_ASG: case DIV_ASG: case MOD_ASG:
+ case APPLY: case NEWCLASS:
+ case ERRONEOUS:
+ return true;
+ default:
+ return false;
+ }
+ }
+
/**
* Return true if the AST corresponds to a static select of the kind A.B
*/
--- a/langtools/test/tools/javac/lambda/LambdaConv21.java Thu Nov 29 09:41:48 2012 +0000
+++ b/langtools/test/tools/javac/lambda/LambdaConv21.java Fri Nov 30 15:14:12 2012 +0000
@@ -23,7 +23,7 @@
static void testExpressionLambda() {
SAM_void s1 = ()->m_void(); //ok
SAM_java_lang_Void s2 = ()->m_void(); //no - incompatible target
- SAM_void s3 = ()->m_java_lang_Void(); //no - incompatible target
+ SAM_void s3 = ()->m_java_lang_Void(); //ok - expression statement lambda is compatible with void
SAM_java_lang_Void s4 = ()->m_java_lang_Void(); //ok
}
--- a/langtools/test/tools/javac/lambda/LambdaConv21.out Thu Nov 29 09:41:48 2012 +0000
+++ b/langtools/test/tools/javac/lambda/LambdaConv21.out Fri Nov 30 15:14:12 2012 +0000
@@ -1,6 +1,5 @@
LambdaConv21.java:25:43: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: void, java.lang.Void))
-LambdaConv21.java:26:43: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: java.lang.Void, void))
LambdaConv21.java:32:33: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.missing.ret.val: java.lang.Void))
LambdaConv21.java:33:53: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.unexpected.ret.val))
LambdaConv21.java:36:33: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.missing.ret.val: java.lang.Void))
-5 errors
+4 errors
--- a/langtools/test/tools/javac/lambda/VoidCompatibility.out Thu Nov 29 09:41:48 2012 +0000
+++ b/langtools/test/tools/javac/lambda/VoidCompatibility.out Fri Nov 30 15:14:12 2012 +0000
@@ -1,2 +1,3 @@
+VoidCompatibility.java:17:9: compiler.err.ref.ambiguous: schedule, kindname.method, schedule(VoidCompatibility.Runnable), VoidCompatibility, kindname.method, schedule(VoidCompatibility.Thunk<?>), VoidCompatibility
VoidCompatibility.java:23:9: compiler.err.ref.ambiguous: schedule, kindname.method, schedule(VoidCompatibility.Runnable), VoidCompatibility, kindname.method, schedule(VoidCompatibility.Thunk<?>), VoidCompatibility
-1 error
+2 errors