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

Thu, 15 Aug 2013 22:33:43 +0200

author
jlahoda
date
Thu, 15 Aug 2013 22:33:43 +0200
changeset 1955
ec77c7b46c37
parent 1954
a6378c19836b
child 1956
f657d400c736

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

src/share/classes/com/sun/tools/javac/code/Type.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/comp/Attr.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/comp/Flow.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/resources/compiler.properties file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/tree/JCTree.java file | annotate | diff | comparison | revisions
test/tools/javac/diags/examples/IncompatibleThrownTypesInLambda.java file | annotate | diff | comparison | revisions
test/tools/javac/lambda/ExceptionsInLambda.java file | annotate | diff | comparison | revisions
test/tools/javac/lambda/ExceptionsInLambda.out file | annotate | diff | comparison | revisions
test/tools/javac/lambda/TargetType21.out file | annotate | diff | comparison | revisions
     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

mercurial