8080069: JShell: Support for corralled classes
authorrfield
Thu, 10 Mar 2016 14:47:14 -0800
changeset 36499 9d823cc0fe98
parent 36498 8a741def7f32
child 36500 d31e4986dc8b
8080069: JShell: Support for corralled classes Reviewed-by: jlahoda
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/Corraller.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/UnresolvedReferenceException.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java
langtools/test/jdk/jshell/ClassesTest.java
langtools/test/jdk/jshell/DropTest.java
langtools/test/jdk/jshell/KullaTesting.java
langtools/test/jdk/jshell/ReplaceTest.java
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Thu Mar 10 09:51:46 2016 -0800
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Thu Mar 10 14:47:14 2016 -0800
@@ -98,6 +98,7 @@
 import jdk.internal.jshell.tool.Feedback.FormatResolve;
 import jdk.internal.jshell.tool.Feedback.FormatWhen;
 import static java.util.stream.Collectors.toList;
+import static jdk.jshell.Snippet.Kind.METHOD;
 import static java.util.stream.Collectors.toMap;
 import static jdk.jshell.Snippet.SubKind.VAR_VALUE_SUBKIND;
 
@@ -2139,7 +2140,7 @@
     }
     //where
     void printUnresolved(UnresolvedReferenceException ex) {
-        MethodSnippet corralled =  ex.getMethodSnippet();
+        DeclarationSnippet corralled =  ex.getSnippet();
         List<Diag> otherErrors = errorsOnly(state.diagnostics(corralled));
         StringBuilder sb = new StringBuilder();
         if (otherErrors.size() > 0) {
@@ -2155,7 +2156,10 @@
             sb.append(".");
         }
 
-        hard("Attempted to call %s which cannot be invoked until%s", corralled.name(),
+        String format = corralled.kind() == METHOD
+                ? "Attempted to call %s which cannot be invoked until%s"
+                : "Attempted to use %s which cannot be accessed until%s";
+        hard(format, corralled.name(),
                 unresolved(corralled), sb.toString());
         if (otherErrors.size() > 0) {
             printDiagnostics(corralled.source(), otherErrors, true);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Corraller.java	Thu Mar 10 14:47:14 2016 -0800
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2016, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jshell;
+
+import java.util.List;
+import com.sun.source.tree.ArrayTypeTree;
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.VariableTree;
+import jdk.jshell.Wrap.Range;
+import static java.util.stream.Collectors.toList;
+
+/**
+ * Produce a corralled version of the Wrap for a snippet.
+ *
+ * @author Robert Field
+ */
+class Corraller {
+
+    private final int index;
+    private final String compileSource;
+    private final TreeDissector dis;
+
+    Corraller(int index, String compileSource, TreeDissector dis) {
+        this.index = index;
+        this.compileSource = compileSource;
+        this.dis = dis;
+    }
+
+    Wrap corralTree(Tree tree, String enclosingType, int indent) {
+        switch (tree.getKind()) {
+            case VARIABLE:
+                return corralVariable((VariableTree) tree, indent);
+            case CLASS:
+            case ENUM:
+            case ANNOTATION_TYPE:
+            case INTERFACE:
+                return corralType((ClassTree) tree, indent);
+            case METHOD:
+                return corralMethod((MethodTree) tree, enclosingType, indent);
+            default:
+                return null;
+        }
+    }
+
+    Wrap corralMethod(MethodTree mt) {
+        return corralMethod(mt, null, 1);
+    }
+
+    Wrap corralMethod(MethodTree mt, String enclosingType, int indent) {
+        Range modRange = dis.treeToRange(mt.getModifiers());
+        Range tpRange = dis.treeListToRange(mt.getTypeParameters());
+        Range typeRange = dis.treeToRange(mt.getReturnType());
+        String name = mt.getName().toString();
+        if ("<init>".equals(name)) {
+            name = enclosingType;
+        }
+        Range paramRange = dis.treeListToRange(mt.getParameters());
+        Range throwsRange = dis.treeListToRange(mt.getThrows());
+        return Wrap.corralledMethod(compileSource,
+                modRange, tpRange, typeRange, name, paramRange, throwsRange, index, indent);
+    }
+
+    Wrap corralVariable(VariableTree vt, int indent) {
+        String name = vt.getName().toString();
+        Range modRange = dis.treeToRange(vt.getModifiers());
+        Tree baseType = vt.getType();
+        StringBuilder sbBrackets = new StringBuilder();
+        while (baseType instanceof ArrayTypeTree) {
+            //TODO handle annotations too
+            baseType = ((ArrayTypeTree) baseType).getType();
+            sbBrackets.append("[]");
+        }
+        Range rtype = dis.treeToRange(baseType);
+        Range runit = dis.treeToRange(vt);
+        runit = new Range(runit.begin, runit.end - 1);
+        ExpressionTree it = vt.getInitializer();
+        int nameMax;
+        if (it != null) {
+            Range rinit = dis.treeToRange(it);
+            nameMax = rinit.begin - 1;
+        } else {
+            nameMax = runit.end - 1;
+        }
+        int nameStart = compileSource.lastIndexOf(name, nameMax);
+        if (nameStart < 0) {
+            throw new AssertionError("Name '" + name + "' not found");
+        }
+        int nameEnd = nameStart + name.length();
+        Range rname = new Range(nameStart, nameEnd);
+        return Wrap.corralledVar(compileSource, modRange, rtype, sbBrackets.toString(), rname, indent);
+    }
+
+    Wrap corralType(ClassTree ct, int indent) {
+        boolean isClass;
+        switch (ct.getKind()) {
+            case CLASS:
+                isClass = true;
+                break;
+            case INTERFACE:
+                isClass = false;
+                break;
+            default:
+                return null;
+        }
+        Range modRange = dis.treeToRange(ct.getModifiers());
+        String name = ct.getSimpleName().toString();
+        Range tpRange = dis.treeListToRange(ct.getTypeParameters());
+        Range extendsRange = dis.treeToRange(ct.getExtendsClause());
+        List<Range> implementsRanges = ct.getImplementsClause().stream()
+                .map(ic -> dis.treeToRange(ic))
+                .collect(toList());
+        List<Wrap> members = ct.getMembers().stream()
+                .map(t -> corralTree(t, name, indent + 1))
+                .filter(w -> w != null)
+                .collect(toList());
+        boolean hasConstructor = ct.getMembers().stream()
+                .anyMatch(t -> t.getKind() == Tree.Kind.METHOD && ((MethodTree) t).getName().toString().equals("<init>"));
+        Wrap wrap = Wrap.corralledType(compileSource, modRange, ct.getKind(), name, tpRange,
+                extendsRange, implementsRanges, members, isClass && !hasConstructor, index, indent);
+        return wrap;
+    }
+}
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Thu Mar 10 09:51:46 2016 -0800
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Thu Mar 10 14:47:14 2016 -0800
@@ -53,6 +53,7 @@
 import jdk.jshell.ClassTracker.ClassInfo;
 import jdk.jshell.Key.ErroneousKey;
 import jdk.jshell.Key.MethodKey;
+import jdk.jshell.Key.TypeDeclKey;
 import jdk.jshell.Snippet.SubKind;
 import jdk.jshell.TaskFactory.AnalyzeTask;
 import jdk.jshell.TaskFactory.BaseTask;
@@ -300,7 +301,8 @@
         ClassTree klassTree = (ClassTree) unitTree;
         String name = klassTree.getSimpleName().toString();
         Wrap guts = Wrap.classMemberWrap(compileSource);
-        Wrap corralled = null; //TODO
+        TypeDeclKey key = state.keyMap.keyForClass(name);
+        Wrap corralled = new Corraller(key.index(), compileSource, dis).corralType(klassTree, 1);
         Snippet snip = new TypeDeclSnippet(state.keyMap.keyForClass(name), userSource, guts,
                 name, snippetKind,
                 corralled, tds.declareReferences(), tds.bodyReferences());
@@ -362,12 +364,8 @@
         String unitName = mt.getName().toString();
         Wrap guts = Wrap.classMemberWrap(compileSource);
 
-        Range modRange = dis.treeToRange(mt.getModifiers());
-        Range tpRange = dis.treeListToRange(mt.getTypeParameters());
         Range typeRange = dis.treeToRange(mt.getReturnType());
         String name = mt.getName().toString();
-        Range paramRange = dis.treeListToRange(mt.getParameters());
-        Range throwsRange = dis.treeListToRange(mt.getThrows());
 
         String parameterTypes
                 = mt.getParameters()
@@ -378,8 +376,7 @@
 
         MethodKey key = state.keyMap.keyForMethod(name, parameterTypes);
         // rewrap with correct Key index
-        Wrap corralled = Wrap.corralledMethod(compileSource,
-                modRange, tpRange, typeRange, name, paramRange, throwsRange, key.index());
+        Wrap corralled = new Corraller(key.index(), compileSource, dis).corralMethod(mt);
         Snippet snip = new MethodSnippet(key, userSource, guts,
                 unitName, signature,
                 corralled, tds.declareReferences(), tds.bodyReferences());
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java	Thu Mar 10 09:51:46 2016 -0800
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java	Thu Mar 10 14:47:14 2016 -0800
@@ -225,7 +225,7 @@
                 int id = in.readInt();
                 StackTraceElement[] elems = readStackTrace();
                 Snippet si = maps.getSnippet(id);
-                throw new UnresolvedReferenceException((MethodSnippet) si, elems);
+                throw new UnresolvedReferenceException((DeclarationSnippet) si, elems);
             }
             case RESULT_KILLED: {
                 proc.out.println("Killed.");
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/UnresolvedReferenceException.java	Thu Mar 10 09:51:46 2016 -0800
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/UnresolvedReferenceException.java	Thu Mar 10 14:47:14 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -28,33 +28,33 @@
 /**
  * Exception reported on attempting to execute a
  * {@link jdk.jshell.Snippet.Status#RECOVERABLE_DEFINED RECOVERABLE_DEFINED}
- * method.
+ * snippet.
  * <p>
  * The stack can be queried by methods on <code>Exception</code>.
  * Note that in stack trace frames representing JShell Snippets,
  * <code>StackTraceElement.getFileName()</code> will return "#" followed by
  * the Snippet id and for snippets without a method name (for example an
- * expression) <code>StackTraceElement.getMethodName()</code> will be the
+ * expression) <code>StackTraceElement.getName()</code> will be the
  * empty string.
  */
 @SuppressWarnings("serial")             // serialVersionUID intentionally omitted
 public class UnresolvedReferenceException extends Exception {
 
-    final MethodSnippet methodSnippet;
+    final DeclarationSnippet snippet;
 
-    UnresolvedReferenceException(MethodSnippet methodSnippet, StackTraceElement[] stackElements) {
-        super("Attempt to invoke method with unresolved references");
-        this.methodSnippet = methodSnippet;
+    UnresolvedReferenceException(DeclarationSnippet snippet, StackTraceElement[] stackElements) {
+        super("Attempt to use definition snippet with unresolved references");
+        this.snippet = snippet;
         this.setStackTrace(stackElements);
     }
 
     /**
-     * Return the method Snippet which has the unresolved reference(s).
-     * @return the <code>MethodSnippet</code> of the
+     * Return the Snippet which has the unresolved reference(s).
+     * @return the <code>Snippet</code> of the
      * {@link jdk.jshell.Snippet.Status#RECOVERABLE_DEFINED RECOVERABLE_DEFINED}
-     * method.
+     * definition snippet.
      */
-    public MethodSnippet getMethodSnippet() {
-        return methodSnippet;
+    public DeclarationSnippet getSnippet() {
+        return snippet;
     }
 }
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java	Thu Mar 10 09:51:46 2016 -0800
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java	Thu Mar 10 14:47:14 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -27,6 +27,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import com.sun.source.tree.Tree;
 import static jdk.internal.jshell.remote.RemoteCodes.DOIT_METHOD_NAME;
 
 /**
@@ -58,9 +59,18 @@
         return methodWrap("", source, "");
     }
 
-    public static Wrap corralledMethod(String source, Range modRange, Range tpRange, Range typeRange, String name, Range paramRange, Range throwsRange, int id) {
+    private static String indent(int n) {
+        return "                              ".substring(0, n * 4);
+    }
+
+    private static String nlindent(int n) {
+        return "\n" + indent(n);
+    }
+
+    public static Wrap corralledMethod(String source, Range modRange, Range tpRange,
+            Range typeRange, String name, Range paramRange, Range throwsRange, int id, int indent) {
         List<Object> l = new ArrayList<>();
-        l.add("    public static\n    ");
+        l.add(indent(indent) + ((indent == 1) ? "public static" + nlindent(indent) : ""));
         if (!modRange.isEmpty()) {
             l.add(new RangeWrap(source, modRange));
             l.add(" ");
@@ -70,17 +80,81 @@
             l.add(new RangeWrap(source, tpRange));
             l.add("> ");
         }
-        l.add(new RangeWrap(source, typeRange));
-        l.add(" " + name + "(\n        ");
-        if (paramRange != null) {
+        if (!typeRange.isEmpty()) {
+            l.add(new RangeWrap(source, typeRange));
+            l.add(" ");
+        }
+        l.add(name + "(");
+        if (paramRange != null && !paramRange.isEmpty()) {
+            l.add(nlindent(indent + 1));
             l.add(new RangeWrap(source, paramRange));
         }
-        l.add(") ");
+        l.add(")");
         if (throwsRange != null) {
-            l.add("throws ");
+            l.add(" throws ");
             l.add(new RangeWrap(source, throwsRange));
         }
-        l.add(" {\n        throw new jdk.internal.jshell.remote.RemoteResolutionException(" + id + ");\n}\n");
+        l.add(" {"
+                + nlindent(indent+1)
+                + "throw new jdk.internal.jshell.remote.RemoteResolutionException(" + id + ");"
+                + nlindent(indent)
+                + "}\n");
+        return new CompoundWrap(l.toArray());
+    }
+
+    public static Wrap corralledType(String source, Range modRange, Tree.Kind kind, String name, Range tpRange,
+            Range extendsRange, List<Range> implementsRanges, List<Wrap> members,
+            boolean defaultConstructor, int id, int indent) {
+        boolean isInterface = kind == Tree.Kind.INTERFACE;
+        List<Object> l = new ArrayList<>();
+        l.add(indent(indent) + ((indent == 1) ? "public static" + nlindent(indent) : ""));
+        if (!modRange.isEmpty()) {
+            l.add(new RangeWrap(source, modRange));
+            l.add(" ");
+        }
+        l.add((isInterface ? "interface " : "class ") + name);
+        if (tpRange != null) {
+            l.add("<");
+            l.add(new RangeWrap(source, tpRange));
+            l.add("> ");
+        }
+        if (extendsRange != null && !extendsRange.isEmpty()) {
+            l.add(" extends ");
+            l.add(new RangeWrap(source, extendsRange));
+        }
+        for (int i = 0; i < implementsRanges.size(); ++i) {
+            Range ir = implementsRanges.get(i);
+            l.add(i == 0 ? " implements " : ", ");
+            l.add(new RangeWrap(source, ir));
+        }
+        if (defaultConstructor) {
+            l.add(" {"
+                + nlindent(indent+1)
+                + ((indent == 1)? "public " : "") + name + "()  {"
+                + nlindent(indent+2)
+                + "throw new jdk.internal.jshell.remote.RemoteResolutionException(" + id + ");"
+                + nlindent(indent+1)
+                + "}\n");
+        } else {
+            l.add(" {\n");
+        }
+        l.addAll(members);
+        l.add(indent(indent) + "}\n");
+        return new CompoundWrap(l.toArray());
+    }
+
+    public static Wrap corralledVar(String source, Range modRange, Range typeRange, String brackets, Range nameRange, int indent) {
+        RangeWrap wname = new RangeWrap(source, nameRange);
+        List<Object> l = new ArrayList<>();
+        l.add(indent(indent) + ((indent == 1) ? "public static" + nlindent(indent) : ""));
+        if (!modRange.isEmpty()) {
+            l.add(new RangeWrap(source, modRange));
+            l.add(" ");
+        }
+        l.add(new RangeWrap(source, typeRange));
+        l.add(" ");
+        l.add(wname);
+        l.add(semi(wname));
         return new CompoundWrap(l.toArray());
     }
 
--- a/langtools/test/jdk/jshell/ClassesTest.java	Thu Mar 10 09:51:46 2016 -0800
+++ b/langtools/test/jdk/jshell/ClassesTest.java	Thu Mar 10 14:47:14 2016 -0800
@@ -43,12 +43,13 @@
 import jdk.jshell.Diag;
 import static jdk.jshell.Snippet.Status.VALID;
 import static jdk.jshell.Snippet.Status.RECOVERABLE_NOT_DEFINED;
+import static jdk.jshell.Snippet.Status.RECOVERABLE_DEFINED;
 import static jdk.jshell.Snippet.Status.DROPPED;
 import static jdk.jshell.Snippet.Status.REJECTED;
+import static jdk.jshell.Snippet.Status.OVERWRITTEN;
 import static jdk.jshell.Snippet.SubKind.*;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertTrue;
-import static jdk.jshell.Snippet.Status.OVERWRITTEN;
 
 @Test
 public class ClassesTest extends KullaTesting {
@@ -82,10 +83,10 @@
         TypeDeclSnippet c1 = (TypeDeclSnippet) assertDeclareFail("class A { void f() { return g(); } }", "compiler.err.prob.found.req");
         assertTypeDeclSnippet(c1, "A", REJECTED, CLASS_SUBKIND, 0, 2);
         TypeDeclSnippet c2 = classKey(assertEval("class A { int f() { return g(); } }",
-                ste(c1, REJECTED, RECOVERABLE_NOT_DEFINED, false, null)));
-        assertTypeDeclSnippet(c2, "A", RECOVERABLE_NOT_DEFINED, CLASS_SUBKIND, 1, 0);
+                ste(c1, REJECTED, RECOVERABLE_DEFINED, true, null)));
+        assertTypeDeclSnippet(c2, "A", RECOVERABLE_DEFINED, CLASS_SUBKIND, 1, 0);
         assertDrop(c2,
-                ste(c2, RECOVERABLE_NOT_DEFINED, DROPPED, false, null));
+                ste(c2, RECOVERABLE_DEFINED, DROPPED, true, null));
     }
 
     public void classDeclaration() {
--- a/langtools/test/jdk/jshell/DropTest.java	Thu Mar 10 09:51:46 2016 -0800
+++ b/langtools/test/jdk/jshell/DropTest.java	Thu Mar 10 14:47:14 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8081431
+ * @bug 8081431 8080069
  * @summary Test of JShell#drop().
  * @build KullaTesting TestingInputStream
  * @run testng DropTest
@@ -31,6 +31,7 @@
 
 import jdk.jshell.DeclarationSnippet;
 import jdk.jshell.PersistentSnippet;
+import jdk.jshell.VarSnippet;
 import org.testng.annotations.Test;
 
 import static jdk.jshell.Snippet.Status.*;
@@ -45,21 +46,27 @@
         assertDrop(var,
                 ste(var, VALID, DROPPED, true, null),
                 ste(method, VALID, RECOVERABLE_DEFINED, false, var));
-        //assertDrop(method,
-        //        ste(method, RECOVERABLE_DEFINED, DROPPED, false, null),
-        //        ste(clazz, RECOVERABLE_NOT_DEFINED, RECOVERABLE_NOT_DEFINED, false, method));
-        //assertDeclareFail("new C();", "compiler.err.cant.resolve.location");
+        assertDrop(method,
+                ste(method, RECOVERABLE_DEFINED, DROPPED, true, null),
+                ste(clazz, VALID, RECOVERABLE_DEFINED, false, method));
+        VarSnippet cc = varKey(assertEval("C c;"));
+        assertEvalUnresolvedException("new C();", "C", 1, 0);
         assertVariables();
         assertMethods();
         assertClasses();
         assertActiveKeys();
 
+        method = methodKey(assertEval("int mu() { return x * 4; }",
+                ste(MAIN_SNIPPET, DROPPED, RECOVERABLE_DEFINED, true, null),
+                ste(clazz, RECOVERABLE_DEFINED, VALID, false, MAIN_SNIPPET)));
         assertEval("int x = 10;", "10",
-                ste(var, DROPPED, VALID, true, null),
+                ste(MAIN_SNIPPET, DROPPED, VALID, true, null),
                 ste(method, RECOVERABLE_DEFINED, VALID, false, MAIN_SNIPPET));
         PersistentSnippet c0 = varKey(assertEval("C c0 = new C();"));
         assertEval("c0.v();", "\"#40\"");
-        assertEval("C c = new C();");
+        assertEval("C c = new C();",
+                ste(MAIN_SNIPPET, VALID, VALID, false, null),
+                ste(cc, VALID, OVERWRITTEN, false, MAIN_SNIPPET));
         assertEval("c.v();", "\"#40\"");
         assertEval("int mu() { return x * 3; }",
                 ste(MAIN_SNIPPET, VALID, VALID, false, null),
@@ -144,9 +151,10 @@
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 ste(x, VALID, DROPPED, true, null),
-                ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, x));
-        assertUnresolvedDependencies1(a, RECOVERABLE_NOT_DEFINED, "variable x");
-        assertDeclareFail("new A().a;", "compiler.err.cant.resolve.location");
+                ste(a, VALID, RECOVERABLE_DEFINED, false, x));
+        assertEval("A foo() { return null; }");
+        assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "variable x");
+        assertEvalUnresolvedException("new A();", "A", 1, 0);
         assertVariables();
         assertActiveKeys();
     }
@@ -158,9 +166,9 @@
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 ste(x, VALID, DROPPED, true, null),
-                ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, x));
-        assertUnresolvedDependencies1(a, RECOVERABLE_NOT_DEFINED, "method x()");
-        assertDeclareFail("new A().a;", "compiler.err.cant.resolve.location");
+                ste(a, VALID, RECOVERABLE_DEFINED, false, x));
+        assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "method x()");
+        assertEvalUnresolvedException("new A();", "A", 1, 0);
         assertMethods();
         assertActiveKeys();
     }
--- a/langtools/test/jdk/jshell/KullaTesting.java	Thu Mar 10 09:51:46 2016 -0800
+++ b/langtools/test/jdk/jshell/KullaTesting.java	Thu Mar 10 14:47:14 2016 -0800
@@ -191,14 +191,14 @@
         return key;
     }
 
-    public MethodSnippet assertEvalUnresolvedException(String input, String name, int unresolvedSize, int diagnosticsSize) {
+    public DeclarationSnippet assertEvalUnresolvedException(String input, String name, int unresolvedSize, int diagnosticsSize) {
         List<SnippetEvent> events = assertEval(input, null, UnresolvedReferenceException.class, DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, null);
         SnippetEvent ste = events.get(0);
-        MethodSnippet methodKey = ((UnresolvedReferenceException) ste.exception()).getMethodSnippet();
-        assertEquals(methodKey.name(), name, "Given input: " + input + ", checking name");
-        assertEquals(getState().unresolvedDependencies(methodKey).size(), unresolvedSize, "Given input: " + input + ", checking unresolved");
-        assertEquals(getState().diagnostics(methodKey).size(), diagnosticsSize, "Given input: " + input + ", checking diagnostics");
-        return methodKey;
+        DeclarationSnippet sn = ((UnresolvedReferenceException) ste.exception()).getSnippet();
+        assertEquals(sn.name(), name, "Given input: " + input + ", checking name");
+        assertEquals(getState().unresolvedDependencies(sn).size(), unresolvedSize, "Given input: " + input + ", checking unresolved");
+        assertEquals(getState().diagnostics(sn).size(), diagnosticsSize, "Given input: " + input + ", checking diagnostics");
+        return sn;
     }
 
     public Snippet assertKeyMatch(String input, boolean isExecutable, SubKind expectedSubKind, STEInfo mainInfo, STEInfo... updates) {
--- a/langtools/test/jdk/jshell/ReplaceTest.java	Thu Mar 10 09:51:46 2016 -0800
+++ b/langtools/test/jdk/jshell/ReplaceTest.java	Thu Mar 10 14:47:14 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -22,7 +22,7 @@
  */
 
 /*
- * @test
+ * @test 8080069
  * @summary Test of Snippet redefinition and replacement.
  * @build KullaTesting TestingInputStream
  * @run testng ReplaceTest
@@ -30,6 +30,7 @@
 
 import java.util.Collection;
 
+import java.util.List;
 import jdk.jshell.Snippet;
 import jdk.jshell.MethodSnippet;
 import jdk.jshell.PersistentSnippet;
@@ -38,9 +39,11 @@
 import jdk.jshell.DeclarationSnippet;
 import org.testng.annotations.Test;
 
+import jdk.jshell.SnippetEvent;
+import jdk.jshell.UnresolvedReferenceException;
+import static org.testng.Assert.assertEquals;
 import static jdk.jshell.Snippet.Status.*;
 import static jdk.jshell.Snippet.SubKind.*;
-import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertTrue;
 
 @Test
@@ -259,7 +262,7 @@
                 ste(MAIN_SNIPPET, VALID, VALID, true, null),
                 ste(g, VALID, OVERWRITTEN, false, MAIN_SNIPPET),
                 ste(f, VALID, RECOVERABLE_DEFINED, false, MAIN_SNIPPET));
-        MethodSnippet exsn = assertEvalUnresolvedException("t();", "f", 0, 1);
+        DeclarationSnippet exsn = assertEvalUnresolvedException("t();", "f", 0, 1);
         assertTrue(exsn == f, "Identity must not change");
         assertActiveKeys();
     }
@@ -289,13 +292,95 @@
     }
 
     public void testForwardVarToClass() {
-        DeclarationSnippet a = classKey(assertEval("class A { int f() { return g; } }", added(RECOVERABLE_NOT_DEFINED)));
-        assertUnresolvedDependencies1(a, RECOVERABLE_NOT_DEFINED, "variable g");
+        DeclarationSnippet a = classKey(assertEval("class A { int f() { return g; } }", added(RECOVERABLE_DEFINED)));
+        assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "variable g");
+        Snippet g = varKey(assertEval("int g = 10;", "10",
+                added(VALID),
+                ste(a, RECOVERABLE_DEFINED, VALID, false, null)));
+        assertEval("new A().f();", "10");
+        assertEval("double g = 10;", "10.0", null,
+                DiagCheck.DIAG_OK,
+                DiagCheck.DIAG_ERROR,
+                ste(MAIN_SNIPPET, VALID, VALID, true, null),
+                ste(g, VALID, OVERWRITTEN, false, MAIN_SNIPPET),
+                ste(a, VALID, RECOVERABLE_DEFINED, false, MAIN_SNIPPET));
+        assertUnresolvedDependencies(a, 0);
+        assertActiveKeys();
+    }
+
+    public void testForwardVarToClassGeneric() {
+        DeclarationSnippet a = classKey(assertEval("class A<T> { final T x; A(T v) { this.x = v; } ; T get() { return x; } int core() { return g; } }", added(RECOVERABLE_DEFINED)));
+        assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "variable g");
+
+        List<SnippetEvent> events = assertEval("A<String> as = new A<>(\"hi\");", null,
+                UnresolvedReferenceException.class, DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, null);
+        SnippetEvent ste = events.get(0);
+        Snippet assn = ste.snippet();
+        DeclarationSnippet unsn = ((UnresolvedReferenceException) ste.exception()).getSnippet();
+        assertEquals(unsn.name(), "A", "Wrong with unresolved");
+        assertEquals(getState().unresolvedDependencies(unsn).size(), 1, "Wrong size unresolved");
+        assertEquals(getState().diagnostics(unsn).size(), 0, "Expected no diagnostics");
+
         Snippet g = varKey(assertEval("int g = 10;", "10",
                 added(VALID),
+                ste(a, RECOVERABLE_DEFINED, VALID, false, MAIN_SNIPPET)));
+        assertEval("A<String> as = new A<>(\"low\");",
+                ste(MAIN_SNIPPET, VALID, VALID, false, null),
+                ste(assn, VALID, OVERWRITTEN, false, MAIN_SNIPPET));
+        assertEval("as.get();", "\"low\"");
+        assertUnresolvedDependencies(a, 0);
+        assertActiveKeys();
+    }
+
+   public void testForwardVarToClassExtendsImplements() {
+        DeclarationSnippet ik = classKey(assertEval("interface I { default int ii() { return 1; } }", added(VALID)));
+        DeclarationSnippet jk = classKey(assertEval("interface J { default int jj() { return 2; } }", added(VALID)));
+        DeclarationSnippet ck = classKey(assertEval("class C { int cc() { return 3; } }", added(VALID)));
+        DeclarationSnippet dk = classKey(assertEval("class D extends C implements I,J { int dd() { return g; } }", added(RECOVERABLE_DEFINED)));
+        DeclarationSnippet ek = classKey(assertEval("class E extends D { int ee() { return 5; } }", added(VALID)));
+        assertUnresolvedDependencies1(dk, RECOVERABLE_DEFINED, "variable g");
+        assertEvalUnresolvedException("new D();", "D", 1, 0);
+        assertEvalUnresolvedException("new E();", "D", 1, 0);
+        VarSnippet g = varKey(assertEval("int g = 10;", "10",
+                added(VALID),
+                ste(dk, RECOVERABLE_DEFINED, VALID, false, MAIN_SNIPPET)));
+        assertEval("E e = new E();");
+        assertDrop(g,
+                ste(g, VALID, DROPPED, true, null),
+                ste(dk, VALID, RECOVERABLE_DEFINED, false, g));
+        assertEvalUnresolvedException("new D();", "D", 1, 0);
+        assertEvalUnresolvedException("new E();", "D", 1, 0);
+        assertEval("e.ee();", "5");
+        assertEvalUnresolvedException("e.dd();", "D", 1, 0);
+        assertEval("e.cc();", "3");
+        assertEval("e.jj();", "2");
+        assertEval("e.ii();", "1");
+        assertActiveKeys();
+    }
+
+    public void testForwardVarToInterface() {
+        DeclarationSnippet i = classKey(assertEval("interface I { default int f() { return x; } }", added(RECOVERABLE_DEFINED)));
+        assertUnresolvedDependencies1(i, RECOVERABLE_DEFINED, "variable x");
+        DeclarationSnippet c = classKey(assertEval("class C implements I { int z() { return 2; } }", added(VALID)));
+        assertEval("C c = new C();");
+        assertEval("c.z();", "2");
+        assertEvalUnresolvedException("c.f()", "I", 1, 0);
+        Snippet g = varKey(assertEval("int x = 55;", "55",
+                added(VALID),
+                ste(i, RECOVERABLE_DEFINED, VALID, false, null)));
+        assertEval("c.f();", "55");
+        assertUnresolvedDependencies(i, 0);
+        assertActiveKeys();
+    }
+
+    public void testForwardVarToEnum() {
+        DeclarationSnippet a = classKey(assertEval("enum E { Q, W, E; float ff() { return fff; } }", added(RECOVERABLE_NOT_DEFINED)));
+        assertUnresolvedDependencies1(a, RECOVERABLE_NOT_DEFINED, "variable fff");
+        Snippet g = varKey(assertEval("float fff = 4.5f;", "4.5",
+                added(VALID),
                 ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null)));
-        assertEval("new A().f();", "10");
-        assertEval("double g = 10;", "10.0", null,
+        assertEval("E.Q.ff();", "4.5");
+        assertEval("double fff = 3.3;", "3.3", null,
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 ste(MAIN_SNIPPET, VALID, VALID, true, null),
@@ -305,20 +390,21 @@
         assertActiveKeys();
     }
 
-
     public void testForwardMethodToClass() {
-        DeclarationSnippet a = classKey(assertEval("class A { int f() { return g(); } }", added(RECOVERABLE_NOT_DEFINED)));
-        assertUnresolvedDependencies1(a, RECOVERABLE_NOT_DEFINED, "method g()");
+        DeclarationSnippet a = classKey(assertEval("class A { int f() { return g(); } }", added(RECOVERABLE_DEFINED)));
+        assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "method g()");
+        assertEval("A foo() { return null; }");
+        assertEvalUnresolvedException("new A();", "A", 1, 0);
         Snippet g = methodKey(assertEval("int g() { return 10; }",
                 added(VALID),
-                ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null)));
+                ste(a, RECOVERABLE_DEFINED, VALID, false, null)));
         assertEval("new A().f();", "10");
         assertEval("double g() { return 10; }",
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 ste(MAIN_SNIPPET, VALID, VALID, true, null),
                 ste(g, VALID, OVERWRITTEN, false, MAIN_SNIPPET),
-                ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, MAIN_SNIPPET));
+                ste(a, VALID, RECOVERABLE_DEFINED, false, MAIN_SNIPPET));
         assertUnresolvedDependencies(a, 0);
         assertActiveKeys();
     }
@@ -336,8 +422,8 @@
                 DiagCheck.DIAG_ERROR,
                 ste(MAIN_SNIPPET, VALID, VALID, true, null),
                 ste(b, VALID, OVERWRITTEN, false, MAIN_SNIPPET),
-                ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, MAIN_SNIPPET));
-        assertDeclareFail("new A().b;", "compiler.err.cant.resolve.location");
+                ste(a, VALID, RECOVERABLE_DEFINED, true, MAIN_SNIPPET));
+        assertEvalUnresolvedException("new A().b;", "A", 0, 1);
         assertActiveKeys();
     }
 
@@ -503,42 +589,42 @@
 
     public void testForwardSingleImportMethodToClass1() {
         PersistentSnippet a = classKey(assertEval("class A { String s = format(\"%d\", 10); }",
-                added(RECOVERABLE_NOT_DEFINED)));
-        assertDeclareFail("new A();", "compiler.err.cant.resolve.location");
+                added(RECOVERABLE_DEFINED)));
+        assertEvalUnresolvedException("new A();", "A", 1, 0);
         assertEval("import static java.lang.String.format;",
                 added(VALID),
-                ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null));
+                ste(a, RECOVERABLE_DEFINED, VALID, false, null));
         assertEval("new A().s;", "\"10\"");
         PersistentSnippet format = methodKey(assertEval("void format(String s, int d) { }",
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 added(VALID),
-                ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, MAIN_SNIPPET)));
-        assertDeclareFail("new A().s;", "compiler.err.cant.resolve.location");
+                ste(a, VALID, RECOVERABLE_DEFINED, false, MAIN_SNIPPET)));
+        assertEvalUnresolvedException("new A();", "A", 0, 1);
         assertActiveKeys();
         assertDrop(format,
                 ste(format, VALID, DROPPED, true, null),
-                ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, format));
+                ste(a, RECOVERABLE_DEFINED, VALID, false, format));
     }
 
     public void testForwardSingleImportMethodToClass2() {
         PersistentSnippet a = classKey(assertEval("class A { String s() { return format(\"%d\", 10); } }",
-                added(RECOVERABLE_NOT_DEFINED)));
-        assertDeclareFail("new A();", "compiler.err.cant.resolve.location");
+                added(RECOVERABLE_DEFINED)));
+        assertEvalUnresolvedException("new A();", "A", 1, 0);
         assertEval("import static java.lang.String.format;",
                 added(VALID),
-                ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null));
+                ste(a, RECOVERABLE_DEFINED, VALID, false, null));
         assertEval("new A().s();", "\"10\"");
         PersistentSnippet format = methodKey(assertEval("void format(String s, int d) { }",
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 added(VALID),
-                ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, null)));
-        assertDeclareFail("new A().s();", "compiler.err.cant.resolve.location");
+                ste(a, VALID, RECOVERABLE_DEFINED, false, null)));
+        assertEvalUnresolvedException("new A();", "A", 0, 1);
         assertActiveKeys();
         assertDrop(format,
                 ste(format, VALID, DROPPED, true, null),
-                ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, format));
+                ste(a, RECOVERABLE_DEFINED, VALID, false, format));
     }
 
     public void testForwardSingleImportClassToClass1() {
@@ -589,42 +675,44 @@
 
     public void testForwardImportOnDemandMethodToClass1() {
         PersistentSnippet a = classKey(assertEval("class A { String s = format(\"%d\", 10); }",
-                added(RECOVERABLE_NOT_DEFINED)));
-        assertDeclareFail("new A();", "compiler.err.cant.resolve.location");
+                added(RECOVERABLE_DEFINED)));
+        assertEvalUnresolvedException("new A();", "A", 1, 0);
         assertEval("import static java.lang.String.*;",
                 added(VALID),
-                ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null));
-        assertEval("new A().s;", "\"10\"");
+                ste(a, RECOVERABLE_DEFINED, VALID, false, null));
+        assertEval("A x = new A();");
+        assertEval("x.s;", "\"10\"");
         PersistentSnippet format = methodKey(assertEval("void format(String s, int d) { }",
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 added(VALID),
-                ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, null)));
-        assertDeclareFail("new A().s;", "compiler.err.cant.resolve.location");
+                ste(a, VALID, RECOVERABLE_DEFINED, false, null)));
+        assertEvalUnresolvedException("new A();", "A", 0, 1);
         assertActiveKeys();
         assertDrop(format,
                 ste(format, VALID, DROPPED, true, null),
-                ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, format));
+                ste(a, RECOVERABLE_DEFINED, VALID, false, format));
+        assertEval("x.s;", "\"10\"");
     }
 
     public void testForwardImportOnDemandMethodToClass2() {
         PersistentSnippet a = classKey(assertEval("class A { String s() { return format(\"%d\", 10); } }",
-                added(RECOVERABLE_NOT_DEFINED)));
-        assertDeclareFail("new A();", "compiler.err.cant.resolve.location");
+                added(RECOVERABLE_DEFINED)));
+        assertEvalUnresolvedException("new A();", "A", 1, 0);
         assertEval("import static java.lang.String.*;",
                 added(VALID),
-                ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null));
+                ste(a, RECOVERABLE_DEFINED, VALID, false, null));
         assertEval("new A().s();", "\"10\"");
         PersistentSnippet format = methodKey(assertEval("void format(String s, int d) { }",
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 added(VALID),
-                ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, null)));
-        assertDeclareFail("new A().s();", "compiler.err.cant.resolve.location");
+                ste(a, VALID, RECOVERABLE_DEFINED, false, null)));
+        assertEvalUnresolvedException("new A();", "A", 0, 1);
         assertActiveKeys();
         assertDrop(format,
                 ste(format, VALID, DROPPED, true, null),
-                ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, format));
+                ste(a, RECOVERABLE_DEFINED, VALID, false, format));
     }
 
     public void testForwardImportOnDemandClassToClass1() {
@@ -673,86 +761,87 @@
 
     public void testForwardSingleImportFieldToClass1() {
         PersistentSnippet a = classKey(assertEval("class A { static double pi() { return PI; } }",
-                added(RECOVERABLE_NOT_DEFINED)));
-        assertDeclareFail("new A();", "compiler.err.cant.resolve.location");
+                added(RECOVERABLE_DEFINED)));
+        assertEvalUnresolvedException("new A();", "A", 1, 0);
         assertEval("import static java.lang.Math.PI;",
                 added(VALID),
-                ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null));
+                ste(a, RECOVERABLE_DEFINED, VALID, false, null));
         assertEval("Math.abs(A.pi() - 3.1415) < 0.001;", "true");
 
         PersistentSnippet list = varKey(assertEval("String PI;",
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 added(VALID),
-                ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, null)));
-        assertDeclareFail("new A();", "compiler.err.cant.resolve.location");
+                ste(a, VALID, RECOVERABLE_DEFINED, false, null)));
+        assertEvalUnresolvedException("new A();", "A", 0, 1);
         assertActiveKeys();
         assertDrop(list,
                 ste(list, VALID, DROPPED, true, null),
-                ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, list));
+                ste(a, RECOVERABLE_DEFINED, VALID, false, list));
     }
 
     public void testForwardSingleImportFieldToClass2() {
         PersistentSnippet a = classKey(assertEval("class A { static double pi = PI; }",
-                added(RECOVERABLE_NOT_DEFINED)));
-        assertDeclareFail("new A();", "compiler.err.cant.resolve.location");
+                added(RECOVERABLE_DEFINED)));
+        assertEvalUnresolvedException("new A();", "A", 1, 0);
         assertEval("import static java.lang.Math.PI;",
                 added(VALID),
-                ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null));
+                ste(a, RECOVERABLE_DEFINED, VALID, true, null));
         assertEval("Math.abs(A.pi - 3.1415) < 0.001;", "true");
 
         PersistentSnippet list = varKey(assertEval("String PI;",
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 added(VALID),
-                ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, null)));
-        assertDeclareFail("new A();", "compiler.err.cant.resolve.location");
+                ste(a, VALID, RECOVERABLE_DEFINED, true, null)));
+        assertEvalUnresolvedException("new A();", "A", 0, 1);
         assertActiveKeys();
         assertDrop(list,
                 ste(list, VALID, DROPPED, true, null),
-                ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, list));
+                ste(a, RECOVERABLE_DEFINED, VALID, true, list));
     }
 
     public void testForwardImportOnDemandFieldToClass1() {
         PersistentSnippet a = classKey(assertEval("class A { static double pi() { return PI; } }",
-                added(RECOVERABLE_NOT_DEFINED)));
-        assertDeclareFail("new A();", "compiler.err.cant.resolve.location");
+                added(RECOVERABLE_DEFINED)));
+        assertEvalUnresolvedException("new A();", "A", 1, 0);
         assertEval("import static java.lang.Math.*;",
                 added(VALID),
-                ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null));
+                ste(a, RECOVERABLE_DEFINED, VALID, false, null));
         assertEval("Math.abs(A.pi() - 3.1415) < 0.001;", "true");
 
         PersistentSnippet list = varKey(assertEval("String PI;",
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 added(VALID),
-                ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, null)));
-        assertDeclareFail("new A();", "compiler.err.cant.resolve.location");
+                ste(a, VALID, RECOVERABLE_DEFINED, false, null)));
+        assertEvalUnresolvedException("new A();", "A", 0, 1);
         assertActiveKeys();
         assertDrop(list,
                 ste(list, VALID, DROPPED, true, null),
-                ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, list));
+                ste(a, RECOVERABLE_DEFINED, VALID, false, list));
     }
 
     public void testForwardImportOnDemandFieldToClass2() {
         PersistentSnippet a = classKey(assertEval("class A { static double pi = PI; }",
-                added(RECOVERABLE_NOT_DEFINED)));
-        assertDeclareFail("new A();", "compiler.err.cant.resolve.location");
+                added(RECOVERABLE_DEFINED)));
+        assertEvalUnresolvedException("new A();", "A", 1, 0);
         assertEval("import static java.lang.Math.*;",
                 added(VALID),
-                ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null));
+                ste(a, RECOVERABLE_DEFINED, VALID, true, null));
         assertEval("Math.abs(A.pi - 3.1415) < 0.001;", "true");
 
         PersistentSnippet list = varKey(assertEval("String PI;",
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 added(VALID),
-                ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, null)));
-        assertDeclareFail("new A();", "compiler.err.cant.resolve.location");
+                ste(a, VALID, RECOVERABLE_DEFINED, true, null)));
+        assertEvalUnresolvedException("new A();", "A", 0, 1);
         assertActiveKeys();
         assertDrop(list,
                 ste(list, VALID, DROPPED, true, null),
-                ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, list));
+                ste(a, RECOVERABLE_DEFINED, VALID, true, list));
+        assertEval("Math.abs(A.pi - 3.1415) < 0.001;", "true");
     }
 
     public void testReplaceCausesMethodReferenceError() {