提交 16891a92 编写于 作者: J jlahoda

8015809: More user friendly compile-time errors for uncaught exceptions in lambda expression

Summary: Producing individual errors for uncaught undeclared exceptions inside lambda expressions, rather than one error for the whole lambda
Reviewed-by: mcimadamore
上级 1098e2b6
......@@ -1161,7 +1161,7 @@ public abstract class Type implements TypeMirror {
}
public boolean contains(Type elem) {
return elem == this || contains(argtypes, elem) || restype.contains(elem);
return elem == this || contains(argtypes, elem) || restype.contains(elem) || contains(thrown, elem);
}
public MethodType asMethodType() { return this; }
......
......@@ -2607,8 +2607,7 @@ public class Attr extends JCTree.Visitor {
* are compatible with the expected functional interface descriptor. This means that:
* (i) parameter types must be identical to those of the target descriptor; (ii) return
* types must be compatible with the return type of the expected descriptor;
* (iii) thrown types must be 'included' in the thrown types list of the expected
* descriptor.
* (iii) finish inference of thrown types if required.
*/
private void checkLambdaCompatible(JCLambda tree, Type descriptor, CheckContext checkContext, boolean speculativeAttr) {
Type returnType = checkContext.inferenceContext().asFree(descriptor.getReturnType());
......@@ -2630,9 +2629,7 @@ public class Attr extends JCTree.Visitor {
if (!speculativeAttr) {
List<Type> thrownTypes = checkContext.inferenceContext().asFree(descriptor.getThrownTypes());
if (chk.unhandled(tree.inferredThrownTypes == null ? List.<Type>nil() : tree.inferredThrownTypes, thrownTypes).nonEmpty()) {
log.error(tree, "incompatible.thrown.types.in.lambda", tree.inferredThrownTypes);
}
chk.unhandled(tree.inferredThrownTypes == null ? List.<Type>nil() : tree.inferredThrownTypes, thrownTypes);
}
}
......
......@@ -224,7 +224,7 @@ public class Flow {
}
try {
new AliveAnalyzer().analyzeTree(env, that, make);
new FlowAnalyzer().analyzeTree(env, that, make);
new LambdaFlowAnalyzer().analyzeTree(env, that, make);
} finally {
if (!speculative) {
log.popDiagnosticHandler(diagHandler);
......@@ -1259,12 +1259,24 @@ public class Flow {
ListBuffer<FlowPendingExit> prevPending = pendingExits;
try {
pendingExits = ListBuffer.lb();
caught = List.of(syms.throwableType); //inhibit exception checking
caught = tree.getDescriptorType(types).getThrownTypes();
thrown = List.nil();
scan(tree.body);
tree.inferredThrownTypes = thrown;
}
finally {
List<FlowPendingExit> exits = pendingExits.toList();
pendingExits = new ListBuffer<FlowPendingExit>();
while (exits.nonEmpty()) {
FlowPendingExit exit = exits.head;
exits = exits.tail;
if (exit.thrown == null) {
Assert.check(exit.tree.hasTag(RETURN));
} else {
// uncaught throws will be reported later
pendingExits.append(exit);
}
}
errorUncaught();
} finally {
pendingExits = prevPending;
caught = prevCaught;
thrown = prevThrown;
......@@ -1302,6 +1314,33 @@ public class Flow {
}
}
/**
* Specialized pass that performs inference of thrown types for lambdas.
*/
class LambdaFlowAnalyzer extends FlowAnalyzer {
@Override
public void visitLambda(JCLambda tree) {
if (tree.type != null &&
tree.type.isErroneous()) {
return;
}
List<Type> prevCaught = caught;
List<Type> prevThrown = thrown;
ListBuffer<FlowPendingExit> prevPending = pendingExits;
try {
pendingExits = ListBuffer.lb();
caught = List.of(syms.throwableType);
thrown = List.nil();
scan(tree.body);
tree.inferredThrownTypes = thrown;
} finally {
pendingExits = prevPending;
caught = prevCaught;
thrown = prevThrown;
}
}
}
/**
* This pass implements (i) definite assignment analysis, which ensures that
* each variable is assigned when used and (ii) definite unassignment analysis,
......
......@@ -732,10 +732,6 @@ compiler.misc.incompatible.ret.type.in.mref=\
bad return type in method reference\n\
{0}
# 0: list of type
compiler.err.incompatible.thrown.types.in.lambda=\
incompatible thrown types {0} in lambda expression
# 0: list of type
compiler.err.incompatible.thrown.types.in.mref=\
incompatible thrown types {0} in method reference
......
......@@ -645,7 +645,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
public List<Type> targets;
public Type getDescriptorType(Types types) {
return types.findDescriptorType(targets.head);
return targets.nonEmpty() ? types.findDescriptorType(targets.head) : types.createErrorType(null);
}
}
......
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 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
......@@ -21,12 +21,41 @@
* questions.
*/
// key: compiler.err.incompatible.thrown.types.in.lambda
/*
* @test
* @bug 8015809
* @summary Producing individual errors for uncaught undeclared exceptions inside lambda expressions, instead of one error for whole lambda
* @compile/fail/ref=ExceptionsInLambda.out -XDrawDiagnostics ExceptionsInLambda.java
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.InputStream;
import java.io.Reader;
public class ExceptionsInLambda {
public static void main(Runnable p, File f) {
main(() -> {
StringBuilder sb = new StringBuilder();
class IncompatibleThrownTypesInLambda {
interface SAM {
void m();
Reader in = new FileReader(f);
int r;
while ((r = in.read()) != (-1)) {
sb.append((char) r);
}
}, f);
doOpen(() -> new FileInputStream(f));
}
SAM s = ()-> { throw new Exception(); };
public static InputStream doOpen(Open open) {
return open.open();
}
public interface Open {
public InputStream open();
}
}
ExceptionsInLambda.java:43:25: compiler.err.unreported.exception.need.to.catch.or.throw: java.io.FileNotFoundException
ExceptionsInLambda.java:46:32: compiler.err.unreported.exception.need.to.catch.or.throw: java.io.IOException
ExceptionsInLambda.java:51:22: compiler.err.unreported.exception.need.to.catch.or.throw: java.io.FileNotFoundException
3 errors
TargetType21.java:28:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM2), TargetType21, kindname.method, <R,A>call(TargetType21.SAM3<R,A>), TargetType21
TargetType21.java:28:14: compiler.err.incompatible.thrown.types.in.lambda: java.lang.Exception
TargetType21.java:29:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM2), TargetType21, kindname.method, <R,A>call(TargetType21.SAM3<R,A>), TargetType21
TargetType21.java:30:13: compiler.err.prob.found.req: (compiler.misc.cyclic.inference: A)
TargetType21.java:31:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM1), TargetType21, kindname.method, <R,A>call(TargetType21.SAM3<R,A>), TargetType21
5 errors
4 errors
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册