6943289: Project Coin: Improved Exception Handling for Java (aka 'multicatch')
authormcimadamore
Mon, 03 May 2010 17:12:59 -0700
changeset 5492 515e4b33b335
parent 5491 899e1748bb17
child 5493 d9799ef9198d
child 5647 9a0b03523aa9
6943289: Project Coin: Improved Exception Handling for Java (aka 'multicatch') Reviewed-by: jjg, darcy
langtools/src/share/classes/com/sun/source/tree/DisjointTypeTree.java
langtools/src/share/classes/com/sun/source/tree/Tree.java
langtools/src/share/classes/com/sun/source/tree/TreeVisitor.java
langtools/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java
langtools/src/share/classes/com/sun/source/util/TreeScanner.java
langtools/src/share/classes/com/sun/tools/javac/code/Flags.java
langtools/src/share/classes/com/sun/tools/javac/code/Source.java
langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java
langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java
langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java
langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties
langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java
langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java
langtools/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java
langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java
langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java
langtools/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java
langtools/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java
langtools/test/tools/javac/multicatch/Neg01.java
langtools/test/tools/javac/multicatch/Neg01.out
langtools/test/tools/javac/multicatch/Neg02.java
langtools/test/tools/javac/multicatch/Neg02.out
langtools/test/tools/javac/multicatch/Neg03.java
langtools/test/tools/javac/multicatch/Neg03.out
langtools/test/tools/javac/multicatch/Neg04.java
langtools/test/tools/javac/multicatch/Neg04.out
langtools/test/tools/javac/multicatch/Pos01.java
langtools/test/tools/javac/multicatch/Pos02.java
langtools/test/tools/javac/multicatch/Pos03.java
langtools/test/tools/javac/multicatch/Pos04.java
langtools/test/tools/javac/multicatch/Pos05.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/source/tree/DisjointTypeTree.java	Mon May 03 17:12:59 2010 -0700
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.source.tree;
+
+import java.util.List;
+
+/**
+ * A tree node for a disjoint type expression in a multicatch var declaration.
+ *
+ *
+ * @author Maurizio Cimadamore
+ *
+ * @since 1.7
+ */
+public interface DisjointTypeTree extends Tree {
+    List<? extends Tree> getTypeComponents();
+}
\ No newline at end of file
--- a/langtools/src/share/classes/com/sun/source/tree/Tree.java	Sun May 02 15:55:02 2010 -0700
+++ b/langtools/src/share/classes/com/sun/source/tree/Tree.java	Mon May 03 17:12:59 2010 -0700
@@ -234,6 +234,11 @@
         PARAMETERIZED_TYPE(ParameterizedTypeTree.class),
 
         /**
+         * Used for instances of {@link DisjointTypeTree}.
+         */
+        DISJOINT_TYPE(DisjointTypeTree.class),
+
+        /**
          * Used for instances of {@link TypeCastTree}.
          */
         TYPE_CAST(TypeCastTree.class),
--- a/langtools/src/share/classes/com/sun/source/tree/TreeVisitor.java	Sun May 02 15:55:02 2010 -0700
+++ b/langtools/src/share/classes/com/sun/source/tree/TreeVisitor.java	Mon May 03 17:12:59 2010 -0700
@@ -96,6 +96,7 @@
     R visitCompilationUnit(CompilationUnitTree node, P p);
     R visitTry(TryTree node, P p);
     R visitParameterizedType(ParameterizedTypeTree node, P p);
+    R visitDisjointType(DisjointTypeTree node, P p);
     R visitArrayType(ArrayTypeTree node, P p);
     R visitTypeCast(TypeCastTree node, P p);
     R visitPrimitiveType(PrimitiveTypeTree node, P p);
--- a/langtools/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java	Sun May 02 15:55:02 2010 -0700
+++ b/langtools/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java	Mon May 03 17:12:59 2010 -0700
@@ -228,6 +228,10 @@
         return defaultAction(node, p);
     }
 
+    public R visitDisjointType(DisjointTypeTree node, P p) {
+        return defaultAction(node, p);
+    }
+
     public R visitTypeParameter(TypeParameterTree node, P p) {
         return defaultAction(node, p);
     }
