changeset 713:bfdfc13fe641

6970584: Flow.java should be more error-friendly Summary: Added a post-attribution visitor that fixup uninitialized types/symbol in AST after erroneous attribution Reviewed-by: jjg
author mcimadamore
date Tue, 07 Sep 2010 17:33:43 +0100
parents 12d8f7e417fd
children c388fa8c6a43
files src/share/classes/com/sun/tools/javac/code/Symtab.java src/share/classes/com/sun/tools/javac/comp/Annotate.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/main/JavaCompiler.java test/tools/javac/failover/CheckAttributedTree.java test/tools/javac/failover/FailOver01.java test/tools/javac/failover/FailOver01.out test/tools/javac/failover/FailOver02.java test/tools/javac/failover/FailOver02.out test/tools/javac/failover/FailOver03.java test/tools/javac/failover/FailOver03.out test/tools/javac/failover/FailOver04.java test/tools/javac/failover/FailOver04.out test/tools/javac/failover/FailOver05.java test/tools/javac/failover/FailOver05.out test/tools/javac/failover/FailOver06.java test/tools/javac/failover/FailOver06.out test/tools/javac/failover/FailOver07.java test/tools/javac/failover/FailOver07.out test/tools/javac/failover/FailOver08.java test/tools/javac/failover/FailOver08.out test/tools/javac/failover/FailOver09.java test/tools/javac/failover/FailOver09.out test/tools/javac/failover/FailOver10.java test/tools/javac/failover/FailOver10.out test/tools/javac/failover/FailOver11.java test/tools/javac/failover/FailOver11.out test/tools/javac/failover/FailOver12.java test/tools/javac/failover/FailOver12.out test/tools/javac/failover/FailOver13.java test/tools/javac/failover/FailOver13.out test/tools/javac/failover/FailOver14.java test/tools/javac/failover/FailOver14.out
diffstat 34 files changed, 1132 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/code/Symtab.java	Tue Sep 07 17:32:52 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Symtab.java	Tue Sep 07 17:33:43 2010 +0100
@@ -93,6 +93,10 @@
      */
     public final ClassSymbol errSymbol;
 
+    /** The unknown symbol.
+     */
+    public final ClassSymbol unknownSymbol;
+
     /** A value for the errType, with a originalType of noType */
     public final Type errType;
 
@@ -354,6 +358,7 @@
 
         // create the error symbols
         errSymbol = new ClassSymbol(PUBLIC|STATIC|ACYCLIC, names.any, null, rootPackage);
+        unknownSymbol = new ClassSymbol(PUBLIC|STATIC|ACYCLIC, names.fromString("<any?>"), null, rootPackage);
         errType = new ErrorType(errSymbol, Type.noType);
 
         // initialize builtin types
@@ -368,7 +373,7 @@
         initType(voidType, "void", "Void");
         initType(botType, "<nulltype>");
         initType(errType, errSymbol);
-        initType(unknownType, "<any?>");
+        initType(unknownType, unknownSymbol);
 
         // the builtin class of all arrays
         arrayClass = new ClassSymbol(PUBLIC|ACYCLIC, names.Array, noSymbol);
--- a/src/share/classes/com/sun/tools/javac/comp/Annotate.java	Tue Sep 07 17:32:52 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Annotate.java	Tue Sep 07 17:33:43 2010 +0100
@@ -182,6 +182,7 @@
             if (!method.type.isErroneous())
                 buf.append(new Pair<MethodSymbol,Attribute>
                            ((MethodSymbol)method, value));
+            t.type = result;
         }
         return new Attribute.Compound(a.type, buf.toList());
     }
@@ -234,6 +235,7 @@
                                                l.head,
                                                env));
             }
+            na.type = expected;
             return new Attribute.
                 Array(expected, buf.toArray(new Attribute[buf.length()]));
         }
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Sep 07 17:32:52 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Sep 07 17:33:43 2010 +0100
@@ -3201,4 +3201,104 @@
             super.visitMethodDef(tree);
         }
     };
