提交 ac35075b 编写于 作者: M mcimadamore

8004105: Expression statement lambdas should be void-compatible

Summary: Fix lambda compatibility rules as per latest EDR
Reviewed-by: jjg
上级 fe8b3c1d
...@@ -2244,9 +2244,13 @@ public class Attr extends JCTree.Visitor { ...@@ -2244,9 +2244,13 @@ public class Attr extends JCTree.Visitor {
//with the target-type, it will be recovered anyway in Attr.checkId //with the target-type, it will be recovered anyway in Attr.checkId
needsRecovery = false; 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 ? ResultInfo bodyResultInfo = lambdaType.getReturnType() == Type.recoveryType ?
recoveryInfo : recoveryInfo :
new ResultInfo(VAL, lambdaType.getReturnType(), new LambdaReturnContext(resultInfo.checkContext)); new ResultInfo(VAL, lambdaType.getReturnType(), funcContext);
localEnv.info.returnResult = bodyResultInfo; localEnv.info.returnResult = bodyResultInfo;
if (that.getBodyKind() == JCLambda.BodyKind.EXPRESSION) { if (that.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
...@@ -2327,8 +2331,9 @@ public class Attr extends JCTree.Visitor { ...@@ -2327,8 +2331,9 @@ public class Attr extends JCTree.Visitor {
* type according to both the inherited context and the assignment * type according to both the inherited context and the assignment
* context. * context.
*/ */
class LambdaReturnContext extends Check.NestedCheckContext { class FunctionalReturnContext extends Check.NestedCheckContext {
public LambdaReturnContext(CheckContext enclosingContext) {
FunctionalReturnContext(CheckContext enclosingContext) {
super(enclosingContext); super(enclosingContext);
} }
...@@ -2344,6 +2349,23 @@ public class Attr extends JCTree.Visitor { ...@@ -2344,6 +2349,23 @@ public class Attr extends JCTree.Visitor {
} }
} }
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 * Lambda compatibility. Check that given return types, thrown types, parameter types
* are compatible with the expected functional interface descriptor. This means that: * are compatible with the expected functional interface descriptor. This means that:
...@@ -2560,7 +2582,7 @@ public class Attr extends JCTree.Visitor { ...@@ -2560,7 +2582,7 @@ public class Attr extends JCTree.Visitor {
if (!returnType.hasTag(VOID) && !resType.hasTag(VOID)) { if (!returnType.hasTag(VOID) && !resType.hasTag(VOID)) {
if (resType.isErroneous() || if (resType.isErroneous() ||
new LambdaReturnContext(checkContext).compatible(resType, returnType, types.noWarnings)) { new FunctionalReturnContext(checkContext).compatible(resType, returnType, types.noWarnings)) {
incompatibleReturnType = null; incompatibleReturnType = null;
} }
} }
......
...@@ -3171,21 +3171,12 @@ public class JavacParser implements Parser { ...@@ -3171,21 +3171,12 @@ public class JavacParser implements Parser {
/** Check that given tree is a legal expression statement. /** Check that given tree is a legal expression statement.
*/ */
protected JCExpression checkExprStat(JCExpression t) { protected JCExpression checkExprStat(JCExpression t) {
switch(t.getTag()) { if (!TreeInfo.isExpressionStatement(t)) {
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:
JCExpression ret = F.at(t.pos).Erroneous(List.<JCTree>of(t)); JCExpression ret = F.at(t.pos).Erroneous(List.<JCTree>of(t));
error(ret, "not.stmt"); error(ret, "not.stmt");
return ret; return ret;
} else {
return t;
} }
} }
......
...@@ -267,6 +267,25 @@ public class TreeInfo { ...@@ -267,6 +267,25 @@ public class TreeInfo {
return lambda.params.isEmpty() || return lambda.params.isEmpty() ||
lambda.params.head.vartype != null; 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 * Return true if the AST corresponds to a static select of the kind A.B
*/ */
......
...@@ -23,7 +23,7 @@ class LambdaConv21 { ...@@ -23,7 +23,7 @@ class LambdaConv21 {
static void testExpressionLambda() { static void testExpressionLambda() {
SAM_void s1 = ()->m_void(); //ok SAM_void s1 = ()->m_void(); //ok
SAM_java_lang_Void s2 = ()->m_void(); //no - incompatible target 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 SAM_java_lang_Void s4 = ()->m_java_lang_Void(); //ok
} }
......
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: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: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: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)) 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
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 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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册