--- a/langtools/src/share/classes/com/sun/source/util/TreeScanner.java	Sun May 02 15:55:02 2010 -0700
+++ b/langtools/src/share/classes/com/sun/source/util/TreeScanner.java	Mon May 03 17:12:59 2010 -0700
@@ -354,6 +354,10 @@
         return r;
     }
 
+    public R visitDisjointType(DisjointTypeTree node, P p) {
+        return scan(node.getTypeComponents(), p);
+    }
+
     public R visitTypeParameter(TypeParameterTree node, P p) {
         R r = scan(node.getAnnotations(), p);
         r = scanAndReduce(node.getBounds(), p, r);
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Flags.java	Sun May 02 15:55:02 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Flags.java	Mon May 03 17:12:59 2010 -0700
@@ -230,6 +230,11 @@
      */
     public static final long PROPRIETARY = 1L<<38;
 
+    /**
+     * Flag that marks a disjoint var in a multi-catch clause
+     */
+    public static final long DISJOINT = 1L<<39;
+
     /** Modifier masks.
      */
     public static final int
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java	Sun May 02 15:55:02 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java	Mon May 03 17:12:59 2010 -0700
@@ -125,6 +125,9 @@
     public boolean allowDiamond() {
         return compareTo(JDK1_7) >= 0;
     }
+    public boolean allowMulticatch() {
+        return compareTo(JDK1_7) >= 0;
+    }
     public boolean allowEnums() {
         return compareTo(JDK1_5) >= 0;
     }
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Sun May 02 15:55:02 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Mon May 03 17:12:59 2010 -0700
@@ -988,6 +988,13 @@
             Env<AttrContext> catchEnv =
                 env.dup(c, env.info.dup(env.info.scope.dup()));
             Type ctype = attribStat(c.param, catchEnv);
+            if (TreeInfo.isMultiCatch(c)) {
+                //check that multi-catch parameter is marked as final
+                if ((c.param.sym.flags() & FINAL) == 0) {
+                    log.error(c.param.pos(), "multicatch.param.must.be.final", c.param.sym);
+                }
+                c.param.sym.flags_field = c.param.sym.flags() | DISJOINT;
+            }
             if (c.param.type.tsym.kind == Kinds.VAR) {
                 c.param.sym.setData(ElementKind.EXCEPTION_PARAMETER);
             }
@@ -2735,6 +2742,11 @@
         result = check(tree, owntype, TYP, pkind, pt);
     }
 
