8171981: JShell: Fails compilation: new Object().getClass().getSuperclass()
authorrfield
Mon, 09 Jan 2017 18:04:16 -0800
changeset 43134 006808ae5f6e
parent 43133 08a858022ea6
child 43135 0c7c13fa7bee
8171981: JShell: Fails compilation: new Object().getClass().getSuperclass() Reviewed-by: mcimadamore
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/debug/InternalDebugControl.java
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/ExpressionToTypeInfo.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/TypePrinter.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/VarTypePrinter.java
langtools/test/jdk/jshell/TypeNameTest.java
langtools/test/jdk/jshell/VariablesTest.java
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/debug/InternalDebugControl.java	Mon Jan 09 16:20:48 2017 -0800
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/debug/InternalDebugControl.java	Mon Jan 09 18:04:16 2017 -0800
@@ -68,6 +68,11 @@
      */
     public static final int DBG_EVNT = 0b0010000;
 
+    /**
+     * Event debugging.
+     */
+    public static final int DBG_WRAP = 0b0100000;
+
     private static Map<JShell, Integer> debugMap = null;
 
     /**
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Mon Jan 09 16:20:48 2017 -0800
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Mon Jan 09 18:04:16 2017 -0800
@@ -119,6 +119,7 @@
 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_EVNT;
 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_FMGR;
 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_GEN;
+import static jdk.internal.jshell.debug.InternalDebugControl.DBG_WRAP;
 import static jdk.internal.jshell.tool.ContinuousCompletionProvider.STARTSWITH_MATCHER;
 
 /**
@@ -1919,9 +1920,13 @@
                         flags |= DBG_EVNT;
                         fluff("Event debugging on");
                         break;
+                    case 'w':
+                        flags |= DBG_WRAP;
+                        fluff("Wrap debugging on");
+                        break;
                     default:
                         hard("Unknown debugging option: %c", ch);
-                        fluff("Use: 0 r g f c d");
+                        fluff("Use: 0 r g f c d e w");
                         return false;
                 }
             }
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Mon Jan 09 16:20:48 2017 -0800
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Mon Jan 09 18:04:16 2017 -0800
@@ -49,6 +49,7 @@
 import java.io.Writer;
 import java.util.LinkedHashSet;
 import java.util.Set;
+import jdk.jshell.ExpressionToTypeInfo.ExpressionInfo;
 import jdk.jshell.Key.ErroneousKey;
 import jdk.jshell.Key.MethodKey;
 import jdk.jshell.Key.TypeDeclKey;
@@ -58,7 +59,6 @@
 import jdk.jshell.TaskFactory.BaseTask;
 import jdk.jshell.TaskFactory.CompileTask;
 import jdk.jshell.TaskFactory.ParseTask;
-import jdk.jshell.TreeDissector.ExpressionInfo;
 import jdk.jshell.Wrap.Range;
 import jdk.jshell.Snippet.Status;
 import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
@@ -296,7 +296,7 @@
 
     private List<Snippet> processExpression(String userSource, String compileSource) {
         String name = null;
-        ExpressionInfo ei = typeOfExpression(compileSource);
+        ExpressionInfo ei = ExpressionToTypeInfo.expressionInfo(compileSource, state);
         ExpressionTree assignVar;
         Wrap guts;
         Snippet snip;
@@ -499,16 +499,6 @@
         return singletonList(snip);
     }
 
-    private ExpressionInfo typeOfExpression(String expression) {
-        Wrap guts = Wrap.methodReturnWrap(expression);
-        TaskFactory.AnalyzeTask at = trialCompile(guts);
-        if (!at.hasErrors() && at.firstCuTree() != null) {
-            return TreeDissector.createByFirstClass(at)
-                    .typeOfReturnStatement(at, state);
-        }
-        return null;
-    }
-
     /**
      * Should a temp var wrap the expression. TODO make this user configurable.
      *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExpressionToTypeInfo.java	Mon Jan 09 18:04:16 2017 -0800
@@ -0,0 +1,216 @@
+/*
+ * 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 com.sun.source.tree.ReturnTree;
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.ConditionalExpressionTree;
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.util.TreePath;
+import com.sun.source.util.TreePathScanner;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Types;
+import jdk.jshell.TaskFactory.AnalyzeTask;
+
+/**
+ * Compute information about an expression string, particularly its type name.
+ */
+class ExpressionToTypeInfo {
+
+    private static final String OBJECT_TYPE_NAME = "Object";
+
+    final AnalyzeTask at;
+    final CompilationUnitTree cu;
+    final JShell state;
+    final Symtab syms;
+    final Types types;
+
+    private ExpressionToTypeInfo(AnalyzeTask at, CompilationUnitTree cu, JShell state) {
+        this.at = at;
+        this.cu = cu;
+        this.state = state;
+        this.syms = Symtab.instance(at.context);
+        this.types = Types.instance(at.context);
+    }
+
+    public static class ExpressionInfo {
+        ExpressionTree tree;
+        String typeName;
+        boolean isNonVoid;
+    }
+
+    // return mechanism and other general structure from TreePath.getPath()
+    private static class Result extends Error {
+
+        static final long serialVersionUID = -5942088234594905629L;
+        final TreePath expressionPath;
+
+        Result(TreePath path) {
+            this.expressionPath = path;
+        }
+    }
+
+    private static class PathFinder extends TreePathScanner<TreePath, Boolean> {
+
+        // Optimize out imports etc
+        @Override
+        public TreePath visitCompilationUnit(CompilationUnitTree node, Boolean isTargetContext) {
+            return scan(node.getTypeDecls(), isTargetContext);
+        }
+
+        // Only care about members
+        @Override
+        public TreePath visitClass(ClassTree node, Boolean isTargetContext) {
+            return scan(node.getMembers(), isTargetContext);
+        }
+
+        // Only want the doit method where the code is
+        @Override
+        public TreePath visitMethod(MethodTree node, Boolean isTargetContext) {
+            if (Util.isDoIt(node.getName())) {
+                return scan(node.getBody(), true);
+            } else {
+                return null;
+            }
+        }
+
+        @Override
+        public TreePath visitReturn(ReturnTree node, Boolean isTargetContext) {
+            ExpressionTree tree = node.getExpression();
+            TreePath tp = new TreePath(getCurrentPath(), tree);
+            if (isTargetContext) {
+                throw new Result(tp);
+            } else {
+                return null;
+            }
+        }
+    }
+
+    private Type pathToType(TreePath tp) {
+        return (Type) at.trees().getTypeMirror(tp);
+    }
+
+    private Type pathToType(TreePath tp, Tree tree) {
+        if (tree instanceof ConditionalExpressionTree) {
+            // Conditionals always wind up as Object -- this corrects
+            ConditionalExpressionTree cet = (ConditionalExpressionTree) tree;
+            Type tmt = pathToType(new TreePath(tp, cet.getTrueExpression()));
+            Type tmf = pathToType(new TreePath(tp, cet.getFalseExpression()));
+            if (!tmt.isPrimitive() && !tmf.isPrimitive()) {
+                Type lub = types.lub(tmt, tmf);
+                // System.err.printf("cond ? %s : %s  --  lub = %s\n",
+                //             varTypeName(tmt), varTypeName(tmf), varTypeName(lub));
+                return lub;
+            }
+        }
+        return pathToType(tp);
+    }
+
+    /**
+     * Entry method: get expression info
+     * @param code the expression as a string
+     * @param state a JShell instance
+     * @return type information
+     */
+    public static ExpressionInfo expressionInfo(String code, JShell state) {
+        if (code == null || code.isEmpty()) {
+            return null;
+        }
+        try {
+            OuterWrap codeWrap = state.outerMap.wrapInTrialClass(Wrap.methodReturnWrap(code));
+            AnalyzeTask at = state.taskFactory.new AnalyzeTask(codeWrap);
+            CompilationUnitTree cu = at.firstCuTree();
+            if (at.hasErrors() || cu == null) {
+                return null;
+            }
+            return new ExpressionToTypeInfo(at, cu, state).typeOfExpression();
+        } catch (Exception ex) {
+            return null;
+        }
+    }
+
+    private ExpressionInfo typeOfExpression() {
+        return treeToInfo(findExpressionPath());
+    }
+
+    private TreePath findExpressionPath() {
+        try {
+            new PathFinder().scan(new TreePath(cu), false);
+        } catch (Result result) {
+            return result.expressionPath;
+        }
+        return null;
+    }
+
+    private ExpressionInfo treeToInfo(TreePath tp) {
+        if (tp != null) {
+            Tree tree = tp.getLeaf();
+            if (tree instanceof ExpressionTree) {
+                ExpressionInfo ei = new ExpressionInfo();
+                ei.tree = (ExpressionTree) tree;
+                Type type = pathToType(tp, tree);
+                if (type != null) {
+                    switch (type.getKind()) {
+                        case VOID:
+                        case NONE:
+                        case ERROR:
+                        case OTHER:
+                            break;
+                        case NULL:
+                            ei.isNonVoid = true;
+                            ei.typeName = OBJECT_TYPE_NAME;
+                            break;
+                        default: {
+                            ei.isNonVoid = true;
+                            ei.typeName = varTypeName(type);
+                            if (ei.typeName == null) {
+                                ei.typeName = OBJECT_TYPE_NAME;
+                            }
+                            break;
+                        }
+                    }
+                }
+                return ei;
+            }
+        }
+        return null;
+    }
+
+    private String varTypeName(Type type) {
+        try {
+            TypePrinter tp = new VarTypePrinter(at.messages(),
+                    state.maps::fullClassNameAndPackageToClass, syms, types);
+            return tp.toString(type);
+        } catch (Exception ex) {
+            return null;
+        }
+    }
+
+}
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java	Mon Jan 09 16:20:48 2017 -0800
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java	Mon Jan 09 18:04:16 2017 -0800
@@ -105,7 +105,6 @@
 import java.util.stream.Collectors;
 
 import static java.util.stream.Collectors.collectingAndThen;
