Thu, 15 Aug 2013 22:33:43 +0200
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
1.1 --- a/src/share/classes/com/sun/tools/javac/code/Type.java Fri Aug 16 10:32:42 2013 +0100 1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Type.java Thu Aug 15 22:33:43 2013 +0200 1.3 @@ -1161,7 +1161,7 @@ 1.4 } 1.5 1.6 public boolean contains(Type elem) { 1.7 - return elem == this || contains(argtypes, elem) || restype.contains(elem); 1.8 + return elem == this || contains(argtypes, elem) || restype.contains(elem) || contains(thrown, elem); 1.9 } 1.10 1.11 public MethodType asMethodType() { return this; }
2.1 --- a/src/share/classes/com/sun/tools/javac/comp/Attr.java Fri Aug 16 10:32:42 2013 +0100 2.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java Thu Aug 15 22:33:43 2013 +0200 2.3 @@ -2607,8 +2607,7 @@ 2.4 * are compatible with the expected functional interface descriptor. This means that: 2.5 * (i) parameter types must be identical to those of the target descriptor; (ii) return 2.6 * types must be compatible with the return type of the expected descriptor; 2.7 - * (iii) thrown types must be 'included' in the thrown types list of the expected 2.8 - * descriptor. 2.9 + * (iii) finish inference of thrown types if required. 2.10 */ 2.11 private void checkLambdaCompatible(JCLambda tree, Type descriptor, CheckContext checkContext, boolean speculativeAttr) { 2.12 Type returnType = checkContext.inferenceContext().asFree(descriptor.getReturnType()); 2.13 @@ -2630,9 +2629,7 @@ 2.14 2.15 if (!speculativeAttr) { 2.16 List<Type> thrownTypes = checkContext.inferenceContext().asFree(descriptor.getThrownTypes()); 2.17 - if (chk.unhandled(tree.inferredThrownTypes == null ? List.<Type>nil() : tree.inferredThrownTypes, thrownTypes).nonEmpty()) { 2.18 - log.error(tree, "incompatible.thrown.types.in.lambda", tree.inferredThrownTypes); 2.19 - } 2.20 + chk.unhandled(tree.inferredThrownTypes == null ? List.<Type>nil() : tree.inferredThrownTypes, thrownTypes); 2.21 } 2.22 } 2.23
3.1 --- a/src/share/classes/com/sun/tools/javac/comp/Flow.java Fri Aug 16 10:32:42 2013 +0100 3.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Flow.java Thu Aug 15 22:33:43 2013 +0200 3.3 @@ -224,7 +224,7 @@ 3.4 } 3.5 try { 3.6 new AliveAnalyzer().analyzeTree(env, that, make); 3.7 - new FlowAnalyzer().analyzeTree(env, that, make); 3.8 + new LambdaFlowAnalyzer().analyzeTree(env, that, make); 3.9 } finally { 3.10 if (!speculative) { 3.11 log.popDiagnosticHandler(diagHandler); 3.12 @@ -1259,12 +1259,24 @@ 3.13 ListBuffer<FlowPendingExit> prevPending = pendingExits; 3.14 try { 3.15 pendingExits = ListBuffer.lb(); 3.16 - caught = List.of(syms.throwableType); //inhibit exception checking 3.17 + caught = tree.getDescriptorType(types).getThrownTypes(); 3.18 thrown = List.nil(); 3.19 scan(tree.body); 3.20 - tree.inferredThrownTypes = thrown; 3.21 - } 3.22 - finally { 3.23 + List<FlowPendingExit> exits = pendingExits.toList(); 3.24 + pendingExits = new ListBuffer<FlowPendingExit>(); 3.25 + while (exits.nonEmpty()) { 3.26 + FlowPendingExit exit = exits.head; 3.27 + exits = exits.tail; 3.28 + if (exit.thrown == null) { 3.29 + Assert.check(exit.tree.hasTag(RETURN)); 3.30 + } else { 3.31 + // uncaught throws will be reported later 3.32 + pendingExits.append(exit); 3.33 + } 3.34 + } 3.35 + 3.36 + errorUncaught(); 3.37 + } finally { 3.38 pendingExits = prevPending; 3.39 caught = prevCaught; 3.40 thrown = prevThrown; 3.41 @@ -1303,6 +1315,33 @@ 3.42 } 3.43 3.44 /** 3.45 + * Specialized pass that performs inference of thrown types for lambdas. 3.46 + */ 3.47 + class LambdaFlowAnalyzer extends FlowAnalyzer { 3.48 + @Override 3.49 + public void visitLambda(JCLambda tree) { 3.50 + if (tree.type != null && 3.51 + tree.type.isErroneous()) { 3.52 + return; 3.53 + } 3.54 + List<Type> prevCaught = caught; 3.55 + List<Type> prevThrown = thrown; 3.56 + ListBuffer<FlowPendingExit> prevPending = pendingExits; 3.57 + try { 3.58 + pendingExits = ListBuffer.lb(); 3.59 + caught = List.of(syms.throwableType); 3.60 + thrown = List.nil(); 3.61 + scan(tree.body); 3.62 + tree.inferredThrownTypes = thrown; 3.63 + } finally { 3.64 + pendingExits = prevPending; 3.65 + caught = prevCaught; 3.66 + thrown = prevThrown; 3.67 + } 3.68 + } 3.69 + } 3.70 + 3.71 + /** 3.72 * This pass implements (i) definite assignment analysis, which ensures that 3.73 * each variable is assigned when used and (ii) definite unassignment analysis, 3.74 * which ensures that no final variable is assigned more than once. This visitor
4.1 --- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Aug 16 10:32:42 2013 +0100 4.2 +++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties Thu Aug 15 22:33:43 2013 +0200 4.3 @@ -733,10 +733,6 @@ 4.4 {0} 4.5 4.6 # 0: list of type 4.7 -compiler.err.incompatible.thrown.types.in.lambda=\ 4.8 - incompatible thrown types {0} in lambda expression 4.9 - 4.10 -# 0: list of type 4.11 compiler.err.incompatible.thrown.types.in.mref=\ 4.12 incompatible thrown types {0} in method reference 4.13
5.1 --- a/src/share/classes/com/sun/tools/javac/tree/JCTree.java Fri Aug 16 10:32:42 2013 +0100 5.2 +++ b/src/share/classes/com/sun/tools/javac/tree/JCTree.java Thu Aug 15 22:33:43 2013 +0200 5.3 @@ -645,7 +645,7 @@ 5.4 public List<Type> targets; 5.5 5.6 public Type getDescriptorType(Types types) { 5.7 - return types.findDescriptorType(targets.head); 5.8 + return targets.nonEmpty() ? types.findDescriptorType(targets.head) : types.createErrorType(null); 5.9 } 5.10 } 5.11
6.1 --- a/test/tools/javac/diags/examples/IncompatibleThrownTypesInLambda.java Fri Aug 16 10:32:42 2013 +0100 6.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 6.3 @@ -1,32 +0,0 @@ 6.4 -/* 6.5 - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 6.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6.7 - * 6.8 - * This code is free software; you can redistribute it and/or modify it 6.9 - * under the terms of the GNU General Public License version 2 only, as 6.10 - * published by the Free Software Foundation. 6.11 - * 6.12 - * This code is distributed in the hope that it will be useful, but WITHOUT 6.13 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 6.14 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 6.15 - * version 2 for more details (a copy is included in the LICENSE file that 6.16 - * accompanied this code). 6.17 - * 6.18 - * You should have received a copy of the GNU General Public License version 6.19 - * 2 along with this work; if not, write to the Free Software Foundation, 6.20 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 6.21 - * 6.22 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 6.23 - * or visit www.oracle.com if you need additional information or have any 6.24 - * questions. 6.25 - */ 6.26 - 6.27 -// key: compiler.err.incompatible.thrown.types.in.lambda 6.28 - 6.29 -class IncompatibleThrownTypesInLambda { 6.30 - interface SAM { 6.31 - void m(); 6.32 - } 6.33 - 6.34 - SAM s = ()-> { throw new Exception(); }; 6.35 -}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/test/tools/javac/lambda/ExceptionsInLambda.java Thu Aug 15 22:33:43 2013 +0200 7.3 @@ -0,0 +1,61 @@ 7.4 +/* 7.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 7.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 7.7 + * 7.8 + * This code is free software; you can redistribute it and/or modify it 7.9 + * under the terms of the GNU General Public License version 2 only, as 7.10 + * published by the Free Software Foundation. 7.11 + * 7.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 7.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 7.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 7.15 + * version 2 for more details (a copy is included in the LICENSE file that 7.16 + * accompanied this code). 7.17 + * 7.18 + * You should have received a copy of the GNU General Public License version 7.19 + * 2 along with this work; if not, write to the Free Software Foundation, 7.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 7.21 + * 7.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 7.23 + * or visit www.oracle.com if you need additional information or have any 7.24 + * questions. 7.25 + */ 7.26 + 7.27 +/* 7.28 + * @test 7.29 + * @bug 8015809 7.30 + * @summary Producing individual errors for uncaught undeclared exceptions inside lambda expressions, instead of one error for whole lambda 7.31 + * @compile/fail/ref=ExceptionsInLambda.out -XDrawDiagnostics ExceptionsInLambda.java 7.32 + */ 7.33 + 7.34 +import java.io.File; 7.35 +import java.io.FileInputStream; 7.36 +import java.io.FileReader; 7.37 +import java.io.InputStream; 7.38 +import java.io.Reader; 7.39 + 7.40 +public class ExceptionsInLambda { 7.41 + 7.42 + public static void main(Runnable p, File f) { 7.43 + main(() -> { 7.44 + StringBuilder sb = new StringBuilder(); 7.45 + 7.46 + Reader in = new FileReader(f); 7.47 + int r; 7.48 + 7.49 + while ((r = in.read()) != (-1)) { 7.50 + sb.append((char) r); 7.51 + } 7.52 + }, f); 7.53 + 7.54 + doOpen(() -> new FileInputStream(f)); 7.55 + } 7.56 + 7.57 + public static InputStream doOpen(Open open) { 7.58 + return open.open(); 7.59 + } 7.60 + 7.61 + public interface Open { 7.62 + public InputStream open(); 7.63 + } 7.64 +}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/test/tools/javac/lambda/ExceptionsInLambda.out Thu Aug 15 22:33:43 2013 +0200 8.3 @@ -0,0 +1,4 @@ 8.4 +ExceptionsInLambda.java:43:25: compiler.err.unreported.exception.need.to.catch.or.throw: java.io.FileNotFoundException 8.5 +ExceptionsInLambda.java:46:32: compiler.err.unreported.exception.need.to.catch.or.throw: java.io.IOException 8.6 +ExceptionsInLambda.java:51:22: compiler.err.unreported.exception.need.to.catch.or.throw: java.io.FileNotFoundException 8.7 +3 errors
9.1 --- a/test/tools/javac/lambda/TargetType21.out Fri Aug 16 10:32:42 2013 +0100 9.2 +++ b/test/tools/javac/lambda/TargetType21.out Thu Aug 15 22:33:43 2013 +0200 9.3 @@ -1,6 +1,5 @@ 9.4 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 9.5 -TargetType21.java:28:14: compiler.err.incompatible.thrown.types.in.lambda: java.lang.Exception 9.6 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 9.7 TargetType21.java:30:13: compiler.err.prob.found.req: (compiler.misc.cyclic.inference: A) 9.8 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 9.9 -5 errors 9.10 +4 errors