Exception transparency - lone throws (no checked exceptions)

Stephen Colebourne scolebourne at joda.org
Wed Jun 16 20:08:39 PDT 2010


For completeness, I spent a couple of hours tonight implementing
lone-throws and catch-throws. It was pretty easy. The patch is below.

(This patch is based on an old version of the JDK, originally based on
the FCM branch of Kijaro. Applying it to the current head will almost
certainly fail)

Stephen
http://www.jroller.com/scolebourne/entry/exception_transparency_and_lone_throws

Index: langtools/src/share/classes/com/sun/source/tree/CatchTree.java
===================================================================
--- .	(revision 109)
+++ .	(working copy)
@@ -43,4 +43,5 @@
 public interface CatchTree extends Tree {
     VariableTree getParameter();
     BlockTree getBlock();
+    boolean getCatchThrows();  // LONE-THROWS
 }
Index: langtools/src/share/classes/com/sun/source/tree/MethodTree.java
===================================================================
--- .	(revision 109)
+++ .	(working copy)
@@ -54,6 +54,7 @@
     List<? extends TypeParameterTree> getTypeParameters();
     List<? extends VariableTree> getParameters();
     List<? extends ExpressionTree> getThrows();
+    boolean getThrowAny();  // LONE-THROWS
     BlockTree getBody();
     Tree getDefaultValue(); // for annotation types
 }
Index: langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java
===================================================================
--- .	(revision 131)
+++ .	(working copy)
@@ -657,7 +657,12 @@
             for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
                 if (l.head.getTag() == JCTree.METHODDEF) {
                     scan(l.head);
-                    errorUncaught();
+                    if (!((JCMethodDecl) l.head).throwAny) {  // LONE-THROWS
+                        errorUncaught();
+                    } else {
+                        pendingExits = ListBuffer.lb();
+                        System.out.println("Checked to Unchecked");
+                    }
                 }
             }

@@ -793,6 +798,8 @@
                     pendingExits.append(exit);
                 }
             }
+            errorUncaught();
+
         } finally {
             classDef = classDefPrev;
             thrown = thrownPrev;
@@ -1045,6 +1052,7 @@
                 log.error(l.head.pos(),
                           "except.already.caught", exc);
             } else if (!chk.isUnchecked(l.head.pos(), exc) &&
+                       !l.head.catchThrows &&  // LONE-THROWS
                        exc.tsym != syms.throwableType.tsym &&
                        exc.tsym != syms.exceptionType.tsym &&
                        !chk.intersects(exc, thrownInTry)) {
Index: langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java
===================================================================
--- .	(revision 141)
+++ .	(working copy)
@@ -442,7 +442,7 @@

syms.noSuchFieldErrorType,
                                                               syms.noSymbol),
                                                 null),
-                                    make.Block(0, List.<JCStatement>nil())));
+                                    make.Block(0,
List.<JCStatement>nil()), false));  // LONE-THROWS
             for (Map.Entry<VarSymbol,Integer> e : values.entrySet()) {
                 VarSymbol enumerator = e.getKey();
                 Integer mappedValue = e.getValue();
@@ -1644,7 +1644,7 @@

         // catchBlock := "catch ($catchParam) $rethrowStmt"
         JCCatch catchBlock = make.Catch(make.VarDef(catchParam, null),
-                                      rethrowStmt);
+                                      rethrowStmt, false);  // LONE-THROWS

         // tryCatch := "try $returnResult $catchBlock"
         JCStatement tryCatch = make.Try(returnResult,
Index: langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java
===================================================================
--- .	(revision 115)
+++ .	(working copy)
@@ -436,6 +436,7 @@
                       List.<JCTypeParameter>nil(),
                       List.<JCVariableDecl>nil(),
                       List.<JCExpression>nil(), // thrown
+                      false,  // LONE-THROWS
                       null, //make.Block(0,
Tree.emptyList.prepend(make.Return(make.Ident(names._null)))),
                       null);
         memberEnter(values, env);
@@ -450,6 +451,7 @@
                                             names.fromString("name"),
                                             make.Type(syms.stringType), null)),
                       List.<JCExpression>nil(), // thrown
+                      false,  // LONE-THROWS
                       null, //make.Block(0,
Tree.emptyList.prepend(make.Return(make.Ident(names._null)))),
                       null);
         memberEnter(valueOf, env);
@@ -465,6 +467,7 @@
                       List.<JCTypeParameter>nil(),
                       List.<JCVariableDecl>nil(),
                       List.<JCExpression>nil(),
+                      false,  // LONE-THROWS
                       null,
                       null);
         memberEnter(ordinal, env);
