8004105: Expression statement lambdas should be void-compatible

Fri, 30 Nov 2012 15:14:12 +0000

author
mcimadamore
date
Fri, 30 Nov 2012 15:14:12 +0000
changeset 1433
4f9853659bf1
parent 1432
969c96b980b7
child 1434
34d1ebaf4645

8004105: Expression statement lambdas should be void-compatible
Summary: Fix lambda compatibility rules as per latest EDR
Reviewed-by: jjg

src/share/classes/com/sun/tools/javac/comp/Attr.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/parser/JavacParser.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/tree/TreeInfo.java file | annotate | diff | comparison | revisions
test/tools/javac/lambda/LambdaConv21.java file | annotate | diff | comparison | revisions
test/tools/javac/lambda/LambdaConv21.out file | annotate | diff | comparison | revisions
test/tools/javac/lambda/VoidCompatibility.out file | annotate | diff | comparison | revisions
     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

mercurial