+
+    // <editor-fold desc="post-attribution visitor">
+
+    /**
+     * Handle missing types/symbols in an AST. This routine is useful when
+     * the compiler has encountered some errors (which might have ended up
+     * terminating attribution abruptly); if the compiler is used in fail-over
+     * mode (e.g. by an IDE) and the AST contains semantic errors, this routine
+     * prevents NPE to be progagated during subsequent compilation steps.
+     */
+    public void postAttr(Env<AttrContext> env) {
+        new PostAttrAnalyzer().scan(env.tree);
+    }
+
+    class PostAttrAnalyzer extends TreeScanner {
+
+        private void initTypeIfNeeded(JCTree that) {
+            if (that.type == null) {
+                that.type = syms.unknownType;
+            }
+        }
+
+        @Override
+        public void scan(JCTree tree) {
+            if (tree == null) return;
+            if (tree instanceof JCExpression) {
+                initTypeIfNeeded(tree);
+            }
+            super.scan(tree);
+        }
+
+        @Override
+        public void visitIdent(JCIdent that) {
+            if (that.sym == null) {
+                that.sym = syms.unknownSymbol;
+            }
+        }
+
+        @Override
+        public void visitSelect(JCFieldAccess that) {
+            if (that.sym == null) {
+                that.sym = syms.unknownSymbol;
+            }
+            super.visitSelect(that);
+        }
+
+        @Override
+        public void visitClassDef(JCClassDecl that) {
+            initTypeIfNeeded(that);
+            if (that.sym == null) {
+                that.sym = new ClassSymbol(0, that.name, that.type, syms.noSymbol);
+            }
+            super.visitClassDef(that);
+        }
+
+        @Override
+        public void visitMethodDef(JCMethodDecl that) {
+            initTypeIfNeeded(that);
+            if (that.sym == null) {
+                that.sym = new MethodSymbol(0, that.name, that.type, syms.noSymbol);
+            }
+            super.visitMethodDef(that);
+        }
+
+        @Override
+        public void visitVarDef(JCVariableDecl that) {
+            initTypeIfNeeded(that);
+            if (that.sym == null) {
+                that.sym = new VarSymbol(0, that.name, that.type, syms.noSymbol);
+                that.sym.adr = 0;
+            }
+            super.visitVarDef(that);
+        }
+
+        @Override
+        public void visitNewClass(JCNewClass that) {
+            if (that.constructor == null) {
+                that.constructor = new MethodSymbol(0, names.init, syms.unknownType, syms.noSymbol);
+            }
+            if (that.constructorType == null) {
+                that.constructorType = syms.unknownType;
+            }
+            super.visitNewClass(that);
+        }
+
+        @Override
+        public void visitBinary(JCBinary that) {
+            if (that.operator == null)
+                that.operator = new OperatorSymbol(names.empty, syms.unknownType, -1, syms.noSymbol);
+            super.visitBinary(that);
+        }
+
+        @Override
+        public void visitUnary(JCUnary that) {
+            if (that.operator == null)
+                that.operator = new OperatorSymbol(names.empty, syms.unknownType, -1, syms.noSymbol);
+            super.visitUnary(that);
+        }
+    }
+    // </editor-fold>
 }
--- a/src/share/classes/com/sun/tools/javac/comp/Flow.java	Tue Sep 07 17:32:52 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Flow.java	Tue Sep 07 17:33:43 2010 +0100
@@ -408,7 +408,9 @@
         tree = TreeInfo.skipParens(tree);
         if (tree.getTag() == JCTree.IDENT || tree.getTag() == JCTree.SELECT) {
             Symbol sym = TreeInfo.symbol(tree);
-            letInit(tree.pos(), (VarSymbol)sym);
+            if (sym.kind == VAR) {
+                letInit(tree.pos(), (VarSymbol)sym);
+            }
         }
     }
 
@@ -481,12 +483,13 @@
 
     /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
      */
-    void split() {
+    void split(boolean setToNull) {
         initsWhenFalse = inits.dup();
         uninitsWhenFalse = uninits.dup();
         initsWhenTrue = inits;
         uninitsWhenTrue = uninits;
-        inits = uninits = null;
+        if (setToNull)
+            inits = uninits = null;
     }
 
     /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
@@ -568,9 +571,11 @@
             uninitsWhenTrue = uninits;
         } else {
             scan(tree);
-            if (inits != null) split();
+            if (inits != null)
+                split(tree.type != syms.unknownType);
         }
-        inits = uninits = null;
+        if (tree.type != syms.unknownType)
+            inits = uninits = null;
     }
 
     /* ------------ Visitor methods for various sorts of trees -------------*/