-import static java.util.stream.Collectors.joining;
 import static java.util.stream.Collectors.toCollection;
 import static java.util.stream.Collectors.toList;
 import static java.util.stream.Collectors.toSet;
@@ -128,6 +127,7 @@
 import javax.tools.JavaFileManager.Location;
 import javax.tools.StandardLocation;
 
+import jdk.jshell.ExpressionToTypeInfo.ExpressionInfo;
 import static jdk.jshell.Util.REPL_DOESNOTMATTER_CLASS_NAME;
 import static jdk.jshell.SourceCodeAnalysis.Completeness.DEFINITELY_INCOMPLETE;
 import static jdk.jshell.TreeDissector.printType;
@@ -1430,47 +1430,17 @@
 
     @Override
     public String analyzeType(String code, int cursor) {
-        code = code.substring(0, cursor);
-        CompletionInfo completionInfo = analyzeCompletion(code);
-        if (!completionInfo.completeness().isComplete())
-            return null;
-        if (completionInfo.completeness() == Completeness.COMPLETE_WITH_SEMI) {
-            code += ";";
-        }
-
-        OuterWrap codeWrap;
         switch (guessKind(code)) {
             case IMPORT: case METHOD: case CLASS: case ENUM:
             case INTERFACE: case ANNOTATION_TYPE: case VARIABLE:
                 return null;
             default:
-                codeWrap = proc.outerMap.wrapInTrialClass(Wrap.methodWrap(code));
                 break;
         }
-        AnalyzeTask at = proc.taskFactory.new AnalyzeTask(codeWrap);
-        SourcePositions sp = at.trees().getSourcePositions();
-        CompilationUnitTree topLevel = at.firstCuTree();
-        int pos = codeWrap.snippetIndexToWrapIndex(code.length());
-        TreePath tp = pathFor(topLevel, sp, pos);
-        while (ExpressionTree.class.isAssignableFrom(tp.getParentPath().getLeaf().getKind().asInterface()) &&
-               tp.getParentPath().getLeaf().getKind() != Kind.ERRONEOUS &&
-               tp.getParentPath().getParentPath() != null)
-            tp = tp.getParentPath();
-        TypeMirror type = at.trees().getTypeMirror(tp);
-
-        if (type == null)
-            return null;
-
-        switch (type.getKind()) {
-            case ERROR: case NONE: case OTHER:
-            case PACKAGE: case VOID:
-                return null; //not usable
-            case NULL:
-                type = at.getElements().getTypeElement("java.lang.Object").asType();
-                break;
-        }
-
-        return TreeDissector.printType(at, proc, type);
+        ExpressionInfo ei = ExpressionToTypeInfo.expressionInfo(code, proc);
+        return (ei == null || !ei.isNonVoid)
+                ? null
+                : ei.typeName;
     }
 
     @Override
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java	Mon Jan 09 16:20:48 2017 -0800
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java	Mon Jan 09 18:04:16 2017 -0800
@@ -321,7 +321,7 @@
         final JavacTaskImpl task;
         private DiagList diags = null;
         private final SourceHandler<?> sourceHandler;
