Fri, 30 Nov 2012 15:14:12 +0000
8004105: Expression statement lambdas should be void-compatible
Summary: Fix lambda compatibility rules as per latest EDR
Reviewed-by: jjg
1.1 --- a/src/share/classes/com/sun/tools/javac/comp/Attr.java Thu Nov 29 09:41:48 2012 +0000 1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java Fri Nov 30 15:14:12 2012 +0000 1.3 @@ -2244,9 +2244,13 @@ 1.4 //with the target-type, it will be recovered anyway in Attr.checkId 1.5 needsRecovery = false; 1.6 1.7 + FunctionalReturnContext funcContext = that.getBodyKind() == JCLambda.BodyKind.EXPRESSION ? 1.8 + new ExpressionLambdaReturnContext((JCExpression)that.getBody(), resultInfo.checkContext) : 1.9 + new FunctionalReturnContext(resultInfo.checkContext); 1.10 + 1.11 ResultInfo bodyResultInfo = lambdaType.getReturnType() == Type.recoveryType ? 1.12 recoveryInfo : 1.13 - new ResultInfo(VAL, lambdaType.getReturnType(), new LambdaReturnContext(resultInfo.checkContext)); 1.14 + new ResultInfo(VAL, lambdaType.getReturnType(), funcContext); 1.15 localEnv.info.returnResult = bodyResultInfo; 1.16 1.17 if (that.getBodyKind() == JCLambda.BodyKind.EXPRESSION) { 1.18 @@ -2327,8 +2331,9 @@ 1.19 * type according to both the inherited context and the assignment 1.20 * context. 1.21 */ 1.22 - class LambdaReturnContext extends Check.NestedCheckContext { 1.23 - public LambdaReturnContext(CheckContext enclosingContext) { 1.24 + class FunctionalReturnContext extends Check.NestedCheckContext { 1.25 + 1.26 + FunctionalReturnContext(CheckContext enclosingContext) { 1.27 super(enclosingContext); 1.28 } 1.29 1.30 @@ -2344,6 +2349,23 @@ 1.31 } 1.32 } 1.33 1.34 + class ExpressionLambdaReturnContext extends FunctionalReturnContext { 1.35 + 1.36 + JCExpression expr; 1.37 + 1.38 + ExpressionLambdaReturnContext(JCExpression expr, CheckContext enclosingContext) { 1.39 + super(enclosingContext); 1.40 + this.expr = expr; 1.41 + } 1.42 + 1.43 + @Override 1.44 + public boolean compatible(Type found, Type req, Warner warn) { 1.45 + //a void return is compatible with an expression statement lambda 1.46 + return TreeInfo.isExpressionStatement(expr) && req.hasTag(VOID) || 1.47 + super.compatible(found, req, warn); 1.48 + } 1.49 + } 1.50 + 1.51 /** 1.52 * Lambda compatibility. Check that given return types, thrown types, parameter types 1.53 * are compatible with the expected functional interface descriptor. This means that: 1.54 @@ -2560,7 +2582,7 @@ 1.55 1.56 if (!returnType.hasTag(VOID) && !resType.hasTag(VOID)) { 1.57 if (resType.isErroneous() || 1.58 - new LambdaReturnContext(checkContext).compatible(resType, returnType, types.noWarnings)) { 1.59 + new FunctionalReturnContext(checkContext).compatible(resType, returnType, types.noWarnings)) { 1.60 incompatibleReturnType = null; 1.61 } 1.62 }
2.1 --- a/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Thu Nov 29 09:41:48 2012 +0000 2.2 +++ b/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Fri Nov 30 15:14:12 2012 +0000 2.3 @@ -3171,21 +3171,12 @@ 2.4 /** Check that given tree is a legal expression statement. 2.5 */ 2.6 protected JCExpression checkExprStat(JCExpression t) { 2.7 - switch(t.getTag()) { 2.8 - case PREINC: case PREDEC: 2.9 - case POSTINC: case POSTDEC: 2.10 - case ASSIGN: 2.11 - case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG: 2.12 - case SL_ASG: case SR_ASG: case USR_ASG: 2.13 - case PLUS_ASG: case MINUS_ASG: 2.14 - case MUL_ASG: case DIV_ASG: case MOD_ASG: 2.15 - case APPLY: case NEWCLASS: 2.16 - case ERRONEOUS: 2.17 - return t; 2.18 - default: 2.19 + if (!TreeInfo.isExpressionStatement(t)) { 2.20 JCExpression ret = F.at(t.pos).Erroneous(List.<JCTree>of(t)); 2.21 error(ret, "not.stmt"); 2.22 return ret; 2.23 + } else { 2.24 + return t; 2.25 } 2.26 } 2.27
3.1 --- a/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java Thu Nov 29 09:41:48 2012 +0000 3.2 +++ b/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java Fri Nov 30 15:14:12 2012 +0000 3.3 @@ -267,6 +267,25 @@ 3.4 return lambda.params.isEmpty() || 3.5 lambda.params.head.vartype != null; 3.6 } 3.7 + 3.8 + /** Return true if the tree corresponds to an expression statement */ 3.9 + public static boolean isExpressionStatement(JCExpression tree) { 3.10 + switch(tree.getTag()) { 3.11 + case PREINC: case PREDEC: 3.12 + case POSTINC: case POSTDEC: 3.13 + case ASSIGN: 3.14 + case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG: 3.15 + case SL_ASG: case SR_ASG: case USR_ASG: 3.16 + case PLUS_ASG: case MINUS_ASG: 3.17 + case MUL_ASG: case DIV_ASG: case MOD_ASG: 3.18 + case APPLY: case NEWCLASS: 3.19 + case ERRONEOUS: 3.20 + return true; 3.21 + default: 3.22 + return false; 3.23 + } 3.24 + } 3.25 + 3.26 /** 3.27 * Return true if the AST corresponds to a static select of the kind A.B 3.28 */
4.1 --- a/test/tools/javac/lambda/LambdaConv21.java Thu Nov 29 09:41:48 2012 +0000 4.2 +++ b/test/tools/javac/lambda/LambdaConv21.java Fri Nov 30 15:14:12 2012 +0000 4.3 @@ -23,7 +23,7 @@ 4.4 static void testExpressionLambda() { 4.5 SAM_void s1 = ()->m_void(); //ok 4.6 SAM_java_lang_Void s2 = ()->m_void(); //no - incompatible target 4.7 - SAM_void s3 = ()->m_java_lang_Void(); //no - incompatible target 4.8 + SAM_void s3 = ()->m_java_lang_Void(); //ok - expression statement lambda is compatible with void 4.9 SAM_java_lang_Void s4 = ()->m_java_lang_Void(); //ok 4.10 } 4.11
5.1 --- a/test/tools/javac/lambda/LambdaConv21.out Thu Nov 29 09:41:48 2012 +0000 5.2 +++ b/test/tools/javac/lambda/LambdaConv21.out Fri Nov 30 15:14:12 2012 +0000 5.3 @@ -1,6 +1,5 @@ 5.4 LambdaConv21.java:25:43: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: void, java.lang.Void)) 5.5 -LambdaConv21.java:26:43: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: java.lang.Void, void)) 5.6 LambdaConv21.java:32:33: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.missing.ret.val: java.lang.Void)) 5.7 LambdaConv21.java:33:53: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.unexpected.ret.val)) 5.8 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.9 -5 errors 5.10 +4 errors
6.1 --- a/test/tools/javac/lambda/VoidCompatibility.out Thu Nov 29 09:41:48 2012 +0000 6.2 +++ b/test/tools/javac/lambda/VoidCompatibility.out Fri Nov 30 15:14:12 2012 +0000 6.3 @@ -1,2 +1,3 @@ 6.4 +VoidCompatibility.java:17:9: compiler.err.ref.ambiguous: schedule, kindname.method, schedule(VoidCompatibility.Runnable), VoidCompatibility, kindname.method, schedule(VoidCompatibility.Thunk<?>), VoidCompatibility 6.5 VoidCompatibility.java:23:9: compiler.err.ref.ambiguous: schedule, kindname.method, schedule(VoidCompatibility.Runnable), VoidCompatibility, kindname.method, schedule(VoidCompatibility.Thunk<?>), VoidCompatibility 6.6 -1 error 6.7 +2 errors