@@ -1007,7 +1012,7 @@
                 List.of(resource.type);
             for (Type sup : closeableSupertypes) {
                 if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
-                    Symbol closeMethod = rs.resolveInternalMethod(tree,
+                    Symbol closeMethod = rs.resolveQualifiedMethod(tree,
                             attrEnv,
                             sup,
                             names.close,
@@ -1050,20 +1055,22 @@
             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);
+                if (exc != syms.unknownType) {
+                    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();
--- a/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Tue Sep 07 17:32:52 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Tue Sep 07 17:33:43 2010 +0100
@@ -1144,6 +1144,11 @@
                                   env.toplevel.sourcefile);
         try {
             attr.attribClass(env.tree.pos(), env.enclClass.sym);
+            if (errorCount() > 0 && !shouldStop(CompileState.ATTR)) {
+                //if in fail-over mode, ensure that AST expression nodes
+                //are correctly initialized (e.g. they have a type/symbol)
+                attr.postAttr(env);
+            }
             compileStates.put(env, CompileState.ATTR);
         }
         finally {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/CheckAttributedTree.java	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,775 @@
+/*
+ * Copyright (c) 2010, 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.
+ */
+
+import com.sun.source.util.TaskEvent;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+import javax.swing.event.CaretEvent;
+import javax.swing.event.CaretListener;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.DefaultHighlighter;
+import javax.swing.text.Highlighter;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticListener;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.TaskListener;
+import com.sun.tools.javac.api.JavacTool;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
+import com.sun.tools.javac.tree.JCTree.JCImport;
+import com.sun.tools.javac.tree.TreeInfo;
+import com.sun.tools.javac.tree.TreeScanner;
+import com.sun.tools.javac.util.Pair;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import javax.lang.model.element.Element;
+
+/**
+ * Utility and test program to check validity of tree positions for tree nodes.
+ * The program can be run standalone, or as a jtreg test.  In standalone mode,
+ * errors can be displayed in a gui viewer. For info on command line args,
+ * run program with no args.
+ *
+ * <p>
+ * jtreg: Note that by using the -r switch in the test description below, this test
+ * will process all java files in the langtools/test directory, thus implicitly
+ * covering any new language features that may be tested in this test suite.
+ */
+
+/*
+ * @test
+ * @bug 6970584
+ * @summary assorted position errors in compiler syntax trees
+ * @run main CheckAttributedTree -q -r -et ERRONEOUS .
+ */
+public class CheckAttributedTree {
+    /**
+     * Main entry point.
+     * If test.src is set, program runs in jtreg mode, and will throw an Error
+     * if any errors arise, otherwise System.exit will be used, unless the gui
+     * viewer is being used. In jtreg mode, the default base directory for file
+     * args is the value of ${test.src}. In jtreg mode, the -r option can be
+     * given to change the default base directory to the root test directory.
+     */
+    public static void main(String... args) {
+        String testSrc = System.getProperty("test.src");
+        File baseDir = (testSrc == null) ? null : new File(testSrc);
+        boolean ok = new CheckAttributedTree().run(baseDir, args);
+        if (!ok) {
+            if (testSrc != null)  // jtreg mode
+                throw new Error("failed");
+            else
+                System.exit(1);
+        }
+    }
+
+    /**
+     * Run the program. A base directory can be provided for file arguments.
+     * In jtreg mode, the -r option can be given to change the default base
+     * directory to the test root directory. For other options, see usage().
+     * @param baseDir base directory for any file arguments.
+     * @param args command line args
+     * @return true if successful or in gui mode
+     */
+    boolean run(File baseDir, String... args) {
+        if (args.length == 0) {
+            usage(System.out);
+            return true;
+        }
+
+        List<File> files = new ArrayList<File>();
+        for (int i = 0; i < args.length; i++) {
+            String arg = args[i];
+            if (arg.equals("-encoding") && i + 1 < args.length)
+                encoding = args[++i];
+            else if (arg.equals("-gui"))
+                gui = true;
+            else if (arg.equals("-q"))
+                quiet = true;
+            else if (arg.equals("-v"))
+                verbose = true;
+            else if (arg.equals("-t") && i + 1 < args.length)
+                tags.add(args[++i]);
+            else if (arg.equals("-ef") && i + 1 < args.length)
+                excludeFiles.add(new File(baseDir, args[++i]));
+            else if (arg.equals("-et") && i + 1 < args.length)
+                excludeTags.add(args[++i]);
+            else if (arg.equals("-r")) {
+                if (excludeFiles.size() > 0)
+                    throw new Error("-r must be used before -ef");
+                File d = baseDir;
+                while (!new File(d, "TEST.ROOT").exists()) {
+                    if (d == null)
+                        throw new Error("cannot find TEST.ROOT");
+                    d = d.getParentFile();
+                }
+                baseDir = d;
+            }
+            else if (arg.startsWith("-"))
+                throw new Error("unknown option: " + arg);
+            else {
+                while (i < args.length)
+                    files.add(new File(baseDir, args[i++]));
+            }
+        }
+
+        for (File file: files) {
+            if (file.exists())
+                test(file);
+            else
+                error("File not found: " + file);
+        }
+
+        if (fileCount != 1)
+            System.err.println(fileCount + " files read");
+        if (errors > 0)
+            System.err.println(errors + " errors");
+
+        return (gui || errors == 0);
+    }
+
+    /**
+     * Print command line help.
+     * @param out output stream
+     */
+    void usage(PrintStream out) {
+        out.println("Usage:");
+        out.println("  java CheckAttributedTree options... files...");
+        out.println("");
+        out.println("where options include:");
+        out.println("-q        Quiet: don't report on inapplicable files");
+        out.println("-gui      Display returns in a GUI viewer");
+        out.println("-v        Verbose: report on files as they are being read");
+        out.println("-t tag    Limit checks to tree nodes with this tag");
+        out.println("          Can be repeated if desired");
+        out.println("-ef file  Exclude file or directory");
+        out.println("-et tag   Exclude tree nodes with given tag name");
+        out.println("");
+        out.println("files may be directories or files");
+        out.println("directories will be scanned recursively");
+        out.println("non java files, or java files which cannot be parsed, will be ignored");
+        out.println("");
+    }
+
+    /**
+     * Test a file. If the file is a directory, it will be recursively scanned
+     * for java files.
+     * @param file the file or directory to test
+     */
+    void test(File file) {
+        if (excludeFiles.contains(file)) {
+            if (!quiet)
+                error("File " + file + " excluded");
+            return;
+        }
+
+        if (file.isDirectory()) {
+            for (File f: file.listFiles()) {
+                test(f);
+            }
+            return;
+        }
+
+        if (file.isFile() && file.getName().endsWith(".java")) {
+            try {
+                if (verbose)
+                    System.err.println(file);
+                fileCount++;
+                NPETester p = new NPETester();
+                p.test(read(file));
+            } catch (AttributionException e) {
+                if (!quiet) {
+                    error("Error attributing " + file + "\n" + e.getMessage());
+                }
+            } catch (IOException e) {
+                error("Error reading " + file + ": " + e);
+            }
+            return;
+        }
+
+        if (!quiet)
+            error("File " + file + " ignored");
+    }
+
+    /**
+     * Read a file.
+     * @param file the file to be read
+     * @return the tree for the content of the file
+     * @throws IOException if any IO errors occur
+     * @throws TreePosTest.ParseException if any errors occur while parsing the file
+     */
+    List<Pair<JCCompilationUnit, JCTree>> read(File file) throws IOException, AttributionException {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        Reporter r = new Reporter(pw);
+        JavacTool tool = JavacTool.create();
+        Charset cs = (encoding == null ? null : Charset.forName(encoding));
+        StandardJavaFileManager fm = tool.getStandardFileManager(r, null, null);
+        Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(file);
+        String[] opts = { "-XDshouldStopPolicy=ATTR", "-XDverboseCompilePolicy" };
+        JavacTask task = tool.getTask(pw, fm, r, Arrays.asList(opts), null, files);
+        final List<Element> analyzedElems = new ArrayList<>();
+        task.setTaskListener(new TaskListener() {
+            public void started(TaskEvent e) {
+                if (e.getKind() == TaskEvent.Kind.ANALYZE)
+                        analyzedElems.add(e.getTypeElement());
+            }
+            public void finished(TaskEvent e) { }
+        });
+
+        try {
+            Iterable<? extends CompilationUnitTree> trees = task.parse();
+            task.analyze();
+            List<Pair<JCCompilationUnit, JCTree>> res = new ArrayList<>();
+            System.out.println("Try to add pairs. Elems are " + analyzedElems);
+            for (CompilationUnitTree t : trees) {
+               JCCompilationUnit cu = (JCCompilationUnit)t;
+               for (JCTree def : cu.defs) {
+                   if (def.getTag() == JCTree.CLASSDEF &&
+                           analyzedElems.contains(((JCTree.JCClassDecl)def).sym)) {
+                       System.out.println("Adding pair...");
+                       res.add(new Pair<>(cu, def));
+                   }
+               }
+            }
+            return res;
+        }
+        catch (Throwable t) {
+            throw new AttributionException("Exception while attributing file: " + file);
+        }
+    }
+
+    /**
+     * Report an error. When the program is complete, the program will either
+     * exit or throw an Error if any errors have been reported.
+     * @param msg the error message
+     */
+    void error(String msg) {
+        System.err.println(msg);
+        errors++;
+    }
+
+    /** Number of files that have been analyzed. */
+    int fileCount;
+    /** Number of errors reported. */
+    int errors;
+    /** Flag: don't report irrelevant files. */
+    boolean quiet;
+    /** Flag: show errors in GUI viewer. */
+    boolean gui;
+    /** The GUI viewer for errors. */
+    Viewer viewer;
+    /** Flag: report files as they are processed. */
+    boolean verbose;
+    /** Option: encoding for test files. */
+    String encoding;
+    /** The set of tags for tree nodes to be analyzed; if empty, all tree nodes
+     * are analyzed. */
+    Set<String> tags = new HashSet<String>();
+    /** Set of files and directories to be excluded from analysis. */
+    Set<File> excludeFiles = new HashSet<File>();
+    /** Set of tag names to be excluded from analysis. */
+    Set<String> excludeTags = new HashSet<String>();
+    /** Utility class for trees */
+    TreeUtil treeUtil = new TreeUtil();
+
+    /**
+     * Main class for testing assertions concerning types/symbol
+     * left uninitialized after attribution
+     */
+    private class NPETester extends TreeScanner {
+        void test(List<Pair<JCCompilationUnit, JCTree>> trees) {
+            for (Pair<JCCompilationUnit, JCTree> p : trees) {
+                sourcefile = p.fst.sourcefile;
+                endPosTable = p.fst.endPositions;
+                encl = new Info(p.snd, endPosTable);
+                p.snd.accept(this);
+            }
+        }
+
+        @Override
+        public void scan(JCTree tree) {
+            if (tree == null ||
+                    excludeTags.contains(treeUtil.nameFromTag(tree.getTag()))) {
+                return;
+            }
+
+            Info self = new Info(tree, endPosTable);
+            check(!mandatoryType(tree) ||
+                    (tree.type != null &&
+                    checkFields(tree)),
+                    "'null' found in tree ",
+                    self);
+
+            Info prevEncl = encl;
+            encl = self;
+            tree.accept(this);
+            encl = prevEncl;
+        }
+
+        private boolean mandatoryType(JCTree that) {
+            return that instanceof JCTree.JCExpression ||
+                    that.getTag() == JCTree.VARDEF ||
+                    that.getTag() == JCTree.METHODDEF ||
+                    that.getTag() == JCTree.CLASSDEF;
+        }
+
+        private final List<String> excludedFields = Arrays.asList("varargsElement");
+
+        void check(boolean ok, String label, Info self) {
+            if (!ok) {
+                if (gui) {
+                    if (viewer == null)
+                        viewer = new Viewer();
+                    viewer.addEntry(sourcefile, label, encl, self);
+                }
+                error(label + self.toString() + " encl: " + encl.toString() + " in file: " + sourcefile + "  " + self.tree);
+            }
+        }
+
+        boolean checkFields(JCTree t) {
+            List<Field> fieldsToCheck = treeUtil.getFieldsOfType(t,
+                    excludedFields,
+                    Symbol.class,
+                    Type.class);
+            for (Field f : fieldsToCheck) {
+                try {
+                    if (f.get(t) == null) {
+                        return false;
+                    }
+                }
+                catch (IllegalAccessException e) {
+                    System.err.println("Cannot read field: " + f);
+                    //swallow it
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public void visitImport(JCImport tree) { }
+
+        @Override
+        public void visitTopLevel(JCCompilationUnit tree) {
+            scan(tree.defs);
+        }
+
+        JavaFileObject sourcefile;
+        Map<JCTree, Integer> endPosTable;
+        Info encl;
+    }
+
+    /**
+     * Utility class providing easy access to position and other info for a tree node.
+     */
+    private class Info {
+        Info() {
+            tree = null;
+            tag = JCTree.ERRONEOUS;
+            start = 0;
+            pos = 0;
+            end = Integer.MAX_VALUE;
+        }
+
+        Info(JCTree tree, Map<JCTree, Integer> endPosTable) {
+            this.tree = tree;
+            tag = tree.getTag();
+            start = TreeInfo.getStartPos(tree);
+            pos = tree.pos;
+            end = TreeInfo.getEndPos(tree, endPosTable);
+        }
+
+        @Override
+        public String toString() {
+            return treeUtil.nameFromTag(tree.getTag()) + "[start:" + start + ",pos:" + pos + ",end:" + end + "]";
+        }
+
+        final JCTree tree;
+        final int tag;
+        final int start;
+        final int pos;
+        final int end;
+    }
+
+    /**
+     * Names for tree tags.
+     * javac does not provide an API to convert tag values to strings, so this class uses
+     * reflection to determine names of public static final int values in JCTree.
+     */
+    private static class TreeUtil {
+        String nameFromTag(int tag) {
+            if (names == null) {
+                names = new HashMap<Integer, String>();
+                Class c = JCTree.class;
+                for (Field f : c.getDeclaredFields()) {
+                    if (f.getType().equals(int.class)) {
+                        int mods = f.getModifiers();
+                        if (Modifier.isPublic(mods) && Modifier.isStatic(mods) && Modifier.isFinal(mods)) {
+                            try {
+                                names.put(f.getInt(null), f.getName());
+                            } catch (IllegalAccessException e) {
+                            }
+                        }
+                    }
+                }
+            }
+            String name = names.get(tag);
+            return (name == null) ? "??" : name;
+        }
+
+        List<Field> getFieldsOfType(JCTree t, List<String> excludeNames, Class<?>... types) {
+            List<Field> buf = new ArrayList<Field>();
+            for (Field f : t.getClass().getDeclaredFields()) {
+                if (!excludeNames.contains(f.getName())) {
+                    for (Class<?> type : types) {
+                        if (type.isAssignableFrom(f.getType())) {
+                            f.setAccessible(true);
+                            buf.add(f);
+                            break;
+                        }
+                    }
+                }
+            }
+            return buf;
+        }
+
+        private Map<Integer, String> names;
+    }
+
+    /**
+     * Thrown when errors are found parsing a java file.
+     */
+    private static class ParseException extends Exception {
+        ParseException(String msg) {
+            super(msg);
+        }
+    }
+
+    private static class AttributionException extends Exception {
+        AttributionException(String msg) {
+            super(msg);
+        }
+    }
+
+    /**
+     * DiagnosticListener to report diagnostics and count any errors that occur.
+     */
+    private static class Reporter implements DiagnosticListener<JavaFileObject> {
+        Reporter(PrintWriter out) {
+            this.out = out;
+        }
+
+        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+            out.println(diagnostic);
+            switch (diagnostic.getKind()) {
+                case ERROR:
+                    errors++;
+            }
+        }
+        int errors;
+        PrintWriter out;
+    }
+
+    /**
+     * GUI viewer for issues found by TreePosTester. The viewer provides a drop
+     * down list for selecting error conditions, a header area providing details
+     * about an error, and a text area with the ranges of text highlighted as
+     * appropriate.
+     */
+    private class Viewer extends JFrame {
+        /**
+         * Create a viewer.
+         */
+        Viewer() {
+            initGUI();
+        }
+
+        /**
+         * Add another entry to the list of errors.
+         * @param file The file containing the error
+         * @param check The condition that was being tested, and which failed
+         * @param encl the enclosing tree node
+         * @param self the tree node containing the error
+         */
+        void addEntry(JavaFileObject file, String check, Info encl, Info self) {
+            Entry e = new Entry(file, check, encl, self);
+            DefaultComboBoxModel m = (DefaultComboBoxModel) entries.getModel();
+            m.addElement(e);
+            if (m.getSize() == 1)
+                entries.setSelectedItem(e);
+        }
+
+        /**
+         * Initialize the GUI window.
+         */
+        private void initGUI() {
+            JPanel head = new JPanel(new GridBagLayout());
+            GridBagConstraints lc = new GridBagConstraints();
+            GridBagConstraints fc = new GridBagConstraints();
+            fc.anchor = GridBagConstraints.WEST;
+            fc.fill = GridBagConstraints.HORIZONTAL;
+            fc.gridwidth = GridBagConstraints.REMAINDER;
+
+            entries = new JComboBox();
+            entries.addActionListener(new ActionListener() {
+                public void actionPerformed(ActionEvent e) {
+                    showEntry((Entry) entries.getSelectedItem());
+                }
+            });
+            fc.insets.bottom = 10;
+            head.add(entries, fc);
+            fc.insets.bottom = 0;
+            head.add(new JLabel("check:"), lc);
+            head.add(checkField = createTextField(80), fc);
+            fc.fill = GridBagConstraints.NONE;
+            head.add(setBackground(new JLabel("encl:"), enclColor), lc);
+            head.add(enclPanel = new InfoPanel(), fc);
+            head.add(setBackground(new JLabel("self:"), selfColor), lc);
+            head.add(selfPanel = new InfoPanel(), fc);
+            add(head, BorderLayout.NORTH);
+
+            body = new JTextArea();
+            body.setFont(Font.decode(Font.MONOSPACED));
+            body.addCaretListener(new CaretListener() {
+                public void caretUpdate(CaretEvent e) {
+                    int dot = e.getDot();
+                    int mark = e.getMark();
+                    if (dot == mark)
+                        statusText.setText("dot: " + dot);
+                    else
+                        statusText.setText("dot: " + dot + ", mark:" + mark);
+                }
+            });
+            JScrollPane p = new JScrollPane(body,
+                    JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+                    JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+            p.setPreferredSize(new Dimension(640, 480));
+            add(p, BorderLayout.CENTER);
+
+            statusText = createTextField(80);
+            add(statusText, BorderLayout.SOUTH);
+
+            pack();
+            setLocationRelativeTo(null); // centered on screen
+            setVisible(true);
+            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        }
+
+        /** Show an entry that has been selected. */
+        private void showEntry(Entry e) {
+            try {
+                // update simple fields
+                setTitle(e.file.getName());
+                checkField.setText(e.check);
+                enclPanel.setInfo(e.encl);
+                selfPanel.setInfo(e.self);
+                // show file text with highlights
+                body.setText(e.file.getCharContent(true).toString());
+                Highlighter highlighter = body.getHighlighter();
+                highlighter.removeAllHighlights();
+                addHighlight(highlighter, e.encl, enclColor);
+                addHighlight(highlighter, e.self, selfColor);
+                scroll(body, getMinPos(enclPanel.info, selfPanel.info));
+            } catch (IOException ex) {
+                body.setText("Cannot read " + e.file.getName() + ": " + e);
+            }
+        }
+
+        /** Create a test field. */
+        private JTextField createTextField(int width) {
+            JTextField f = new JTextField(width);
+            f.setEditable(false);
+            f.setBorder(null);
+            return f;
+        }
+
+        /** Add a highlighted region based on the positions in an Info object. */
+        private void addHighlight(Highlighter h, Info info, Color c) {
+            int start = info.start;
+            int end = info.end;
+            if (start == -1 && end == -1)
+                return;
+            if (start == -1)
+                start = end;
+            if (end == -1)
+                end = start;
+            try {
+                h.addHighlight(info.start, info.end,
+                        new DefaultHighlighter.DefaultHighlightPainter(c));
+                if (info.pos != -1) {
+                    Color c2 = new Color(c.getRed(), c.getGreen(), c.getBlue(), (int)(.4f * 255)); // 40%
+                    h.addHighlight(info.pos, info.pos + 1,
+                        new DefaultHighlighter.DefaultHighlightPainter(c2));
+                }
+            } catch (BadLocationException e) {
+                e.printStackTrace();
+            }
+        }
+
+        /** Get the minimum valid position in a set of info objects. */
+        private int getMinPos(Info... values) {
+            int i = Integer.MAX_VALUE;
+            for (Info info: values) {
+                if (info.start >= 0) i = Math.min(i, info.start);
+                if (info.pos   >= 0) i = Math.min(i, info.pos);
+                if (info.end   >= 0) i = Math.min(i, info.end);
+            }
+            return (i == Integer.MAX_VALUE) ? 0 : i;
+        }
+
+        /** Set the background on a component. */
+        private JComponent setBackground(JComponent comp, Color c) {
+            comp.setOpaque(true);
+            comp.setBackground(c);
+            return comp;
+        }
+
+        /** Scroll a text area to display a given position near the middle of the visible area. */
+        private void scroll(final JTextArea t, final int pos) {
+            // Using invokeLater appears to give text a chance to sort itself out
+            // before the scroll happens; otherwise scrollRectToVisible doesn't work.
+            // Maybe there's a better way to sync with the text...
+            EventQueue.invokeLater(new Runnable() {
+                public void run() {
+                    try {
+                        Rectangle r = t.modelToView(pos);
+                        JScrollPane p = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, t);
+                        r.y = Math.max(0, r.y - p.getHeight() * 2 / 5);
+                        r.height += p.getHeight() * 4 / 5;
+                        t.scrollRectToVisible(r);
+                    } catch (BadLocationException ignore) {
+                    }
+                }
+            });
+        }
+
+        private JComboBox entries;
+        private JTextField checkField;
+        private InfoPanel enclPanel;
+        private InfoPanel selfPanel;
+        private JTextArea body;
+        private JTextField statusText;
+
+        private Color selfColor = new Color(0.f, 1.f, 0.f, 0.2f); // 20% green
+        private Color enclColor = new Color(1.f, 0.f, 0.f, 0.2f); // 20% red
+
+        /** Panel to display an Info object. */
+        private class InfoPanel extends JPanel {
+            InfoPanel() {
+                add(tagName = createTextField(20));
+                add(new JLabel("start:"));
+                add(addListener(start = createTextField(6)));
+                add(new JLabel("pos:"));
+                add(addListener(pos = createTextField(6)));
+                add(new JLabel("end:"));
+                add(addListener(end = createTextField(6)));
+            }
+
+            void setInfo(Info info) {
+                this.info = info;
+                tagName.setText(treeUtil.nameFromTag(info.tag));
+                start.setText(String.valueOf(info.start));
+                pos.setText(String.valueOf(info.pos));
+                end.setText(String.valueOf(info.end));
+            }
+
+            JTextField addListener(final JTextField f) {
+                f.addMouseListener(new MouseAdapter() {
+                    @Override
+                    public void mouseClicked(MouseEvent e) {
+                        body.setCaretPosition(Integer.valueOf(f.getText()));
+                        body.getCaret().setVisible(true);
+                    }
+                });
+                return f;
+            }
+
+            Info info;
+            JTextField tagName;
+            JTextField start;
+            JTextField pos;
+            JTextField end;
+        }
+
+        /** Object to record information about an error to be displayed. */
+        private class Entry {
+            Entry(JavaFileObject file, String check, Info encl, Info self) {
+                this.file = file;
+                this.check = check;
+                this.encl = encl;
+                this.self= self;
+            }
+
+            @Override
+            public String toString() {
+                return file.getName() + " " + check + " " + getMinPos(encl, self);
+            }
+
+            final JavaFileObject file;
+            final String check;
+            final Info encl;
+            final Info self;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver01.java	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,10 @@
+/*
+  * @test /nodynamiccopyright/
+ * @bug 6970584
+ * @summary Flow.java should be more error-friendly
+ * @author mcimadamore
+ *
+ * @compile/fail/ref=FailOver01.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver01.java
+ */
+
+class Test { { x = "" } }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver01.out	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,3 @@
+FailOver01.java:10:22: compiler.err.expected: ';'
+FailOver01.java:10:16: compiler.err.cant.resolve.location: kindname.variable, x, , , kindname.class, Test
+2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver02.java	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,14 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6970584
+ * @summary Flow.java should be more error-friendly
+ * @author mcimadamore
+ *
+ * @compile/fail/ref=FailOver02.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver02.java
+ */
+
+class Test implements AutoCloseable {
+    void test() {
+        try(Test t = null) {}
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver02.out	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,3 @@
+FailOver02.java:10:1: compiler.err.does.not.override.abstract: Test, close(), java.lang.AutoCloseable
+FailOver02.java:12:9: compiler.err.cant.resolve.location.args: kindname.method, close, , , kindname.class, Test
+2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver03.java	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,12 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6970584
+ * @summary Flow.java should be more error-friendly
+ * @author mcimadamore
+ *
+ * @compile/fail/ref=FailOver03.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver03.java
+ */
+
+class Test extends Test {
+   Test i;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver03.out	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,2 @@
+FailOver03.java:10:1: compiler.err.cyclic.inheritance: Test
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver04.java	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,12 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6970584
+ * @summary Flow.java should be more error-friendly
+ * @author mcimadamore
+ *
+ * @compile/fail/ref=FailOver04.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver04.java
+ */
+
+class Test {
+   { new Unknown() {}; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver04.out	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,2 @@
+FailOver04.java:11:10: compiler.err.cant.resolve.location: kindname.class, Unknown, , , kindname.class, Test
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver05.java	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,12 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6970584
+ * @summary Flow.java should be more error-friendly
+ * @author mcimadamore
+ *
+ * @compile/fail/ref=FailOver05.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver05.java
+ */
+
+class Test extends Test {
+   { for ( Integer x : null) {} }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver05.out	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,2 @@
+FailOver05.java:10:1: compiler.err.cyclic.inheritance: Test
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver06.java	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,13 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6970584
+ * @summary Flow.java should be more error-friendly
+ * @author mcimadamore
+ *
+ * @compile/fail/ref=FailOver06.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver06.java
+ */
+
+class Test extends Test {
+    Inference x = 1;
+    { if (x == 1) { } else { } }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver06.out	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,2 @@
+FailOver06.java:10:1: compiler.err.cyclic.inheritance: Test
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver07.java	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,13 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6970584
+ * @summary Flow.java should be more error-friendly
+ * @author mcimadamore
+ *
+ * @compile/fail/ref=FailOver07.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver07.java
+ */
+
+class Test extends Test {
+    Integer x = 1;
+    { do {} while (x); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver07.out	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,2 @@
+FailOver07.java:10:1: compiler.err.cyclic.inheritance: Test
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver08.java	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,13 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6970584
+ * @summary Flow.java should be more error-friendly
+ * @author mcimadamore
+ *
+ * @compile/fail/ref=FailOver08.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver08.java
+ */
+
+class Test extends Test {
+    Integer x = 1;
+    { while (x) {}; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver08.out	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,2 @@
+FailOver08.java:10:1: compiler.err.cyclic.inheritance: Test
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver09.java	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,13 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6970584
+ * @summary Flow.java should be more error-friendly
+ * @author mcimadamore
+ *
+ * @compile/fail/ref=FailOver09.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver09.java
+ */
+
+class Test extends Test {
+    Integer x = 1;
+    { for (x = 0 ; x ; x++) {}; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver09.out	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,2 @@
+FailOver09.java:10:1: compiler.err.cyclic.inheritance: Test
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver10.java	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,15 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6970584
+ * @summary Flow.java should be more error-friendly
+ * @author mcimadamore
+ *
+ * @compile/fail/ref=FailOver10.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver10.java
+ */
+
+class Test extends Test {
+
+    boolean cond;
+
+    { Object o = null; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver10.out	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,2 @@
+FailOver10.java:10:1: compiler.err.cyclic.inheritance: Test
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver11.java	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,17 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6970584
+ * @summary Flow.java should be more error-friendly
+ * @author mcimadamore
+ *
+ * @compile/fail/ref=FailOver11.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver11.java
+ */
+
+class Test extends Test {
+
+    boolean cond;
+
+    void m(Object o) {}
+
+    { m(cond ? null : null); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver11.out	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,2 @@
+FailOver11.java:10:1: compiler.err.cyclic.inheritance: Test
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver12.java	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,15 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6970584
+ * @summary Flow.java should be more error-friendly
+ * @author mcimadamore
+ *
+ * @compile/fail/ref=FailOver12.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver12.java
+ */
+
+class Test extends Test {
+
+    Integer x = 1;
+
+    { try {} catch (Exception e) {} }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver12.out	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,2 @@
+FailOver12.java:10:1: compiler.err.cyclic.inheritance: Test
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver13.java	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,15 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6970584
+ * @summary Flow.java should be more error-friendly
+ * @author mcimadamore
+ *
+ * @compile/fail/ref=FailOver13.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver13.java
+ */
+
+class Test extends Test {
+
+    Integer x = 1;
+
+    { x = (Object)o; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver13.out	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,2 @@
+FailOver13.java:10:1: compiler.err.cyclic.inheritance: Test
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver14.java	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,14 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6970584
+ * @summary Flow.java should be more error-friendly
+ * @author mcimadamore
+ *
+ * @compile/fail/ref=FailOver14.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver14.java
+ */
+
+class Test extends Test  {
+
+   { for (Integer x : !x) { } }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/failover/FailOver14.out	Tue Sep 07 17:33:43 2010 +0100
@@ -0,0 +1,2 @@
+FailOver14.java:10:1: compiler.err.cyclic.inheritance: Test
+1 error