@@ -477,6 +480,7 @@
                       List.<JCTypeParameter>nil(),
                       List.<JCVariableDecl>nil(),
                       List.<JCExpression>nil(),
+                      false,  // LONE-THROWS
                       null,
                       null);
         memberEnter(name, env);
@@ -1070,6 +1074,7 @@
             make.TypeParams(typarams),
             params,
             make.Types(thrown),
+            false,  // LONE-THROWS
             make.Block(0, stats),
             null);
         return result;
Index: langtools/src/share/classes/com/sun/tools/javac/parser/Parser.java
===================================================================
--- .	(revision 131)
+++ .	(working copy)
@@ -1933,6 +1933,12 @@
     JCCatch catchClause() {
         int pos = S.pos();
         accept(CATCH);
+        boolean catchThrows = false;
+        if (S.token() == THROWS) {
+            catchThrows = true;
+            accept(THROWS);
+            System.out.println("Found catch throws");
+        }
         accept(LPAREN);
         JCVariableDecl formal =
             variableDeclaratorId(optFinal(Flags.PARAMETER),
qualident(), false);  // FCM-MREF
@@ -1938,7 +1944,7 @@
             variableDeclaratorId(optFinal(Flags.PARAMETER),
qualident(), false);  // FCM-MREF
         accept(RPAREN);
         JCBlock body = block();
-        return F.at(pos).Catch(formal, body);
+        return F.at(pos).Catch(formal, body, catchThrows);  // LONE-THROWS
     }

     /** SwitchBlockStatementGroups = { SwitchBlockStatementGroup }
@@ -2674,7 +2680,7 @@
                         pos = S.pos();
                         List<JCTree> err = isVoid
                             ?
List.<JCTree>of(toP(F.at(pos).MethodDef(mods, name, type, typarams,
-                                List.<JCVariableDecl>nil(),
List.<JCExpression>nil(), null, null)))
+                                List.<JCVariableDecl>nil(),
List.<JCExpression>nil(), false, null, null)))  // LONE-THROWS
                             : null;
                         return List.<JCTree>of(syntaxError(S.pos(),
err, "expected", keywords.token2string(LPAREN)));
                     }
@@ -2709,9 +2715,15 @@

         // throws clause
         List<JCExpression> thrown = List.nil();
+        boolean throwAny = false;
         if (S.token() == THROWS) {
             S.nextToken();
-            thrown = qualidentList();
+            if (S.token() == LBRACE) {
+                System.out.println("Found lone-throws");
+                throwAny = true;
+            } else {
+                thrown = qualidentList();
+            }
         }

         // main body
@@ -2740,7 +2752,7 @@
         }
         JCMethodDecl result =
             toP(F.at(pos).MethodDef(mods, name, type, typarams,
-                                    params, thrown,
+                                    params, thrown, throwAny,
                                     body, defaultValue));
         attach(result, dc);
         return result;
Index: langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java
===================================================================
--- .	(revision 141)
+++ .	(working copy)
@@ -649,6 +649,7 @@
         public List<JCTypeParameter> typarams;
         public List<JCVariableDecl> params;
         public List<JCExpression> thrown;
+        public boolean throwAny;  // LONE-THROWS
         public JCBlock body;
         public JCExpression defaultValue; // for annotation types
         public MethodSymbol sym;
@@ -658,6 +659,7 @@
                             List<JCTypeParameter> typarams,
                             List<JCVariableDecl> params,
                             List<JCExpression> thrown,
+                            boolean throwAny,  // LONE-THROWS
                             JCBlock body,
                             JCExpression defaultValue,
                             MethodSymbol sym)
@@ -668,6 +670,7 @@
             this.typarams = typarams;
             this.params = params;
             this.thrown = thrown;
+            this.throwAny = throwAny;  // LONE-THROWS
             this.body = body;
             this.defaultValue = defaultValue;
             this.sym = sym;
@@ -688,6 +691,7 @@
         public List<JCExpression> getThrows() {
             return thrown;
         }
+        public boolean getThrowAny() { return throwAny; }
         public JCBlock getBody() { return body; }
         public JCTree getDefaultValue() { // for annotation types
             return defaultValue;
@@ -1067,9 +1071,11 @@
     public static class JCCatch extends JCTree implements CatchTree {
         public JCVariableDecl param;
         public JCBlock body;
-        protected JCCatch(JCVariableDecl param, JCBlock body) {
+        public boolean catchThrows;  // LONE-THROWS
+        protected JCCatch(JCVariableDecl param, JCBlock body, boolean
catchThrows) {
             this.param = param;
             this.body = body;
+            this.catchThrows = catchThrows;  // LONE-THROWS
         }
         @Override
         public void accept(Visitor v) { v.visitCatch(this); }
@@ -1077,6 +1083,7 @@
         public Kind getKind() { return Kind.CATCH; }
         public JCVariableDecl getParameter() { return param; }
         public JCBlock getBlock() { return body; }
+        public boolean getCatchThrows() { return catchThrows; }  // LONE-THROWS
         @Override
         public <R,D> R accept(TreeVisitor<R,D> v, D d) {
             return v.visitCatch(this, d);
@@ -2233,6 +2240,7 @@
                             List<JCTypeParameter> typarams,
                             List<JCVariableDecl> params,
                             List<JCExpression> thrown,
+                            boolean throwAny,  // LONE-THROWS
                             JCBlock body,
                             JCExpression defaultValue);
         JCVariableDecl VarDef(JCModifiers mods,
@@ -2253,7 +2261,7 @@
         JCCase Case(JCExpression pat, List<JCStatement> stats);
         JCSynchronized Synchronized(JCExpression lock, JCBlock body);
         JCTry Try(JCBlock body, List<JCCatch> catchers, JCBlock finalizer);
-        JCCatch Catch(JCVariableDecl param, JCBlock body);
+        JCCatch Catch(JCVariableDecl param, JCBlock body, boolean catchThrows);
         JCConditional Conditional(JCExpression cond,
                                 JCExpression thenpart,
                                 JCExpression elsepart);
Index: langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java
===================================================================
--- .	(revision 131)
+++ .	(working copy)
@@ -461,7 +461,9 @@
             print(")");
             if (tree.thrown.nonEmpty()) {
                 print(" throws ");
-                printExprs(tree.thrown);
+                if (!tree.throwAny) {
+                    printExprs(tree.thrown);  // LONE-THROWS
+                }
             }
             if (tree.body != null) {
                 print(" ");
@@ -683,7 +685,7 @@

     public void visitCatch(JCCatch tree) {
         try {
-            print(" catch (");
+            print(tree.catchThrows ? " catch throws (" : " catch (");
 // LONE-THROWS
             printExpr(tree.param);
             print(") ");
             printStat(tree.body);
Index: langtools/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java
===================================================================
--- .	(revision 131)
+++ .	(working copy)
@@ -133,7 +133,7 @@
         JCCatch t = (JCCatch) node;
         JCVariableDecl param = copy(t.param, p);
         JCBlock body = copy(t.body, p);
-        return M.at(t.pos).Catch(param, body);
+        return M.at(t.pos).Catch(param, body, t.catchThrows);  // LONE-THROWS
     }

     public JCTree visitClass(ClassTree node, P p) {
@@ -241,7 +241,7 @@
         List<JCExpression> thrown = copy(t.thrown, p);
         JCBlock body = copy(t.body, p);
         JCExpression defaultValue = copy(t.defaultValue, p);
-        return M.at(t.pos).MethodDef(mods, t.name, restype, typarams,
params, thrown, body, defaultValue);
+        return M.at(t.pos).MethodDef(mods, t.name, restype, typarams,
params, thrown, t.throwAny, body, defaultValue);  // LONE-THROWS
     }

     public JCTree visitMethodInvocation(MethodInvocationTree node, P p) {
Index: langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java
===================================================================
--- .	(revision 131)
+++ .	(working copy)
@@ -171,6 +171,7 @@
                                List<JCTypeParameter> typarams,
                                List<JCVariableDecl> params,
                                List<JCExpression> thrown,
+                               boolean throwAny,  // LONE-THROWS
                                JCBlock body,
                                JCExpression defaultValue)
     {
@@ -180,6 +181,7 @@
                                        typarams,
                                        params,
                                        thrown,
+                                       throwAny,  // LONE-THROWS
                                        body,
                                        defaultValue,
                                        null);
@@ -263,8 +265,8 @@
         return tree;
     }

-    public JCCatch Catch(JCVariableDecl param, JCBlock body) {
-        JCCatch tree = new JCCatch(param, body);
+    public JCCatch Catch(JCVariableDecl param, JCBlock body, boolean
catchThrows) {  // LONE-THROWS
+        JCCatch tree = new JCCatch(param, body, catchThrows);
         tree.pos = pos;
         return tree;
     }
@@ -801,6 +803,7 @@
                 TypeParams(mtype.getTypeArguments()),
                 Params(mtype.getParameterTypes(), m),
                 Types(mtype.getThrownTypes()),
+                false,  // LONE-THROWS
                 body,
                 null,
                 m).setPos(pos).setType(mtype);


More information about the lambda-dev mailing list