+    public void visitTypeDisjoint(JCTypeDisjoint tree) {
+        List<Type> componentTypes = attribTypes(tree.components, env);
+        tree.type = result = check(tree, types.lub(componentTypes), TYP, pkind, pt);
+    }
+
     public void visitTypeParameter(JCTypeParameter tree) {
         TypeVar a = (TypeVar)tree.type;
         Set<Type> boundSet = new HashSet<Type>();
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java	Sun May 02 15:55:02 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java	Mon May 03 17:12:59 2010 -0700
@@ -27,6 +27,8 @@
 
 package com.sun.tools.javac.comp;
 
+import java.util.HashMap;
+
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.tree.*;
 import com.sun.tools.javac.util.*;
@@ -184,6 +186,7 @@
     private final Check chk;
     private       TreeMaker make;
     private       Lint lint;
+    private final boolean allowRethrowAnalysis;
 
     public static Flow instance(Context context) {
         Flow instance = context.get(flowKey);
@@ -194,13 +197,14 @@
 
     protected Flow(Context context) {
         context.put(flowKey, this);
-
         names = Names.instance(context);
         log = Log.instance(context);
         syms = Symtab.instance(context);
         types = Types.instance(context);
         chk = Check.instance(context);
         lint = Lint.instance(context);
+        Source source = Source.instance(context);
+        allowRethrowAnalysis = source.allowMulticatch();
     }
 
     /** A flag that indicates whether the last statement could
@@ -216,6 +220,8 @@
      */
     Bits uninits;
 
+    HashMap<Symbol, List<Type>> multicatchTypes;
+
     /** The set of variables that are definitely unassigned everywhere
      *  in current try block. This variable is maintained lazily; it is
      *  updated only when something gets removed from uninits,
@@ -355,8 +361,14 @@
         if (sym.adr >= firstadr && trackable(sym)) {
             if ((sym.flags() & FINAL) != 0) {
                 if ((sym.flags() & PARAMETER) != 0) {
-                    log.error(pos, "final.parameter.may.not.be.assigned",
+                    if ((sym.flags() & DISJOINT) != 0) { //multi-catch parameter
+                        log.error(pos, "multicatch.parameter.may.not.be.assigned",
+                                  sym);
+                    }
+                    else {
+                        log.error(pos, "final.parameter.may.not.be.assigned",
                               sym);
+                    }
                 } else if (!uninits.isMember(sym.adr)) {
                     log.error(pos,
                               loopPassTwo
@@ -952,8 +964,14 @@
         List<Type> caughtPrev = caught;
         List<Type> thrownPrev = thrown;
         thrown = List.nil();
-        for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail)
-            caught = chk.incl(l.head.param.type, caught);
+        for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
+            List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
+                    ((JCTypeDisjoint)l.head.param.vartype).components :
+                    List.of(l.head.param.vartype);
+            for (JCExpression ct : subClauses) {
+                caught = chk.incl(ct.type, caught);
+            }
+        }
         Bits uninitsTryPrev = uninitsTry;
         ListBuffer<PendingExit> prevPendingExits = pendingExits;
         pendingExits = new ListBuffer<PendingExit>();
@@ -973,27 +991,39 @@
         for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
             alive = true;
             JCVariableDecl param = l.head.param;
-            Type exc = param.type;
-            if (chk.subset(exc, caughtInTry)) {
-                log.error(l.head.pos(),
-                          "except.already.caught", exc);
-            } else if (!chk.isUnchecked(l.head.pos(), exc) &&
-                       exc.tsym != syms.throwableType.tsym &&
-                       exc.tsym != syms.exceptionType.tsym &&
-                       !chk.intersects(exc, thrownInTry)) {
-                log.error(l.head.pos(),
-                          "except.never.thrown.in.try", exc);
+            List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
+                    ((JCTypeDisjoint)l.head.param.vartype).components :
+                    List.of(l.head.param.vartype);
+            List<Type> ctypes = List.nil();
+            List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
+            for (JCExpression ct : subClauses) {
+                Type exc = ct.type;
+                ctypes = ctypes.append(exc);
+                if (types.isSameType(exc, syms.objectType))
+                    continue;
+                if (chk.subset(exc, caughtInTry)) {
+                    log.error(l.head.pos(),
+                              "except.already.caught", exc);
+                } else if (!chk.isUnchecked(l.head.pos(), exc) &&
+                           exc.tsym != syms.throwableType.tsym &&
+                           exc.tsym != syms.exceptionType.tsym &&
+                           !chk.intersects(exc, thrownInTry)) {
+                    log.error(l.head.pos(),
+                              "except.never.thrown.in.try", exc);
+                }
+                caughtInTry = chk.incl(exc, caughtInTry);
             }
-            caughtInTry = chk.incl(exc, caughtInTry);
             inits = initsTry.dup();
             uninits = uninitsTry.dup();
             scan(param);
             inits.incl(param.sym.adr);
             uninits.excl(param.sym.adr);
+            multicatchTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
             scanStat(l.head.body);
             initsEnd.andSet(inits);
             uninitsEnd.andSet(uninits);
             nextadr = nextadrCatch;
+            multicatchTypes.remove(param.sym);
             aliveEnd |= alive;
         }
         if (tree.finalizer != null) {
@@ -1121,7 +1151,19 @@
 
     public void visitThrow(JCThrow tree) {
         scanExpr(tree.expr);
-        markThrown(tree, tree.expr.type);
+        Symbol sym = TreeInfo.symbol(tree.expr);
+        if (sym != null &&
+            sym.kind == VAR &&
+            (sym.flags() & FINAL) != 0 &&
+            multicatchTypes.get(sym) != null &&
+            allowRethrowAnalysis) {
+            for (Type t : multicatchTypes.get(sym)) {
+                markThrown(tree, t);
+            }
+        }
+        else {
+            markThrown(tree, tree.expr.type);
+        }
         markDead();
     }
 
@@ -1308,6 +1350,7 @@
             firstadr = 0;
             nextadr = 0;
             pendingExits = new ListBuffer<PendingExit>();
+            multicatchTypes = new HashMap<Symbol, List<Type>>();
             alive = true;
             this.thrown = this.caught = null;
             this.classDef = null;
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java	Sun May 02 15:55:02 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java	Mon May 03 17:12:59 2010 -0700
@@ -1454,20 +1454,26 @@
                       int startpc, int endpc,
                       List<Integer> gaps) {
             if (startpc != endpc) {
-                int catchType = makeRef(tree.pos(), tree.param.type);
-                while (gaps.nonEmpty()) {
-                    int end = gaps.head.intValue();
-                    registerCatch(tree.pos(),
-                                  startpc,  end, code.curPc(),
-                                  catchType);
-                    gaps = gaps.tail;
-                    startpc = gaps.head.intValue();
-                    gaps = gaps.tail;
+                List<JCExpression> subClauses = TreeInfo.isMultiCatch(tree) ?
+                    ((JCTypeDisjoint)tree.param.vartype).components :
+                    List.of(tree.param.vartype);
+                for (JCExpression subCatch : subClauses) {
+                    int catchType = makeRef(tree.pos(), subCatch.type);
+                    List<Integer> lGaps = gaps;
+                    while (lGaps.nonEmpty()) {
+                        int end = lGaps.head.intValue();
+                        registerCatch(tree.pos(),
+                                      startpc,  end, code.curPc(),
+                                      catchType);
+                        lGaps = lGaps.tail;
+                        startpc = lGaps.head.intValue();
+                        lGaps = lGaps.tail;
+                    }
+                    if (startpc < endpc)
+                        registerCatch(tree.pos(),
+                                      startpc, endpc, code.curPc(),
+                                      catchType);
                 }
-                if (startpc < endpc)
-                    registerCatch(tree.pos(),
-                                  startpc, endpc, code.curPc(),
-                                  catchType);
                 VarSymbol exparam = tree.param.sym;
                 code.statBegin(tree.pos);
                 code.markStatBegin();
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Sun May 02 15:55:02 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Mon May 03 17:12:59 2010 -0700
@@ -132,6 +132,7 @@
         this.allowStaticImport = source.allowStaticImport();
         this.allowAnnotations = source.allowAnnotations();
         this.allowDiamond = source.allowDiamond();
+        this.allowMulticatch = source.allowMulticatch();
         this.allowTypeAnnotations = source.allowTypeAnnotations();
         this.keepDocComments = keepDocComments;
         if (keepDocComments)
@@ -153,6 +154,10 @@
      */
     boolean allowDiamond;
 
+    /** Switch: Should multicatch clause be accepted?
+     */
+    boolean allowMulticatch;
+
     /** Switch: Should varargs be recognized?
      */
     boolean allowVarargs;
@@ -2011,14 +2016,28 @@
         int pos = S.pos();
         accept(CATCH);
         accept(LPAREN);
-        JCVariableDecl formal =
-            variableDeclaratorId(optFinal(Flags.PARAMETER),
-                                 qualident());
+        JCModifiers mods = optFinal(Flags.PARAMETER);
+        List<JCExpression> catchTypes = catchTypes();
+        JCExpression paramType = catchTypes.size() > 1 ?
+                toP(F.at(catchTypes.head.getStartPosition()).TypeDisjoint(catchTypes)) :
+                catchTypes.head;
+        JCVariableDecl formal = variableDeclaratorId(mods, paramType);
         accept(RPAREN);
         JCBlock body = block();
         return F.at(pos).Catch(formal, body);
     }
 
+    List<JCExpression> catchTypes() {
+        ListBuffer<JCExpression> catchTypes = ListBuffer.lb();
+        catchTypes.add(parseType());
+        while (S.token() == BAR) {
+            checkMulticatch();
+            S.nextToken();
+            catchTypes.add(qualident());
+        }
+        return catchTypes.toList();
+    }
+
     /** SwitchBlockStatementGroups = { SwitchBlockStatementGroup }
      *  SwitchBlockStatementGroup = SwitchLabel BlockStatements
      *  SwitchLabel = CASE ConstantExpression ":" | DEFAULT ":"
@@ -3193,4 +3212,10 @@
             allowDiamond = true;
         }
     }
+    void checkMulticatch() {
+        if (!allowMulticatch) {
+            log.error(S.pos(), "multicatch.not.supported.in.source", source.name);
+            allowMulticatch = true;
+            }
+    }
 }
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Sun May 02 15:55:02 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Mon May 03 17:12:59 2010 -0700
@@ -172,6 +172,10 @@
 
 compiler.err.final.parameter.may.not.be.assigned=\
     final parameter {0} may not be assigned
+compiler.err.multicatch.parameter.may.not.be.assigned=\
+    multi-catch parameter {0} may not be assigned
+compiler.err.multicatch.param.must.be.final=\
+    multi-catch parameter {0} must be final
 compiler.err.finally.without.try=\
     ''finally'' without ''try''
 compiler.err.foreach.not.applicable.to.type=\
@@ -1235,6 +1239,10 @@
     enums are not supported in -source {0}\n\
 (use -source 5 or higher to enable enums)
 
+compiler.err.multicatch.not.supported.in.source=\
+    multi-catch statement is not supported in -source {0}\n\
+(use -source 7 or higher to enable multi-catch statement)
+
 compiler.err.string.switch.not.supported.in.source=\
     strings in switch are not supported in -source {0}\n\
 (use -source 7 or higher to enable strings in switch)
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java	Sun May 02 15:55:02 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java	Mon May 03 17:12:59 2010 -0700
@@ -236,9 +236,13 @@
      */
     public static final int TYPEAPPLY = TYPEARRAY + 1;
 
+    /** Disjunctive types, of type TypeDisjoint.
+     */
+    public static final int TYPEDISJOINT = TYPEAPPLY + 1;
+
     /** Formal type parameters, of type TypeParameter.
      */
-    public static final int TYPEPARAMETER = TYPEAPPLY + 1;
+    public static final int TYPEPARAMETER = TYPEDISJOINT + 1;
 
     /** Type argument.
      */
@@ -1863,6 +1867,34 @@
     }
 
     /**
+     * A disjoint type, T1 | T2 | ... Tn (used in multicatch statements)
+     */
+    public static class JCTypeDisjoint extends JCExpression implements DisjointTypeTree {
+
+        public List<JCExpression> components;
+
+        protected JCTypeDisjoint(List<JCExpression> components) {
+            this.components = components;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitTypeDisjoint(this); }
+
+        public Kind getKind() { return Kind.DISJOINT_TYPE; }
+
+        public List<JCExpression> getTypeComponents() {
+            return components;
+        }
+        @Override
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitDisjointType(this, d);
+        }
+        @Override
+        public int getTag() {
+            return TYPEDISJOINT;
+        }
+    }
+
+    /**
      * A formal class parameter.
      * @param name name
      * @param bounds bounds
@@ -2220,6 +2252,7 @@
         public void visitTypeIdent(JCPrimitiveTypeTree that) { visitTree(that); }
         public void visitTypeArray(JCArrayTypeTree that)     { visitTree(that); }
         public void visitTypeApply(JCTypeApply that)         { visitTree(that); }
+        public void visitTypeDisjoint(JCTypeDisjoint that)   { visitTree(that); }
         public void visitTypeParameter(JCTypeParameter that) { visitTree(that); }
         public void visitWildcard(JCWildcard that)           { visitTree(that); }
         public void visitTypeBoundKind(TypeBoundKind that)   { visitTree(that); }
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java	Sun May 02 15:55:02 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java	Mon May 03 17:12:59 2010 -0700
@@ -1182,6 +1182,14 @@
         }
     }
 
+    public void visitTypeDisjoint(JCTypeDisjoint tree) {
+        try {
+            printExprs(tree.components, " | ");
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
     public void visitTypeParameter(JCTypeParameter tree) {
         try {
             print(tree.name);
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Sun May 02 15:55:02 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Mon May 03 17:12:59 2010 -0700
@@ -345,6 +345,12 @@
         return M.at(t.pos).TypeApply(clazz, arguments);
     }
 
+    public JCTree visitDisjointType(DisjointTypeTree node, P p) {
+        JCTypeDisjoint t = (JCTypeDisjoint) node;
+        List<JCExpression> components = copy(t.components, p);
+        return M.at(t.pos).TypeDisjoint(components);
+    }
+
     public JCTree visitArrayType(ArrayTypeTree node, P p) {
         JCArrayTypeTree t = (JCArrayTypeTree) node;
         JCExpression elemtype = copy(t.elemtype, p);
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Sun May 02 15:55:02 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Mon May 03 17:12:59 2010 -0700
@@ -118,6 +118,10 @@
         return false;
     }
 
+    public static boolean isMultiCatch(JCCatch catchClause) {
+        return catchClause.param.vartype.getTag() == JCTree.TYPEDISJOINT;
+    }
+
     /** Is statement an initializer for a synthetic field?
      */
     public static boolean isSyntheticInit(JCTree stat) {
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Sun May 02 15:55:02 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Mon May 03 17:12:59 2010 -0700
@@ -444,6 +444,12 @@
         return tree;
     }
 
