Mercurial > hg > openjdk > jdk8 > langtools
changeset 1954:ec77c7b46c37
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
author | jlahoda |
---|---|
date | Thu, 15 Aug 2013 22:33:43 +0200 |
parents | a6378c19836b |
children | f657d400c736 |
files | src/share/classes/com/sun/tools/javac/code/Type.java src/share/classes/com/sun/tools/javac/comp/Attr.java src/share/classes/com/sun/tools/javac/comp/Flow.java src/share/classes/com/sun/tools/javac/resources/compiler.properties src/share/classes/com/sun/tools/javac/tree/JCTree.java test/tools/javac/diags/examples/IncompatibleThrownTypesInLambda.java test/tools/javac/lambda/ExceptionsInLambda.java test/tools/javac/lambda/ExceptionsInLambda.out test/tools/javac/lambda/TargetType21.out |
diffstat | 9 files changed, 114 insertions(+), 50 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/code/Type.java Fri Aug 16 10:32:42 2013 +0100 +++ b/src/share/classes/com/sun/tools/javac/code/Type.java Thu Aug 15 22:33:43 2013 +0200 @@ -1161,7 +1161,7 @@ } 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; }
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java Fri Aug 16 10:32:42 2013 +0100 +++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java Thu Aug 15 22:33:43 2013 +0200 @@ -2607,8 +2607,7 @@ * 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 @@ 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); } }
--- a/src/share/classes/com/sun/tools/javac/comp/Flow.java Fri Aug 16 10:32:42 2013 +0100 +++ b/src/share/classes/com/sun/tools/javac/comp/Flow.java Thu Aug 15 22:33:43 2013 +0200 @@ -224,7 +224,7 @@ } 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 @@ 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; @@ -1303,6 +1315,33 @@ } /** + * 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, * which ensures that no final variable is assigned more than once. This visitor
--- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Aug 16 10:32:42 2013 +0100 +++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties Thu Aug 15 22:33:43 2013 +0200 @@ -733,10 +733,6 @@ {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
--- a/src/share/classes/com/sun/tools/javac/tree/JCTree.java Fri Aug 16 10:32:42 2013 +0100 +++ b/src/share/classes/com/sun/tools/javac/tree/JCTree.java Thu Aug 15 22:33:43 2013 +0200 @@ -645,7 +645,7 @@ public List<Type> targets; public Type getDescriptorType(Types types) { - return types.findDescriptorType(targets.head); + return targets.nonEmpty() ? types.findDescriptorType(targets.head) : types.createErrorType(null); } }
--- a/test/tools/javac/diags/examples/IncompatibleThrownTypesInLambda.java Fri Aug 16 10:32:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2012, 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -// key: compiler.err.incompatible.thrown.types.in.lambda - -class IncompatibleThrownTypesInLambda { - interface SAM { - void m(); - } - - SAM s = ()-> { throw new Exception(); }; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/lambda/ExceptionsInLambda.java Thu Aug 15 22:33:43 2013 +0200 @@ -0,0 +1,61 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @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(); + + Reader in = new FileReader(f); + int r; + + while ((r = in.read()) != (-1)) { + sb.append((char) r); + } + }, f); + + doOpen(() -> new FileInputStream(f)); + } + + public static InputStream doOpen(Open open) { + return open.open(); + } + + public interface Open { + public InputStream open(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/lambda/ExceptionsInLambda.out Thu Aug 15 22:33:43 2013 +0200 @@ -0,0 +1,4 @@ +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
--- a/test/tools/javac/lambda/TargetType21.out Fri Aug 16 10:32:42 2013 +0100 +++ b/test/tools/javac/lambda/TargetType21.out Thu Aug 15 22:33:43 2013 +0200 @@ -1,6 +1,5 @@ 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