-        private final Context context = new Context();
+        final Context context = new Context();
         private Types types;
         private JavacMessages messages;
         private Trees trees;
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java	Mon Jan 09 16:20:48 2017 -0800
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java	Mon Jan 09 18:04:16 2017 -0800
@@ -28,14 +28,11 @@
 
 import com.sun.source.tree.ClassTree;
 import com.sun.source.tree.CompilationUnitTree;
-import com.sun.source.tree.ExpressionTree;
 import com.sun.source.tree.MethodTree;
-import com.sun.source.tree.ReturnTree;
 import com.sun.source.tree.StatementTree;
 import com.sun.source.tree.Tree;
 import com.sun.source.tree.VariableTree;
 import com.sun.source.util.SourcePositions;
-import com.sun.source.util.TreePath;
 import com.sun.source.util.Trees;
 import com.sun.tools.javac.code.Type;
 import com.sun.tools.javac.code.Type.MethodType;
@@ -47,7 +44,6 @@
 import jdk.jshell.Wrap.Range;
 
 import java.util.List;
-import java.util.Locale;
 
 import java.util.function.Predicate;
 import java.util.stream.Stream;
@@ -61,16 +57,6 @@
 
 class TreeDissector {
 
-    private static final String OBJECT_TYPE = "Object";
-
-    static class ExpressionInfo {
-
-        boolean isNonVoid;
-        String typeName;
-        ExpressionTree tree;
-        String signature;
-    }
-
     private final TaskFactory.BaseTask bt;
     private final ClassTree targetClass;
     private final CompilationUnitTree targetCompilationUnit;
@@ -219,41 +205,6 @@
         return null;
     }
 