+    public JCTypeDisjoint TypeDisjoint(List<JCExpression> components) {
+        JCTypeDisjoint tree = new JCTypeDisjoint(components);
+        tree.pos = pos;
+        return tree;
+    }
+
     public JCTypeParameter TypeParameter(Name name, List<JCExpression> bounds) {
         return TypeParameter(name, bounds, List.<JCTypeAnnotation>nil());
     }
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java	Sun May 02 15:55:02 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java	Mon May 03 17:12:59 2010 -0700
@@ -275,6 +275,10 @@
         scan(tree.arguments);
     }
 
+    public void visitTypeDisjoint(JCTypeDisjoint tree) {
+        scan(tree.components);
+    }
+
     public void visitTypeParameter(JCTypeParameter tree) {
         scan(tree.annotations);
         scan(tree.bounds);
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java	Sun May 02 15:55:02 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java	Mon May 03 17:12:59 2010 -0700
@@ -367,6 +367,11 @@
         result = tree;
     }
 
+    public void visitTypeDisjoint(JCTypeDisjoint tree) {
+        tree.components = translate(tree.components);
+        result = tree;
+    }
+
     public void visitTypeParameter(JCTypeParameter tree) {
         tree.annotations = translate(tree.annotations);
         tree.bounds = translate(tree.bounds);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/multicatch/Neg01.java	Mon May 03 17:12:59 2010 -0700
@@ -0,0 +1,28 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6943289
+ *
+ * @summary Project Coin: Improved Exception Handling for Java (aka 'multicatch')
+ * @author darcy
+ * @compile/fail/ref=Neg01.out -XDrawDiagnostics Neg01.java
+ * @compile -source 6 -XDrawDiagnostics Neg01.java
+ *
+ */
+
+class Neg01 {
+    static class A extends Exception {}
+    static class B1 extends A {}
+    static class B2 extends A {}
+
+    class Test {
+        void m() throws A {
+            try {
+                throw new B1();
+            } catch (final A ex1) {
+                try {
+                    throw ex1; // used to throw A, now throws B1!
+                } catch (B2 ex2) { }//unreachable
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/multicatch/Neg01.out	Mon May 03 17:12:59 2010 -0700
@@ -0,0 +1,2 @@
+Neg01.java:24:19: compiler.err.except.never.thrown.in.try: Neg01.B2
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/multicatch/Neg02.java	Mon May 03 17:12:59 2010 -0700
@@ -0,0 +1,25 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6943289
+ *
+ * @summary Project Coin: Improved Exception Handling for Java (aka 'multicatch')
+ * @author mcimadamore
+ * @compile/fail/ref=Neg02.out -XDrawDiagnostics Neg02.java
+ *
+ */
+
+class Neg02 {
+    static class A extends Exception {}
+    static class B extends Exception {}
+
+    void m() {
+        try {
+            if (true) {
+                throw new A();
+            }
+            else {
+                throw new B();
+            }
+        } catch (A | B ex) {  }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/multicatch/Neg02.out	Mon May 03 17:12:59 2010 -0700
@@ -0,0 +1,2 @@
+Neg02.java:23:24: compiler.err.multicatch.param.must.be.final: ex
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/multicatch/Neg03.java	Mon May 03 17:12:59 2010 -0700
@@ -0,0 +1,27 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6943289
+ *
+ * @summary Project Coin: Improved Exception Handling for Java (aka 'multicatch')
+ * @author mcimadamore
+ * @compile/fail/ref=Neg03.out -XDrawDiagnostics Neg03.java
+ *
+ */
+
+class Neg03 {
+    static class A extends Exception {}
+    static class B extends Exception {}
+
+    void m() {
+        try {
+            if (true) {
+                throw new A();
+            }
+            else {
+                throw new B();
+            }
+        } catch (final A | B ex) {
+            ex = new B();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/multicatch/Neg03.out	Mon May 03 17:12:59 2010 -0700
@@ -0,0 +1,2 @@
+Neg03.java:24:13: compiler.err.multicatch.parameter.may.not.be.assigned: ex
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/multicatch/Neg04.java	Mon May 03 17:12:59 2010 -0700
@@ -0,0 +1,31 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6943289
+ *
+ * @summary Project Coin: Improved Exception Handling for Java (aka 'multicatch')
+ * @author mcimadamore
+ * @compile/fail/ref=Neg04.out -XDrawDiagnostics Neg04.java
+ *
+ */
+
+class Neg04 {
+    static class A extends Exception {}
+    static class B extends Exception {}
+
+    void test() throws B {
+        try {
+            if (true) {
+                throw new A();
+            } else if (false) {
+                throw new B();
+            } else {
+                throw (Throwable)new Exception();
+            }
+        }
+        catch (A e) {}
+        catch (final Exception e) {
+            throw e;
+        }
+        catch (Throwable t) {}
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/multicatch/Neg04.out	Mon May 03 17:12:59 2010 -0700
@@ -0,0 +1,2 @@
+Neg04.java:27:13: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/multicatch/Pos01.java	Mon May 03 17:12:59 2010 -0700
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6943289
+ * @summary Project Coin: Improved Exception Handling for Java (aka 'multicatch')
+ *
+ */
+
+public class Pos01 {
+
+    static class A extends Exception {}
+    static class B extends Exception {}
+
+    static int caughtExceptions = 0;
+
+    static void test(boolean b) {
+        try {
+            if (b) {
+                throw new A();
+            }
+            else {
+                throw new B();
+            }
+        }
+        catch (final A | B ex) {
+            caughtExceptions++;
+        }
+    }
+
+    public static void main(String[] args) {
+        test(true);
+        test(false);
+        if (caughtExceptions != 2) {
+            throw new AssertionError("Exception handler called " + caughtExceptions + "times");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/multicatch/Pos02.java	Mon May 03 17:12:59 2010 -0700
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6943289
+ * @summary Project Coin: Improved Exception Handling for Java (aka 'multicatch')
+ *
+ */
+
+public class Pos02 {
+
+    static class A extends Exception {}
+    static class B extends Exception {}
+    static class C extends Exception {}
+    static class C1 extends C {}
+    static class C2 extends C {}
+
+    enum ExceptionKind {
+        A,
+        B,
+        C1,
+        C2
+    }
+
+    static int caughtExceptions = 0;
+    static int caughtRethrownExceptions = 0;
+
+    static void test(ExceptionKind ekind) throws A, C1 {
+        try {
+            switch (ekind) {
+                case A : throw new A();
+                case B : throw new B();
+                case C1: throw new C1();
+                case C2 : throw new C2();
+            }
+        }
+        catch (final C2 | B ex) {
+            caughtExceptions++;
+        }
+        catch (final C | A ex) {
+            caughtExceptions++;
+            throw ex;
+        }
+    }
+
+    public static void main(String[] args) {
+        for (ExceptionKind ekind : ExceptionKind.values()) {
+            try {
+                test(ekind);
+            }
+            catch (final C1 | A ex) {
+                caughtRethrownExceptions++;
+            }
+        }
+        if (caughtExceptions != 4 && caughtRethrownExceptions == 2) {
+            throw new AssertionError("Exception handler called " + caughtExceptions + "times" +
+                                     " rethrown handler called " + caughtRethrownExceptions + "times");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/multicatch/Pos03.java	Mon May 03 17:12:59 2010 -0700
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6943289
+ * @summary Project Coin: Improved Exception Handling for Java (aka 'multicatch')
+ * @compile Pos03.java
+ */
+
+class Pos03 {
+
+    static class A extends Exception { public void m() {}; public Object f;}
+    static class B1 extends A {}
+    static class B2 extends A {}
+
+    void m() {
+        try {
+            if (true) {
+                throw new B1();
+            }
+            else {
+                throw new B2();
+            }
+        } catch (final B1 | B2 ex) {
+            ex.m();
+            System.out.println(ex.f);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/multicatch/Pos04.java	Mon May 03 17:12:59 2010 -0700
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6943289
+ * @summary Project Coin: Improved Exception Handling for Java (aka 'multicatch')
+ */
+
+import java.lang.annotation.*;
+
+public class Pos04 {
+
+    enum ExceptionKind {
+        A(1),
+        B(2),
+        C(1);
+
+        int expectedValue;
+
+        ExceptionKind(int expectedValue) {
+            this.expectedValue = expectedValue;
+        }
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface CatchNumber {
+       int value();
+    }
+
+    @CatchNumber(1)
+    static class A extends Exception { }
+
+    @CatchNumber(2)
+    static class B extends Exception { }
+
+    @CatchNumber(1)
+    static class C extends Exception { }
+
+    static int sum = 0;
+
+    public static void main(String[] args) {
+        for (ExceptionKind ekind : ExceptionKind.values()) {
+            test(ekind);
+        }
+        if (sum != 4) {
+            throw new Error("bad checksum - expected:4, found:" + sum);
+        }
+    }
+
+    public static void test(ExceptionKind ekind) {
+        try {
+            switch(ekind) {
+                case A: throw new A();
+                case B: throw new B();
+                case C: throw new C();
+            }
+        } catch(final A | C ex) {// Catch number 1
+            CatchNumber catchNumber = ex.getClass().getAnnotation(CatchNumber.class);
+            if (catchNumber == null || catchNumber.value() != ekind.expectedValue) {
+                throw new Error("was expecting 1 - got " + catchNumber);
+            }
+            sum += catchNumber.value();
+        } catch (final B ex) { // Catch number 2
+            CatchNumber catchNumber = ex.getClass().getAnnotation(CatchNumber.class);
+            if (catchNumber == null || catchNumber.value() != ekind.expectedValue) {
+                throw new Error("was expecting 2 - got " + catchNumber);
+            }
+            sum += catchNumber.value();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/multicatch/Pos05.java	Mon May 03 17:12:59 2010 -0700
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6943289
+ * @summary  Project Coin: Improved Exception Handling for Java (aka 'multicatch')
+ * @run main Pos05
+ */
+
+import com.sun.tools.classfile.Attribute;
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.Code_attribute;
+import com.sun.tools.classfile.Code_attribute.Exception_data;
+import com.sun.tools.classfile.Method;
+import java.io.*;
+
+public class Pos05 {
+
+    static class Pos05sub {
+
+        class A extends Exception {}
+        class B extends Exception {}
+        class C extends Exception {}
+
+        void test(boolean b1, boolean b2) {
+            try {
+                if (b1) {
+                    throw new A();
+                }
+                else if (b2) {
+                    throw new B();
+                }
+                else {
+                    throw new C();
+                }
+            }
+            catch (final A | B | C ex) {
+                System.out.println("Exception caught");
+            }
+        }
+    }
+
+    static final int TYPES_IN_MULTICATCH = 3;
+    static final String SUBTEST_NAME = Pos05sub.class.getName() + ".class";
+    static final String TEST_METHOD_NAME = "test";
+
+    public static void main(String... args) throws Exception {
+        new Pos05().run();
+    }
+
+    public void run() throws Exception {
+        String workDir = System.getProperty("test.classes");
+        File compiledTest = new File(workDir, SUBTEST_NAME);
+        verifyMulticatchExceptionRanges(compiledTest);
+    }
+
+    void verifyMulticatchExceptionRanges(File f) {
+        System.err.println("verify: " + f);
+        try {
+            int count = 0;
+            ClassFile cf = ClassFile.read(f);
+            Method testMethod = null;
+            for (Method m : cf.methods) {
+                if (m.getName(cf.constant_pool).equals(TEST_METHOD_NAME)) {
+                    testMethod = m;
+                    break;
+                }
+            }
+            if (testMethod == null) {
+                throw new Error("Test method not found");
+            }
+            Code_attribute ea = (Code_attribute)testMethod.attributes.get(Attribute.Code);
+            if (testMethod == null) {
+                throw new Error("Code attribute for test() method not found");
+            }
+            Exception_data firstExceptionTable = null;
+            for (int i = 0 ; i < ea.exception_table_langth; i++) {
+                if (firstExceptionTable == null) {
+                    firstExceptionTable = ea.exception_table[i];
+                }
+                if (ea.exception_table[i].handler_pc != firstExceptionTable.handler_pc ||
+                        ea.exception_table[i].start_pc != firstExceptionTable.start_pc ||
+                        ea.exception_table[i].end_pc != firstExceptionTable.end_pc) {
+                    throw new Error("Multiple overlapping catch clause found in generated code");
+                }
+                count++;
+            }
+            if (count != TYPES_IN_MULTICATCH) {
+                throw new Error("Wrong number of exception data found: " + count);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new Error("error reading " + f +": " + e);
+        }
+    }
+}