-
-    ExpressionInfo typeOfReturnStatement(AnalyzeTask at, JShell state) {
-        ExpressionInfo ei = new ExpressionInfo();
-        Tree unitTree = firstStatement();
-        if (unitTree instanceof ReturnTree) {
-            ei.tree = ((ReturnTree) unitTree).getExpression();
-            if (ei.tree != null) {
-                TreePath viPath = trees().getPath(targetCompilationUnit, ei.tree);
-                if (viPath != null) {
-                    TypeMirror tm = trees().getTypeMirror(viPath);
-                    if (tm != null) {
-                        ei.typeName = printType(at, state, tm);
-                        switch (tm.getKind()) {
-                            case VOID:
-                            case NONE:
-                            case ERROR:
-                            case OTHER:
-                                break;
-                            case NULL:
-                                ei.isNonVoid = true;
-                                ei.typeName = OBJECT_TYPE;
-                                break;
-                            default: {
-                                ei.isNonVoid = true;
-                                break;
-
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        return ei;
-    }
-
     String typeOfMethod(MethodSnippet msn) {
         Tree unitTree = method(msn);
         if (unitTree instanceof JCMethodDecl) {
@@ -274,8 +225,13 @@
 
     public static String printType(AnalyzeTask at, JShell state, TypeMirror type) {
         Type typeImpl = (Type) type;
-        TypePrinter tp = new TypePrinter(at.messages(), state.maps::fullClassNameAndPackageToClass, typeImpl);
-        return tp.visit(typeImpl, Locale.getDefault());
+        try {
+            TypePrinter tp = new TypePrinter(at.messages(),
+                    state.maps::fullClassNameAndPackageToClass);
+            return tp.toString(typeImpl);
+        } catch (Exception ex) {
+            return null;
+        }
     }
 
     /**
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TypePrinter.java	Mon Jan 09 16:20:48 2017 -0800
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TypePrinter.java	Mon Jan 09 18:04:16 2017 -0800
@@ -22,7 +22,6 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-
 package jdk.jshell;
 
 import static com.sun.tools.javac.code.Flags.COMPOUND;
@@ -41,17 +40,21 @@
  * Print types in source form.
  */
 class TypePrinter extends Printer {
+
     private static final String OBJECT = "Object";
 
     private final JavacMessages messages;
     private final BinaryOperator<String> fullClassNameAndPackageToClass;
-    private boolean useWildCard = false;
 
-    TypePrinter(JavacMessages messages, BinaryOperator<String> fullClassNameAndPackageToClass, Type typeToPrint) {
+    TypePrinter(JavacMessages messages, BinaryOperator<String> fullClassNameAndPackageToClass) {
         this.messages = messages;
         this.fullClassNameAndPackageToClass = fullClassNameAndPackageToClass;
     }
 
+    String toString(Type t) {
+        return visit(t, Locale.getDefault());
+    }
+
     @Override
     protected String localize(Locale locale, String key, Object... args) {
         return messages.getLocalizedString(locale, key, args);
@@ -68,18 +71,6 @@
     }
 
     @Override
-    public String visitWildcardType(Type.WildcardType wt, Locale locale) {
-        if (useWildCard) { // at TypeArgument(ex: List<? extends T>)
-            return super.visitWildcardType(wt, locale);
-        } else { // at TopLevelType(ex: ? extends List<T>, ? extends Number[][])
-            Type extendsBound = wt.getExtendsBound();
-            return extendsBound == null
-                    ? OBJECT
-                    : visit(extendsBound, locale);
-        }
-    }
-
-    @Override
     public String visitType(Type t, Locale locale) {
         String s = (t.tsym == null || t.tsym.name == null)
                 ? OBJECT // none
@@ -87,20 +78,9 @@
         return s;
     }
 
-    @Override
-    public String visitClassType(ClassType ct, Locale locale) {
-        boolean prevUseWildCard = useWildCard;
-        try {
-            useWildCard = true;
-            return super.visitClassType(ct, locale);
-        } finally {
-            useWildCard = prevUseWildCard;
-        }
-    }
-
     /**
-     * Converts a class name into a (possibly localized) string. Anonymous
-     * inner classes get converted into a localized string.
+     * Converts a class name into a (possibly localized) string. Anonymous inner
+     * classes get converted into a localized string.
      *
      * @param t the type of the class whose name is to be rendered
      * @param longform if set, the class' fullname is displayed - if unset the
@@ -112,21 +92,13 @@
     protected String className(ClassType t, boolean longform, Locale locale) {
         Symbol sym = t.tsym;
         if (sym.name.length() == 0 && (sym.flags() & COMPOUND) != 0) {
-            /***
-            StringBuilder s = new StringBuilder(visit(t.supertype_field, locale));
-            for (List<Type> is = t.interfaces_field; is.nonEmpty(); is = is.tail) {
-                s.append('&');
-                s.append(visit(is.head, locale));
-            }
-            return s.toString();
-            ***/
             return OBJECT;
         } else if (sym.name.length() == 0) {
             // Anonymous
             String s;
             ClassType norm = (ClassType) t.tsym.type;
             if (norm == null) {
-                s = "object";
+                s = OBJECT;
             } else if (norm.interfaces_field != null && norm.interfaces_field.nonEmpty()) {
                 s = visit(norm.interfaces_field.head, locale);
             } else {
@@ -160,7 +132,7 @@
     @Override
     public String visitPackageSymbol(PackageSymbol s, Locale locale) {
         return s.isUnnamed()
-                ? ""   // Unnamed package
+                ? "" // Unnamed package
                 : s.fullname.toString();
     }
 
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java	Mon Jan 09 16:20:48 2017 -0800
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java	Mon Jan 09 18:04:16 2017 -0800
@@ -46,6 +46,7 @@
 import static java.util.stream.Collectors.toSet;
 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_EVNT;
 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_GEN;
+import static jdk.internal.jshell.debug.InternalDebugControl.DBG_WRAP;
 import static jdk.jshell.Snippet.Status.OVERWRITTEN;
 import static jdk.jshell.Snippet.Status.RECOVERABLE_DEFINED;
 import static jdk.jshell.Snippet.Status.RECOVERABLE_NOT_DEFINED;
@@ -180,6 +181,8 @@
                     .collect(toList());
             // Set the outer wrap for this snippet
             si.setOuterWrap(state.outerMap.wrapInClass(except, plus, snippets, wraps));
+            state.debug(DBG_WRAP, "++setWrap() %s\n%s\n",
+                    si, si.outerWrap().wrapped());
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/VarTypePrinter.java	Mon Jan 09 18:04:16 2017 -0800
@@ -0,0 +1,267 @@
+/*
+ * 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.HashSet;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Type.ClassType;
+import com.sun.tools.javac.util.JavacMessages;
+import java.util.Locale;
+import java.util.Set;
+import java.util.function.BinaryOperator;
+import com.sun.tools.javac.code.BoundKind;
+import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Type.CapturedType;
+import com.sun.tools.javac.code.Type.TypeMapping;
+import com.sun.tools.javac.code.Type.TypeVar;
+import com.sun.tools.javac.code.Type.WildcardType;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.code.Types.SimpleVisitor;
+import com.sun.tools.javac.util.List;
+import static com.sun.tools.javac.code.BoundKind.EXTENDS;
+import static com.sun.tools.javac.code.BoundKind.SUPER;
+import static com.sun.tools.javac.code.BoundKind.UNBOUND;
+import static com.sun.tools.javac.code.Type.ArrayType;
+import static com.sun.tools.javac.code.TypeTag.BOT;
+import static com.sun.tools.javac.code.TypeTag.WILDCARD;
+
+/**
+ * Print variable types in source form.
+ * TypeProjection and CaptureScanner are copied from Types in the JEP-286
+ * Sandbox by Maurizio.  The checks for Non-Denotable in TypePrinter are
+ * cribbed from denotableChecker of the same source.
+ *
+ * @author Maurizio Cimadamore
+ * @author Robert Field
+ */
+class VarTypePrinter extends TypePrinter {
+    private static final String WILD = "?";
+
+    private final Symtab syms;
+    private final Types types;
+
+    VarTypePrinter(JavacMessages messages, BinaryOperator<String> fullClassNameAndPackageToClass,
+            Symtab syms, Types types) {
+        super(messages, fullClassNameAndPackageToClass);
+        this.syms = syms;
+        this.types = types;
+    }
+
+    @Override
+    String toString(Type t) {
+        return super.toString(upward(t));
+    }
+
+    @Override
+    public String visitTypeVar(TypeVar t, Locale locale) {
+        /* Any type variable mentioned in the inferred type must have been declared as a type parameter
+                  (i.e cannot have been produced by inference (18.4))
+         */
+        // and beyond that, there are no global type vars, so if there are any
+        // type variables left, they need to be eliminated
+        return WILD; // Non-denotable
+    }
+
+    @Override
+    public String visitCapturedType(CapturedType t, Locale locale) {
+        /* Any type variable mentioned in the inferred type must have been declared as a type parameter
+                  (i.e cannot have been produced by capture conversion (5.1.10))
+         */
+        return WILD; // Non-denotable
+    }
+
+    public Type upward(Type t) {
+        List<Type> captures = captures(t);
+        return upward(t, captures);
+    }
+
+    /************* Following from JEP-286 Types.java ***********/
+
+    public Type upward(Type t, List<Type> vars) {
+        return t.map(new TypeProjection(vars), true);
+    }
+
+    public List<Type> captures(Type t) {
+        CaptureScanner cs = new CaptureScanner();
+        Set<Type> captures = new HashSet<>();
+        cs.visit(t, captures);
+        return List.from(captures);
+    }
+
+    class CaptureScanner extends SimpleVisitor<Void, Set<Type>> {
+
+        @Override
+        public Void visitType(Type t, Set<Type> types) {
+            return null;
+        }
+
+        @Override
+        public Void visitClassType(ClassType t, Set<Type> seen) {
+            if (t.isCompound()) {
+                types.directSupertypes(t).forEach(s -> visit(s, seen));
+            } else {
+                t.allparams().forEach(ta -> visit(ta, seen));
+            }
+            return null;
+        }
+
+        @Override
+        public Void visitArrayType(ArrayType t, Set<Type> seen) {
+            return visit(t.elemtype, seen);
+        }
+
+        @Override
+        public Void visitWildcardType(WildcardType t, Set<Type> seen) {
+            visit(t.type, seen);
+            return null;
+        }
+
+        @Override
+        public Void visitTypeVar(TypeVar t, Set<Type> seen) {
+            if ((t.tsym.flags() & Flags.SYNTHETIC) != 0 && seen.add(t)) {
+                visit(t.getUpperBound(), seen);
+            }
+            return null;
+        }
+
+        @Override
+        public Void visitCapturedType(CapturedType t, Set<Type> seen) {
+            if (seen.add(t)) {
+                visit(t.getUpperBound(), seen);
+                visit(t.getLowerBound(), seen);
+            }
+            return null;
+        }
+    }
+
+    class TypeProjection extends TypeMapping<Boolean> {
+
+        List<Type> vars;
+        Set<Type> seen = new HashSet<>();
+
+        public TypeProjection(List<Type> vars) {
+            this.vars = vars;
+        }
+
+        @Override
+        public Type visitClassType(ClassType t, Boolean upward) {
+            if (upward && !t.isCompound() && t.tsym.name.isEmpty()) {
+                //lift anonymous class type to first supertype (class or interface)
+                return types.directSupertypes(t).last();
+            } else if (t.isCompound()) {
+                List<Type> components = types.directSupertypes(t);
+                List<Type> components1 = components.map(c -> c.map(this, upward));
+                if (components == components1) return t;
+                else return types.makeIntersectionType(components1);
+            } else {
+                Type outer = t.getEnclosingType();
+                Type outer1 = visit(outer, upward);
+                List<Type> typarams = t.getTypeArguments();
+                List<Type> typarams1 = typarams.stream()
+                        .map(ta -> mapTypeArgument(ta, upward))
+                        .collect(List.collector());
+                if (typarams1.stream().anyMatch(ta -> ta.hasTag(BOT))) {
+                    //not defined
+                    return syms.botType;
+                }
+                if (outer1 == outer && typarams1 == typarams) return t;
+                else return new ClassType(outer1, typarams1, t.tsym, t.getMetadata()) {
+                    @Override
+                    protected boolean needsStripping() {
+                        return true;
+                    }
+                };
+            }
+        }
+
+        protected Type makeWildcard(Type upper, Type lower) {
+            BoundKind bk;
+            Type bound;
+            if (upper.hasTag(BOT)) {
+                upper = syms.objectType;
+            }
+            boolean isUpperObject = types.isSameType(upper, syms.objectType);
+            if (!lower.hasTag(BOT) && isUpperObject) {
+                bound = lower;
+                bk = SUPER;
+            } else {
+                bound = upper;
+                bk = isUpperObject ? UNBOUND : EXTENDS;
+            }
+            return new WildcardType(bound, bk, syms.boundClass);
+        }
+
+        @Override
+        public Type visitTypeVar(TypeVar t, Boolean upward) {
+            if (vars.contains(t)) {
+                try {
+                    if (seen.add(t)) {
+                        return (upward ?
+                                t.getUpperBound() :
+                                (t.getLowerBound() == null) ?
+                                        syms.botType :
+                                        t.getLowerBound())
+                                    .map(this, upward);
+                    } else {
+                        //cycle
+                        return syms.objectType;
+                    }
+                } finally {
+                    seen.remove(t);
+                }
+            } else {
+                return t;
+            }
+        }
+
+        @Override
+        public Type visitWildcardType(WildcardType wt, Boolean upward) {
+            if (upward) {
+                return wt.isExtendsBound() ?
+                        wt.type.map(this, upward) :
+                        syms.objectType;
+            } else {
+                return wt.isSuperBound() ?
+                        wt.type.map(this, upward) :
+                        syms.botType;
+            }
+        }
+
+        private Type mapTypeArgument(Type t, boolean upward) {
+            if (!t.containsAny(vars)) {
+                return t;
+            } else if (!t.hasTag(WILDCARD) && !upward) {
+                //not defined
+                return syms.botType;
+            } else {
+                Type upper = t.map(this, upward);
+                Type lower = t.map(this, !upward);
+                return makeWildcard(upper, lower);
+            }
+        }
+    }
+}
--- a/langtools/test/jdk/jshell/TypeNameTest.java	Mon Jan 09 16:20:48 2017 -0800
+++ b/langtools/test/jdk/jshell/TypeNameTest.java	Mon Jan 09 18:04:16 2017 -0800
@@ -23,81 +23,229 @@
 
 /*
  * @test
- * @bug 8144903
+ * @bug 8144903 8171981
  * @summary Tests for determining the type from the expression
  * @build KullaTesting TestingInputStream
  * @run testng TypeNameTest
  */
 
-import jdk.jshell.Snippet;
-import jdk.jshell.VarSnippet;
 import org.testng.annotations.Test;
 
-import static jdk.jshell.Snippet.Status.VALID;
 import static org.testng.Assert.assertEquals;
 
 @Test
 public class TypeNameTest extends KullaTesting {
 
-    public void testReplClassName() {
-        assertEval("class C {}");
-        VarSnippet sn = (VarSnippet) varKey(assertEval("new C();"));
-        assertEquals(sn.typeName(), "C");
+
+    private void assertType(String expr, String type) {
+        assertEquals(varKey(assertEval(expr)).typeName(), type);
+        assertInferredType(expr, type);
+    }
+
+    public void testTypeInference() {
+        assertEval("import java.util.List;");
+        assertEval("import java.util.ArrayList;");
+        assertEval("import java.util.Arrays;");
+
+        assertType("new Object().getClass().getSuperclass() ", "Class<?>");
+        assertType("new ArrayList().getClass().getSuperclass()", "Class<?>");
+        assertType("new ArrayList().getClass()", "Class<? extends ArrayList>");
+        assertType("ArrayList.class", "Class<ArrayList>");
+        assertType("ArrayList.class.getSuperclass()", "Class<? super ArrayList>");
+
+        assertEval("class D<T extends CharSequence> { D<? super T> getS() { return null; } }");
+        assertEval("D<?> d = new D<String>();");
+        assertType("d.getS()", "D<? extends CharSequence>");
+        assertType("null", "Object");
+        assertType("Class.forName( \"java.util.ArrayList\" )", "Class<?>");
+        assertType("new ArrayList<Boolean>() {}", "ArrayList<Boolean>");
+        assertType("new ArrayList<String>().stream()", "java.util.stream.Stream<String>");
+        assertType("Arrays.asList( 1, 2, 3)", "List<Integer>");
+        assertType("new ArrayList().getClass().getClass()", "Class<? extends Class>");
+
+        assertEval("interface A {}");
+        assertEval("interface I {}");
+        assertEval("interface J extends A, I {}");
+        assertEval("interface K extends A, I {}");
+        assertEval("class P<T extends A & I> {}");
+        assertType("(P<?>) null", "P<? extends Object>");
+    }
+
+    public void testConditionals() {
+        assertEval("import java.util.List;");
+        assertEval("import java.util.ArrayList;");
+        assertEval("import java.util.Arrays;");
+
+        assertEval("CharSequence cs = \"hi\";");
+        assertEval("String st = \"low\";");
+        assertEval("boolean b;");
+        assertType("b? cs : st", "CharSequence");
+
+        assertEval("List<String> l1 = Arrays.asList(\"hi\");");
+        assertEval("List<? extends String> l2 = Arrays.asList(\"po\");");
+        assertType("b? l1.get(0) : l2.get(0)", "String");
+
+        assertEval("class X {}");
+        assertEval("class B extends X {}");
+        assertEval("class C extends X {}");
+        assertType("b? new B() : new C()", "X");
+    }
+
+    public void testJEP286NonDenotable() {
+        assertEval("import java.util.List;");
+        assertEval("import java.util.Arrays;");
+        assertEval("import java.util.Iterator;");
+
+        assertEval("List<? extends String> extString() { return Arrays.asList( \"hi\", \"low\" ); }");
+        assertEval("List<? super String> supString() { return Arrays.asList( \"hi\", \"low\" ); }");
+        assertEval("List<?> unbString() { return Arrays.asList( \"hi\", \"low\" ); }");
+        assertEval("List<? extends String>[] extStringArr() {" +
+                " @SuppressWarnings(\"unchecked\") " +
+                "List<? extends String>[] a = new List[1]; a[0] = Arrays.asList(\"hi\"); return a; }");
+        assertEval("List<? super String>[] supStringArr() {" +
+                " @SuppressWarnings(\"unchecked\") " +
+                "List<? super String>[] a = new List[1]; a[0] = Arrays.asList(\"hi\"); return a; }");
+        assertEval("List<?>[] unbStringArr() {" +
+                " @SuppressWarnings(\"unchecked\") " +
+                "List<?>[] a = new List[1]; a[0] = Arrays.asList(\"hi\"); return a; }");
+        assertEval("Iterable<? extends List<? extends String>> extStringIter() {" +
+                "return Arrays.asList( Arrays.asList( \"hi\" ) ); }");
+        assertEval("Iterable<? extends List<? super String>> supStringIter() {" +
+                "return Arrays.asList( Arrays.asList( \"hi\" ) ); }");
+        assertEval("Iterable<? extends List<?>> unbStringIter() {" +
+                "return Arrays.asList( Arrays.asList( \"hi\" ) ); }");
+        assertType("extString()", "List<? extends String>");
+        assertType("extString().get(0)", "String");
+        assertType("supString()", "List<? super String>");
+        assertType("supString().get(0)", "Object");
+        assertType("unbString()", "List<?>");
+        assertType("unbString().get(0)", "Object");
+        assertType("supStringArr()", "List<? super String>[]");
+        assertType("supStringArr()[0]", "List<? super String>");
+        assertType("supStringArr()[0].get(0)", "Object");
+        assertType("unbStringArr()", "List<?>[]");
+        assertType("unbStringArr()[0]", "List<?>");
+        assertType("unbStringArr()[0].get(0)", "Object");
+        assertType("extStringIter()", "Iterable<? extends List<? extends String>>");
+        assertType("extStringIter().iterator()", "Iterator<? extends List<? extends String>>");
+        assertType("extStringIter().iterator().next()", "List<? extends String>");
+        assertType("extStringIter().iterator().next().get(0)", "String");
+        assertType("supStringIter()", "Iterable<? extends List<? super String>>");
+        assertType("supStringIter().iterator()", "Iterator<? extends List<? super String>>");
+        assertType("supStringIter().iterator().next()", "List<? super String>");
+        assertType("supStringIter().iterator().next().get(0)", "Object");
+        assertType("unbStringIter()", "Iterable<? extends List<?>>");
+        assertType("unbStringIter().iterator()", "Iterator<? extends List<?>>");
+        assertType("unbStringIter().iterator().next()", "List<?>");
+        assertType("unbStringIter().iterator().next().get(0)", "Object");
+    }
+
+    public void testJEP286NonDenotable2() {
+        assertEval("import java.util.List;");
+        assertEval("import java.util.Arrays;");
+        assertEval("import java.lang.reflect.Array;");
+
+        assertEval("<Z extends Comparable<Z>> List<? extends Z> extFbound() {" +
+                "return Arrays.asList( (Z)null ); }");
+        assertEval("<Z extends Comparable<Z>> List<? super Z> supFbound() {" +
+                "return Arrays.asList( (Z)null ); }");
+        assertEval("<Z extends Comparable<Z>> List<? extends Z>[] extFboundArr() {" +
+                "@SuppressWarnings(\"unchecked\")" +
+                "List<? extends Z>[] a = new List[1]; a[0] = Arrays.asList( (Z)null ); return a; }");
+        assertEval("<Z extends Comparable<Z>> List<? super Z>[] supFboundArr() {" +
+                "@SuppressWarnings(\"unchecked\")" +
+                "List<? super Z>[] a = new List[1]; a[0] = Arrays.asList( (Z)null ); return a; }");
+        assertEval("<Z extends Comparable<Z>> Iterable<? extends List<? extends Z>> extFboundIter() {" +
+                "return Arrays.asList( Arrays.asList( (Z)null ) ); }");
+        assertEval("<Z extends Comparable<Z>> Iterable<? extends List<? super Z>> supFboundIter() {" +
+                "return Arrays.asList( Arrays.asList( (Z)null ) ); }");
+        assertEval("<Z> List<Z> listOf(Z z) { return Arrays.asList( z ); }");
+        assertEval("<Z> Z[] arrayOf(Z z) {" +
+                "@SuppressWarnings(\"unchecked\")" +
+                "final Z[] a = (Z[]) Array.newInstance(z.getClass(), 1); a[0] = z; return a; }");
+        assertType("extFbound()", "List<? extends Comparable<?>>");
+        assertType("extFbound().get(0)", "Comparable<?>");
+        assertType("supFbound()", "List<?>");
+        assertType("supFbound().get(0)", "Object");
+        assertType("extFboundArr()", "List<? extends Comparable<?>>[]");
+        assertType("extFboundArr()[0]", "List<? extends Comparable<?>>");
+        assertType("extFboundArr()[0].get(0)", "Comparable<?>");
+        assertType("supFboundArr()", "List<?>[]");
+        assertType("supFboundArr()[0]", "List<?>");
+        assertType("supFboundArr()[0].get(0)", "Object");
+        assertType("extFboundIter()", "Iterable<? extends List<? extends Comparable<?>>>");
+        assertType("extFboundIter().iterator()", "java.util.Iterator<? extends List<? extends Comparable<?>>>");
+        assertType("extFboundIter().iterator().next()", "List<? extends Comparable<?>>");
+        assertType("extFboundIter().iterator().next().get(0)", "Comparable<?>");
+        assertType("supFboundIter()", "Iterable<? extends List<?>>");
+        assertType("supFboundIter().iterator()", "java.util.Iterator<? extends List<?>>");
+        assertType("supFboundIter().iterator().next()", "List<?>");
+        assertType("supFboundIter().iterator().next().get(0)", "Object");
+        assertType("listOf(23)", "List<Integer>");
+        assertType("listOf(true)", "List<Boolean>");
+        assertType("listOf(true).get(0)", "Boolean");
+        assertType("arrayOf(99)", "Integer[]");
+        assertType("arrayOf(99)[0]", "Integer");
+
+        assertEval("<Z> Z choose(Z z1, Z z2) { return z1; }");
+        assertType("choose(1, 1L);", "Object");
+    }
+
+    public void testVariableTypeName() {
+        assertType("\"x\"", "String");
+
+        assertType("java.util.regex.Pattern.compile(\"x\")", "java.util.regex.Pattern");
+        assertEval("import java.util.regex.*;");
+        assertType("java.util.regex.Pattern.compile(\"x\")", "Pattern");
+
+        assertType("new java.util.ArrayList()", "java.util.ArrayList");
+        assertEval("import java.util.ArrayList;");
+        assertType("new java.util.ArrayList()", "ArrayList");
+
+        assertType("java.util.Locale.Category.FORMAT", "java.util.Locale.Category");
+        assertEval("import static java.util.Locale.Category;");
+        assertType("java.util.Locale.Category.FORMAT", "Category");
     }
 
     public void testReplNestedClassName() {
         assertEval("class D { static class E {} }");
-        VarSnippet sn = (VarSnippet) varKey(assertEval("new D.E();"));
-        assertEquals(sn.typeName(), "D.E");
+        assertType("new D.E();", "D.E");
     }
 
     public void testAnonymousClassName() {
         assertEval("class C {}");
-        VarSnippet sn = (VarSnippet) varKey(assertEval("new C() { int x; };"));
-        assertEquals(sn.typeName(), "C");
+        assertType("new C();", "C");
+        assertType("new C() { int x; };", "C");
     }
 
     public void testCapturedTypeName() {
-        VarSnippet sn = (VarSnippet) varKey(assertEval("\"\".getClass();"));
-        assertEquals(sn.typeName(), "Class<? extends String>");
-    }
-
-    public void testArrayTypeOfCapturedTypeName() {
-        VarSnippet sn = (VarSnippet) varKey(assertEval("\"\".getClass().getEnumConstants();"));
-        assertEquals(sn.typeName(), "String[]");
+        assertType("\"\".getClass();", "Class<? extends String>");
+        assertType("\"\".getClass().getEnumConstants();", "String[]");
     }
 
     public void testJavaLang() {
-        VarSnippet sn = (VarSnippet) varKey(assertEval("\"\";"));
-        assertEquals(sn.typeName(), "String");
+        assertType("\"\";", "String");
     }
 
     public void testNotOverEagerPackageEating() {
-        VarSnippet sn = (VarSnippet) varKey(assertEval("\"\".getClass().getDeclaredMethod(\"hashCode\");"));
-        assertEquals(sn.typeName(), "java.lang.reflect.Method");
+        assertType("\"\".getClass().getDeclaredMethod(\"hashCode\");", "java.lang.reflect.Method");
     }
 
     public void testBounds() {
         assertEval("java.util.List<? extends String> list1 = java.util.Arrays.asList(\"\");");
-        VarSnippet sn1 = (VarSnippet) varKey(assertEval("list1.iterator().next()"));
-        assertEquals(sn1.typeName(), "String");
+        assertType("list1.iterator().next()", "String");
         assertEval("java.util.List<? super String> list2 = java.util.Arrays.asList(\"\");");
-        VarSnippet sn2 = (VarSnippet) varKey(assertEval("list2.iterator().next()"));
-        assertEquals(sn2.typeName(), "Object");
+        assertType("list2.iterator().next()", "Object");
         assertEval("java.util.List<?> list3 = java.util.Arrays.asList(\"\");");
-        VarSnippet sn3 = (VarSnippet) varKey(assertEval("list3.iterator().next()"));
-        assertEquals(sn3.typeName(), "Object");
+        assertType("list3.iterator().next()", "Object");
         assertEval("class Test1<X extends CharSequence> { public X get() { return null; } }");
-        Snippet x = varKey(assertEval("Test1<?> test1 = new Test1<>();"));
-        VarSnippet sn4 = (VarSnippet) varKey(assertEval("test1.get()"));
-        assertEquals(sn4.typeName(), "Object");
+        assertEval("Test1<?> test1 = new Test1<>();");
+        assertType("test1.get()", "CharSequence");
         assertEval("class Test2<X extends Number & CharSequence> { public X get() { return null; } }");
         assertEval("Test2<?> test2 = new Test2<>();");
-        VarSnippet sn5 = (VarSnippet) varKey(assertEval("test2.get()"));
-        assertEquals(sn5.typeName(), "Object");
-        assertEval("class Test3<T> { T[][] get() { return null; } }", added(VALID));
+        assertType("test2.get()", "Object");
+        assertEval("class Test3<T> { T[][] get() { return null; } }");
         assertEval("Test3<? extends String> test3 = new Test3<>();");
-        VarSnippet sn6 = (VarSnippet) varKey(assertEval("test3.get()"));
-        assertEquals(sn6.typeName(), "String[][]");
+        assertType("test3.get()", "String[][]");
     }
 }
--- a/langtools/test/jdk/jshell/VariablesTest.java	Mon Jan 09 16:20:48 2017 -0800
+++ b/langtools/test/jdk/jshell/VariablesTest.java	Mon Jan 09 18:04:16 2017 -0800
@@ -337,20 +337,4 @@
         assertEquals(unr.get(0), "class undefined");
         assertVariables(variable("undefined", "d"));
     }
-
-    public void variableTypeName() {
-        assertEquals(varKey(assertEval("\"x\"")).typeName(), "String");
-
-        assertEquals(varKey(assertEval("java.util.regex.Pattern.compile(\"x\")")).typeName(), "java.util.regex.Pattern");
-        assertEval("import java.util.regex.*;", added(VALID));
-        assertEquals(varKey(assertEval("java.util.regex.Pattern.compile(\"x\")")).typeName(), "Pattern");
-
-        assertEquals(varKey(assertEval("new java.util.ArrayList()")).typeName(), "java.util.ArrayList");
-        assertEval("import java.util.ArrayList;", added(VALID));
-        assertEquals(varKey(assertEval("new java.util.ArrayList()")).typeName(), "ArrayList");
-
-        assertEquals(varKey(assertEval("java.util.Locale.Category.FORMAT")).typeName(), "java.util.Locale.Category");
-        assertEval("import static java.util.Locale.Category;", added(VALID));
-        assertEquals(varKey(assertEval("java.util.Locale.Category.FORMAT")).typeName(), "Category");
-    }
 }