8177466: Add compiler support for local variable type-inference
authormcimadamore
Tue, 26 Sep 2017 12:52:53 +0100
changeset 47268 48ec75306997
parent 47267 b3a91921bafc
child 47269 6e99a776ae76
8177466: Add compiler support for local variable type-inference Summary: Add support for 'var' in implicitly typed local variable declarations Reviewed-by: vromero, jlahoda
src/jdk.compiler/share/classes/com/sun/tools/javac/code/Kinds.java
src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java
src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java
src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java
src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java
src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java
src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java
src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java
src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java
src/jdk.compiler/share/classes/module-info.java
src/jdk.jshell/share/classes/jdk/jshell/Eval.java
src/jdk.jshell/share/classes/jdk/jshell/ExpressionToTypeInfo.java
src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java
src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java
src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java
src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java
src/jdk.jshell/share/classes/jdk/jshell/TypePrinter.java
src/jdk.jshell/share/classes/jdk/jshell/VarTypePrinter.java
src/jdk.jshell/share/classes/jdk/jshell/Wrap.java
test/langtools/jdk/jshell/CompletionSuggestionTest.java
test/langtools/jdk/jshell/ToolSimpleTest.java
test/langtools/jdk/jshell/VariablesTest.java
test/langtools/tools/javac/diags/examples/IllegalRefToVarType.java
test/langtools/tools/javac/diags/examples/LocalArrayMissingTarget.java
test/langtools/tools/javac/diags/examples/LocalCantInferNull.java
test/langtools/tools/javac/diags/examples/LocalLambdaMissingTarget.java
test/langtools/tools/javac/diags/examples/LocalMissingInit.java
test/langtools/tools/javac/diags/examples/LocalMrefMissingTarget.java
test/langtools/tools/javac/diags/examples/LocalRedundantType.java
test/langtools/tools/javac/diags/examples/LocalSelfRef.java
test/langtools/tools/javac/diags/examples/VarNotAllowed.java
test/langtools/tools/javac/diags/examples/VarNotAllowedArray.java
test/langtools/tools/javac/diags/examples/VarNotAllowedCompound.java
test/langtools/tools/javac/diags/examples/VarNotAllowedHere.java
test/langtools/tools/javac/lvti/BadLocalVarInferenceTest.java
test/langtools/tools/javac/lvti/BadLocalVarInferenceTest.out
test/langtools/tools/javac/lvti/FoldingTest.java
test/langtools/tools/javac/lvti/FoldingTest.out
test/langtools/tools/javac/lvti/ParserTest.java
test/langtools/tools/javac/lvti/ParserTest.out
test/langtools/tools/javac/lvti/SelfRefTest.java
test/langtools/tools/javac/lvti/SelfRefTest.out
test/langtools/tools/javac/lvti/badTypeReference/BadTypeReference.java
test/langtools/tools/javac/lvti/badTypeReference/BadTypeReference.out
test/langtools/tools/javac/lvti/badTypeReference/pkg/nested/var/A.java
test/langtools/tools/javac/lvti/badTypeReference/pkg/var.java
test/langtools/tools/javac/lvti/harness/InferredType.java
test/langtools/tools/javac/lvti/harness/LocalVariableInferenceTester.java
test/langtools/tools/javac/lvti/harness/NonDenotableTest.java
test/langtools/tools/javac/lvti/harness/PrimitiveTypeTest.java
test/langtools/tools/javac/lvti/harness/ReferenceTypeTest.java
test/langtools/tools/javac/parser/extend/TrialParser.java
test/langtools/tools/lib/types/TypeHarness.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Kinds.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Kinds.java	Tue Sep 26 12:52:53 2017 +0100
@@ -71,6 +71,7 @@
         HIDDEN(Category.RESOLUTION_TARGET),                            // not overloaded   non-target
         STATICERR(Category.RESOLUTION_TARGET),                         // overloaded?      target
         MISSING_ENCL(Category.RESOLUTION),                             // not overloaded   non-target
+        BAD_VAR(Category.RESOLUTION),                                  // not overloaded   non-target
         ABSENT_VAR(Category.RESOLUTION_TARGET, KindName.VAR),          // not overloaded   non-target
         WRONG_MTHS(Category.RESOLUTION_TARGET, KindName.METHOD),       // overloaded       target
         WRONG_MTH(Category.RESOLUTION_TARGET, KindName.METHOD),        // not overloaded   target
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java	Tue Sep 26 12:52:53 2017 +0100
@@ -227,6 +227,7 @@
         return compareTo(JDK1_8) <= 0;
     }
     public boolean allowPrivateInterfaceMethods() { return compareTo(JDK1_9) >= 0; }
+    public boolean allowLocalVariableTypeInference() { return compareTo(JDK1_10) >= 0; }
     public static SourceVersion toSourceVersion(Source source) {
         switch(source) {
         case JDK1_2:
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java	Tue Sep 26 12:52:53 2017 +0100
@@ -1616,6 +1616,7 @@
 
         public TypeVar(Name name, Symbol owner, Type lower) {
             super(null, TypeMetadata.EMPTY);
+            Assert.checkNonNull(lower);
             tsym = new TypeVariableSymbol(0, name, this, owner);
             this.bound = null;
             this.lower = lower;
@@ -1628,6 +1629,7 @@
         public TypeVar(TypeSymbol tsym, Type bound, Type lower,
                        TypeMetadata metadata) {
             super(tsym, metadata);
+            Assert.checkNonNull(lower);
             this.bound = bound;
             this.lower = lower;
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java	Tue Sep 26 12:52:53 2017 +0100
@@ -1247,7 +1247,9 @@
                 final TypeAnnotationPosition pos =
                     TypeAnnotationPosition.localVariable(currentLambda,
                                                          tree.pos);
-                separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos);
+                if (!tree.isImplicitlyTyped()) {
+                    separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos);
+                }
             } else if (tree.sym.getKind() == ElementKind.EXCEPTION_PARAMETER) {
                 final TypeAnnotationPosition pos =
                     TypeAnnotationPosition.exceptionParameter(currentLambda,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Tue Sep 26 12:52:53 2017 +0100
@@ -190,6 +190,245 @@
     }
     // </editor-fold>
 
+    // <editor-fold defaultstate="collapsed" desc="projections">
+
+    /**
+     * A projection kind. See {@link TypeProjection}
+     */
+    enum ProjectionKind {
+        UPWARDS() {
+            @Override
+            ProjectionKind complement() {
+                return DOWNWARDS;
+            }
+        },
+        DOWNWARDS() {
+            @Override
+            ProjectionKind complement() {
+                return UPWARDS;
+            }
+        };
+
+        abstract ProjectionKind complement();
+    }
+
+    /**
+     * This visitor performs upwards and downwards projections on types.
+     *
+     * A projection is defined as a function that takes a type T, a set of type variables V and that
+     * produces another type S.
+     *
+     * An upwards projection maps a type T into a type S such that (i) T has no variables in V,
+     * and (ii) S is an upper bound of T.
+     *
+     * A downwards projection maps a type T into a type S such that (i) T has no variables in V,
+     * and (ii) S is a lower bound of T.
+     *
+     * Note that projections are only allowed to touch variables in V. Theferore it is possible for
+     * a projection to leave its input type unchanged if it does not contain any variables in V.
+     *
+     * Moreover, note that while an upwards projection is always defined (every type as an upper bound),
+     * a downwards projection is not always defined.
+     *
+     * Examples:
+     *
+     * {@code upwards(List<#CAP1>, [#CAP1]) = List<? extends String>, where #CAP1 <: String }
+     * {@code downwards(List<#CAP2>, [#CAP2]) = List<? super String>, where #CAP2 :> String }
+     * {@code upwards(List<#CAP1>, [#CAP2]) = List<#CAP1> }
+     * {@code downwards(List<#CAP1>, [#CAP1]) = not defined }
+     */
+    class TypeProjection extends StructuralTypeMapping<ProjectionKind> {
+
+        List<Type> vars;
+        Set<Type> seen = new HashSet<>();
+
+        public TypeProjection(List<Type> vars) {
+            this.vars = vars;
+        }
+
+        @Override
+        public Type visitClassType(ClassType t, ProjectionKind pkind) {
+            if (t.isCompound()) {
+                List<Type> components = directSupertypes(t);
+                List<Type> components1 = components.map(c -> c.map(this, pkind));
+                if (components == components1) return t;
+                else return makeIntersectionType(components1);
+            } else {
+                Type outer = t.getEnclosingType();
+                Type outer1 = visit(outer, pkind);
+                List<Type> typarams = t.getTypeArguments();
+                List<Type> typarams1 = typarams.map(ta -> mapTypeArgument(ta, pkind));
+                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 = 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, ProjectionKind pkind) {
+            if (vars.contains(t)) {
+                try {
+                    if (seen.add(t)) {
+                        final Type bound;
+                        switch (pkind) {
+                            case UPWARDS:
+                                bound = t.getUpperBound();
+                                break;
+                            case DOWNWARDS:
+                                bound = (t.getLowerBound() == null) ?
+                                        syms.botType :
+                                        t.getLowerBound();
+                                break;
+                            default:
+                                Assert.error();
+                                return null;
+                        }
+                        return bound.map(this, pkind);
+                    } else {
+                        //cycle
+                        return syms.objectType;
+                    }
+                } finally {
+                    seen.remove(t);
+                }
+            } else {
+                return t;
+            }
+        }
+
+        @Override
+        public Type visitWildcardType(WildcardType wt, ProjectionKind pkind) {
+            switch (pkind) {
+                case UPWARDS:
+                    return wt.isExtendsBound() ?
+                            wt.type.map(this, pkind) :
+                            syms.objectType;
+                case DOWNWARDS:
+                    return wt.isSuperBound() ?
+                            wt.type.map(this, pkind) :
+                            syms.botType;
+                default:
+                    Assert.error();
+                    return null;
+            }
+        }
+
+        private Type mapTypeArgument(Type t, ProjectionKind pkind) {
+            if (!t.containsAny(vars)) {
+                return t;
+            } else if (!t.hasTag(WILDCARD) && pkind == ProjectionKind.DOWNWARDS) {
+                //not defined
+                return syms.botType;
+            } else {
+                Type upper = t.map(this, pkind);
+                Type lower = t.map(this, pkind.complement());
+                return makeWildcard(upper, lower);
+            }
+        }
+    }
+
+    /**
+     * Computes an upward projection of given type, and vars. See {@link TypeProjection}.
+     *
+     * @param t the type to be projected
+     * @param vars the set of type variables to be mapped
+     * @return the type obtained as result of the projection
+     */
+    public Type upward(Type t, List<Type> vars) {
+        return t.map(new TypeProjection(vars), ProjectionKind.UPWARDS);
+    }
+
+    /**
+     * Computes the set of captured variables mentioned in a given type. See {@link CaptureScanner}.
+     * This routine is typically used to computed the input set of variables to be used during
+     * an upwards projection (see {@link Types#upward(Type, List)}).
+     *
+     * @param t the type where occurrences of captured variables have to be found
+     * @return the set of captured variables found in t
+     */
+    public List<Type> captures(Type t) {
+        CaptureScanner cs = new CaptureScanner();
+        Set<Type> captures = new HashSet<>();
+        cs.visit(t, captures);
+        return List.from(captures);
+    }
+
+    /**
+     * This visitor scans a type recursively looking for occurrences of captured type variables.
+     */
+    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()) {
+                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;
+        }
+    }
+
+    // </editor-fold>
+
     // <editor-fold defaultstate="collapsed" desc="isUnbounded">
     /**
      * Checks that all the arguments to a class are unbounded
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java	Tue Sep 26 12:52:53 2017 +0100
@@ -83,6 +83,7 @@
 import static com.sun.tools.javac.code.Flags.GENERATEDCONSTR;
 import static com.sun.tools.javac.code.TypeTag.CLASS;
 import static com.sun.tools.javac.tree.JCTree.Tag.APPLY;
+import static com.sun.tools.javac.tree.JCTree.Tag.FOREACHLOOP;
 import static com.sun.tools.javac.tree.JCTree.Tag.LABELLED;
 import static com.sun.tools.javac.tree.JCTree.Tag.METHODDEF;
 import static com.sun.tools.javac.tree.JCTree.Tag.NEWCLASS;
@@ -139,7 +140,8 @@
     enum AnalyzerMode {
         DIAMOND("diamond", Source::allowDiamond),
         LAMBDA("lambda", Source::allowLambda),
-        METHOD("method", Source::allowGraphInference);
+        METHOD("method", Source::allowGraphInference),
+        LOCAL("local", Source::allowLocalVariableTypeInference);
 
         final String opt;
         final Predicate<Source> sourceFilter;
@@ -341,11 +343,91 @@
         }
     }
 
+    /**
+     * Base class for local variable inference analyzers.
+     */
+    abstract class RedundantLocalVarTypeAnalyzerBase<X extends JCStatement> extends StatementAnalyzer<X, X> {
+
+        RedundantLocalVarTypeAnalyzerBase(JCTree.Tag tag) {
+            super(AnalyzerMode.LOCAL, tag);
+        }
+
+        /**
+         * Map a variable tree into a new declaration using implicit type.
+         */
+        JCVariableDecl mapVar(JCVariableDecl oldTree, JCVariableDecl newTree){
+            newTree.vartype = null;
+            return newTree;
+        }
+
+        /**
+         * Analyze results of local variable inference.
+         */
+        void processVar(JCVariableDecl oldTree, JCVariableDecl newTree, boolean hasErrors){
+            if (!hasErrors) {
+                if (types.isSameType(oldTree.type, newTree.type)) {
+                    log.warning(oldTree, Warnings.LocalRedundantType);
+                }
+            }
+        }
+    }
+
+    /**
+     * This analyzer checks if a local variable declaration has redundant type.
+     */
+    class RedundantLocalVarTypeAnalyzer extends RedundantLocalVarTypeAnalyzerBase<JCVariableDecl> {
+
+        RedundantLocalVarTypeAnalyzer() {
+            super(VARDEF);
+        }
+
+        boolean match(JCVariableDecl tree){
+            return tree.sym.owner.kind == Kind.MTH &&
+                    tree.init != null && !tree.isImplicitlyTyped() &&
+                    attr.canInferLocalVarType(tree) == null;
+        }
+        @Override
+        JCVariableDecl map(JCVariableDecl oldTree, JCVariableDecl newTree){
+            return mapVar(oldTree, newTree);
+        }
+        @Override
+        void process(JCVariableDecl oldTree, JCVariableDecl newTree, boolean hasErrors){
+            processVar(oldTree, newTree, hasErrors);
+        }
+    }
+
+    /**
+     * This analyzer checks if a for each variable declaration has redundant type.
+     */
+    class RedundantLocalVarTypeAnalyzerForEach extends RedundantLocalVarTypeAnalyzerBase<JCEnhancedForLoop> {
+
+        RedundantLocalVarTypeAnalyzerForEach() {
+            super(FOREACHLOOP);
+        }
+
+        @Override
+        boolean match(JCEnhancedForLoop tree){
+            return !tree.var.isImplicitlyTyped();
+        }
+        @Override
+        JCEnhancedForLoop map(JCEnhancedForLoop oldTree, JCEnhancedForLoop newTree){
+            newTree.var = mapVar(oldTree.var, newTree.var);
+            newTree.body = make.Block(0, List.nil()); //ignore body for analysis purpose
+            return newTree;
+        }
+        @Override
+        void process(JCEnhancedForLoop oldTree, JCEnhancedForLoop newTree, boolean hasErrors){
+            processVar(oldTree.var, newTree.var, hasErrors);
+        }
+    }
+
     @SuppressWarnings({"unchecked", "rawtypes"})
     StatementAnalyzer<JCTree, JCTree>[] analyzers = new StatementAnalyzer[] {
             new DiamondInitializer(),
             new LambdaAnalyzer(),
-            new RedundantTypeArgAnalyzer()
+            new RedundantTypeArgAnalyzer(),
+            new RedundantLocalVarTypeAnalyzer(),
+            new RedundantLocalVarTypeAnalyzerForEach()
     };
 
     /**
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java	Tue Sep 26 12:52:53 2017 +0100
@@ -28,9 +28,11 @@
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Attribute.Compound;
 import com.sun.tools.javac.code.Attribute.TypeCompound;
+import com.sun.tools.javac.code.Kinds.KindSelector;
 import com.sun.tools.javac.code.Scope.WriteableScope;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.TypeMetadata.Entry.Kind;
+import com.sun.tools.javac.comp.Check.CheckContext;
 import com.sun.tools.javac.resources.CompilerProperties.Errors;
 import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.tree.JCTree.*;
@@ -602,7 +604,7 @@
     }
 
     private Attribute getAnnotationEnumValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
-        Type result = attr.attribExpr(tree, env, expectedElementType);
+        Type result = attr.attribTree(tree, env, annotationValueInfo(expectedElementType));
         Symbol sym = TreeInfo.symbol(tree);
         if (sym == null ||
                 TreeInfo.nonstaticSelect(tree) ||
@@ -616,7 +618,7 @@
     }
 
     private Attribute getAnnotationClassValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
-        Type result = attr.attribExpr(tree, env, expectedElementType);
+        Type result = attr.attribTree(tree, env, annotationValueInfo(expectedElementType));
         if (result.isErroneous()) {
             // Does it look like an unresolved class literal?
             if (TreeInfo.name(tree) == names._class &&
@@ -642,7 +644,7 @@
     }
 
     private Attribute getAnnotationPrimitiveValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
-        Type result = attr.attribExpr(tree, env, expectedElementType);
+        Type result = attr.attribTree(tree, env, annotationValueInfo(expectedElementType));
         if (result.isErroneous())
             return new Attribute.Error(result.getOriginalType());
         if (result.constValue() == null) {
@@ -653,6 +655,22 @@
         return new Attribute.Constant(expectedElementType, result.constValue());
     }
 
+    private Attr.ResultInfo annotationValueInfo(Type pt) {
+        return attr.unknownExprInfo.dup(pt, new AnnotationValueContext(attr.unknownExprInfo.checkContext));
+    }
+
+    class AnnotationValueContext extends Check.NestedCheckContext {
+        AnnotationValueContext(CheckContext enclosingContext) {
+            super(enclosingContext);
+        }
+
+        @Override
+        public boolean compatible(Type found, Type req, Warner warn) {
+            //handle non-final implicitly-typed vars (will be rejected later on)
+            return found.hasTag(TypeTag.NONE) || super.compatible(found, req, warn);
+        }
+    }
+
     private Attribute getAnnotationArrayValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
         // Special case, implicit array
         if (!tree.hasTag(NEWARRAY)) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Sep 26 12:52:53 2017 +0100
@@ -36,7 +36,6 @@
 import com.sun.source.tree.TreeVisitor;
 import com.sun.source.util.SimpleTreeVisitor;
 import com.sun.tools.javac.code.*;
-import com.sun.tools.javac.code.Directive.RequiresFlag;
 import com.sun.tools.javac.code.Lint.LintCategory;
 import com.sun.tools.javac.code.Scope.WriteableScope;
 import com.sun.tools.javac.code.Symbol.*;
@@ -46,7 +45,6 @@
 import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
 import com.sun.tools.javac.comp.Check.CheckContext;
 import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
-import com.sun.tools.javac.comp.Infer.FreeTypeListener;
 import com.sun.tools.javac.jvm.*;
 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.Diamond;
 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArg;
@@ -830,6 +828,10 @@
         final JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile);
         try {
             Type itype = attribExpr(variable.init, env, type);
+            if (variable.isImplicitlyTyped()) {
+                //fixup local variable type
+                type = variable.type = variable.sym.type = chk.checkLocalVarType(variable, itype.baseType(), variable.name);
+            }
             if (itype.constValue() != null) {
                 return coerce(itype, type).constValue();
             } else {
@@ -1108,6 +1110,21 @@
                 // parameters have already been entered
                 env.info.scope.enter(tree.sym);
             } else {
+                if (tree.isImplicitlyTyped() && (tree.getModifiers().flags & PARAMETER) == 0) {
+                    if (tree.init == null) {
+                        //cannot use 'var' without initializer
+                        log.error(tree, Errors.CantInferLocalVarType(tree.name, Fragments.LocalMissingInit));
+                        tree.vartype = make.Erroneous();
+                    } else {
+                        Fragment msg = canInferLocalVarType(tree);
+                        if (msg != null) {
+                            //cannot use 'var' with initializer which require an explicit target
+                            //(e.g. lambda, method reference, array initializer).
+                            log.error(tree, Errors.CantInferLocalVarType(tree.name, msg));
+                            tree.vartype = make.Erroneous();
+                        }
+                    }
+                }
                 try {
                     annotate.blockAnnotations();
                     memberEnter.memberEnter(tree, env);
@@ -1131,7 +1148,7 @@
         boolean isImplicitLambdaParameter = env.tree.hasTag(LAMBDA) &&
                 ((JCLambda)env.tree).paramKind == JCLambda.ParameterKind.IMPLICIT &&
                 (tree.sym.flags() & PARAMETER) != 0;
-        chk.validate(tree.vartype, env, !isImplicitLambdaParameter);
+        chk.validate(tree.vartype, env, !isImplicitLambdaParameter && !tree.isImplicitlyTyped());
 
         try {
             v.getConstValue(); // ensure compile-time constant initializer is evaluated
@@ -1152,6 +1169,10 @@
                     // marking the variable as undefined.
                     initEnv.info.enclVar = v;
                     attribExpr(tree.init, initEnv, v.type);
+                    if (tree.isImplicitlyTyped()) {
+                        //fixup local variable type
+                        v.type = chk.checkLocalVarType(tree, tree.init.type.baseType(), tree.name);
+                    }
                 }
             }
             result = tree.type = v.type;
@@ -1161,6 +1182,71 @@
         }
     }
 
+    Fragment canInferLocalVarType(JCVariableDecl tree) {
+        LocalInitScanner lis = new LocalInitScanner();
+        lis.scan(tree.init);
+        return lis.badInferenceMsg;
+    }
+
+    static class LocalInitScanner extends TreeScanner {
+        Fragment badInferenceMsg = null;
+        boolean needsTarget = true;
+
+        @Override
+        public void visitNewArray(JCNewArray tree) {
+            if (tree.elemtype == null && needsTarget) {
+                badInferenceMsg = Fragments.LocalArrayMissingTarget;
+            }
+        }
+
+        @Override
+        public void visitLambda(JCLambda tree) {
+            if (needsTarget) {
+                badInferenceMsg = Fragments.LocalLambdaMissingTarget;
+            }
+        }
+
+        @Override
+        public void visitTypeCast(JCTypeCast tree) {
+            boolean prevNeedsTarget = needsTarget;
+            try {
+                needsTarget = false;
+                super.visitTypeCast(tree);
+            } finally {
+                needsTarget = prevNeedsTarget;
+            }
+        }
+
+        @Override
+        public void visitReference(JCMemberReference tree) {
+            if (needsTarget) {
+                badInferenceMsg = Fragments.LocalMrefMissingTarget;
+            }
+        }
+
+        @Override
+        public void visitNewClass(JCNewClass tree) {
+            boolean prevNeedsTarget = needsTarget;
+            try {
+                needsTarget = false;
+                super.visitNewClass(tree);
+            } finally {
+                needsTarget = prevNeedsTarget;
+            }
+        }
+
+        @Override
+        public void visitApply(JCMethodInvocation tree) {
+            boolean prevNeedsTarget = needsTarget;
+            try {
+                needsTarget = false;
+                super.visitApply(tree);
+            } finally {
+                needsTarget = prevNeedsTarget;
+            }
+        }
+    }
+
     public void visitSkip(JCSkip tree) {
         result = null;
     }
@@ -1243,7 +1329,6 @@
             //attributing the for-each expression; we mimick this by attributing
             //the for-each expression first (against original scope).
             Type exprType = types.cvarUpperBound(attribExpr(tree.expr, loopEnv));
-            attribStat(tree.var, loopEnv);
             chk.checkNonVoid(tree.pos(), exprType);
             Type elemtype = types.elemtype(exprType); // perhaps expr is an array?
             if (elemtype == null) {
@@ -1261,6 +1346,15 @@
                         : types.wildUpperBound(iterableParams.head);
                 }
             }
+            if (tree.var.isImplicitlyTyped()) {
+                Type inferredType = chk.checkLocalVarType(tree.var, elemtype, tree.var.name);
+                if (inferredType.isErroneous()) {
+                    tree.var.vartype = make.at(tree.var.vartype).Erroneous();
+                } else {
+                    tree.var.vartype = make.at(tree.var.vartype).Type(inferredType);
+                }
+            }
+            attribStat(tree.var, loopEnv);
             chk.checkType(tree.expr.pos(), elemtype, tree.var.sym.type);
             loopEnv.tree = tree; // before, we were not in loop!
             attribStat(tree.body, loopEnv);
@@ -2379,7 +2473,8 @@
             if (pt().hasTag(ARRAY)) {
                 elemtype = types.elemtype(pt());
             } else {
-                if (!pt().hasTag(ERROR)) {
+                if (!pt().hasTag(ERROR) &&
+                        (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
                     log.error(tree.pos(),
                               Errors.IllegalInitializerForType(pt()));
                 }
@@ -2404,7 +2499,7 @@
     @Override
     public void visitLambda(final JCLambda that) {
         if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
-            if (pt().hasTag(NONE)) {
+            if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
                 //lambda only allowed in assignment or method invocation/cast context
                 log.error(that.pos(), Errors.UnexpectedLambda);
             }
@@ -2837,7 +2932,7 @@
     @Override
     public void visitReference(final JCMemberReference that) {
         if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
-            if (pt().hasTag(NONE)) {
+            if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
                 //method reference only allowed in assignment or method invocation/cast context
                 log.error(that.pos(), Errors.UnexpectedMref);
             }
@@ -3811,6 +3906,14 @@
                 break;
             case VAR:
                 VarSymbol v = (VarSymbol)sym;
+
+                if (env.info.enclVar != null
+                        && v.type.hasTag(NONE)) {
+                    //self reference to implicitly typed variable declaration
+                    log.error(TreeInfo.positionFor(v, env.enclClass), Errors.CantInferLocalVarType(v.name, Fragments.LocalSelfRef));
+                    return v.type = types.createErrorType(v.type);
+                }
+
                 // Test (4): if symbol is an instance field of a raw type,
                 // which is being assigned to, issue an unchecked warning if
                 // its type changes under erasure.
@@ -4135,6 +4238,9 @@
     public void visitTypeArray(JCArrayTypeTree tree) {
         Type etype = attribType(tree.elemtype, env);
         Type type = new ArrayType(etype, syms.arrayClass);
+        if (etype.isErroneous()) {
+            type = types.createErrorType(type);
+        }
         result = check(tree, type, KindSelector.TYP, resultInfo);
     }
 
@@ -4776,7 +4882,7 @@
         }
         public void visitVarDef(final JCVariableDecl tree) {
             //System.err.println("validateTypeAnnotations.visitVarDef " + tree);
-            if (tree.sym != null && tree.sym.type != null)
+            if (tree.sym != null && tree.sym.type != null && !tree.isImplicitlyTyped())
                 validateAnnotatedType(tree.vartype, tree.sym.type);
             scan(tree.mods);
             scan(tree.vartype);
@@ -4904,17 +5010,16 @@
                     repeat = false;
                 } else if (enclTr.hasTag(JCTree.Tag.WILDCARD)) {
                     JCWildcard wc = (JCWildcard) enclTr;
-                    if (wc.getKind() == JCTree.Kind.EXTENDS_WILDCARD) {
-                        validateAnnotatedType(wc.getBound(), ((WildcardType)enclTy).getExtendsBound());
-                    } else if (wc.getKind() == JCTree.Kind.SUPER_WILDCARD) {
-                        validateAnnotatedType(wc.getBound(), ((WildcardType)enclTy).getSuperBound());
+                    if (wc.getKind() == JCTree.Kind.EXTENDS_WILDCARD ||
+                            wc.getKind() == JCTree.Kind.SUPER_WILDCARD) {
+                        validateAnnotatedType(wc.getBound(), wc.getBound().type);
                     } else {
                         // Nothing to do for UNBOUND
                     }
                     repeat = false;
                 } else if (enclTr.hasTag(TYPEARRAY)) {
                     JCArrayTypeTree art = (JCArrayTypeTree) enclTr;
-                    validateAnnotatedType(art.getType(), ((ArrayType)enclTy).getComponentType());
+                    validateAnnotatedType(art.getType(), art.elemtype.type);
                     repeat = false;
                 } else if (enclTr.hasTag(TYPEUNION)) {
                     JCTypeUnion ut = (JCTypeUnion) enclTr;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Tue Sep 26 12:52:53 2017 +0100
@@ -843,26 +843,30 @@
     List<Type> checkDiamondDenotable(ClassType t) {
         ListBuffer<Type> buf = new ListBuffer<>();
         for (Type arg : t.allparams()) {
-            if (!diamondTypeChecker.visit(arg, null)) {
+            if (!checkDenotable(arg)) {
                 buf.append(arg);
             }
         }
         return buf.toList();
     }
+
+    boolean checkDenotable(Type t) {
+        return denotableChecker.visit(t, null);
+    }
         // where
 
         /** diamondTypeChecker: A type visitor that descends down the given type looking for non-denotable
          *  types. The visit methods return false as soon as a non-denotable type is encountered and true
          *  otherwise.
          */
-        private static final Types.SimpleVisitor<Boolean, Void> diamondTypeChecker = new Types.SimpleVisitor<Boolean, Void>() {
+        private static final Types.SimpleVisitor<Boolean, Void> denotableChecker = new Types.SimpleVisitor<Boolean, Void>() {
             @Override
             public Boolean visitType(Type t, Void s) {
                 return true;
             }
             @Override
             public Boolean visitClassType(ClassType t, Void s) {
-                if (t.isCompound()) {
+                if (t.isUnion() || t.isIntersection()) {
                     return false;
                 }
                 for (Type targ : t.allparams()) {
@@ -878,7 +882,7 @@
                 /* 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))
                 */
-                return t.tsym.owner.type.getTypeArguments().contains(t);
+                return (t.tsym.flags() & SYNTHETIC) == 0;
             }
 
             @Override
@@ -941,6 +945,17 @@
                                   (allowPrivateSafeVarargs ? PRIVATE : 0) )) != 0);
         }
 
+    Type checkLocalVarType(DiagnosticPosition pos, Type t, Name name) {
+        //upward project the initializer type
+        t = types.upward(t, types.captures(t));
+        //check that resulting type is not the null type
+        if (t.hasTag(BOT)) {
+            log.error(pos, Errors.CantInferLocalVarType(name, Fragments.LocalCantInferNull));
+            return types.createErrorType(t);
+        }
+        return t;
+    }
+
     Type checkMethod(final Type mtype,
             final Symbol sym,
             final Env<AttrContext> env,
@@ -3159,7 +3174,10 @@
                 if (s.kind == PCK)
                     return true;
             } else if (target == names.TYPE_USE) {
-                if (s.kind == TYP || s.kind == VAR ||
+                if (s.kind == VAR && s.owner.kind == MTH && s.type.hasTag(NONE)) {
+                    //cannot type annotate implictly typed locals
+                    return false;
+                } else if (s.kind == TYP || s.kind == VAR ||
                         (s.kind == MTH && !s.isConstructor() &&
                                 !s.type.getReturnType().hasTag(VOID)) ||
                         (s.kind == MTH && s.isConstructor())) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java	Tue Sep 26 12:52:53 2017 +0100
@@ -529,7 +529,7 @@
             List<Type> upperBounds = uv.getBounds(InferenceBound.UPPER);
             if (Type.containsAny(upperBounds, vars)) {
                 TypeSymbol fresh_tvar = new TypeVariableSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner);
-                fresh_tvar.type = new TypeVar(fresh_tvar, types.makeIntersectionType(uv.getBounds(InferenceBound.UPPER)), null);
+                fresh_tvar.type = new TypeVar(fresh_tvar, types.makeIntersectionType(uv.getBounds(InferenceBound.UPPER)), syms.botType);
                 todo.append(uv);
                 uv.setInst(fresh_tvar.type);
             } else if (upperBounds.nonEmpty()) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Tue Sep 26 12:52:53 2017 +0100
@@ -259,7 +259,7 @@
         try {
             if (TreeInfo.isEnumInit(tree)) {
                 attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype);
-            } else {
+            } else if (!tree.isImplicitlyTyped()) {
                 attr.attribType(tree.vartype, localEnv);
                 if (TreeInfo.isReceiverParam(tree))
                     checkReceiver(tree, localEnv);
@@ -279,8 +279,8 @@
             tree.vartype.type = atype.makeVarargs();
         }
         WriteableScope enclScope = enter.enterScope(env);
-        VarSymbol v =
-            new VarSymbol(0, tree.name, tree.vartype.type, enclScope.owner);
+        Type vartype = tree.isImplicitlyTyped() ? Type.noType : tree.vartype.type;
+        VarSymbol v = new VarSymbol(0, tree.name, vartype, enclScope.owner);
         v.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, v, tree);
         tree.sym = v;
         if (tree.init != null) {
@@ -298,7 +298,9 @@
         }
 
         annotate.annotateLater(tree.mods.annotations, localEnv, v, tree.pos());
-        annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree.pos());
+        if (!tree.isImplicitlyTyped()) {
+            annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree.pos());
+        }
 
         v.pos = tree.pos;
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Tue Sep 26 12:52:53 2017 +0100
@@ -105,6 +105,7 @@
     public final boolean allowModules;
     public final boolean checkVarargsAccessAfterResolution;
     private final boolean compactMethodDiags;
+    private final boolean allowLocalVariableTypeInference;
     final EnumSet<VerboseResolutionMode> verboseResolutionMode;
 
     WriteableScope polymorphicSignatureScope;
@@ -136,6 +137,7 @@
         Target target = Target.instance(context);
         allowMethodHandles = target.hasMethodHandles();
         allowFunctionalInterfaceMostSpecific = source.allowFunctionalInterfaceMostSpecific();
+        allowLocalVariableTypeInference = source.allowLocalVariableTypeInference();
         checkVarargsAccessAfterResolution =
                 source.allowPostApplicabilityVarargsAccessCheck();
         polymorphicSignatureScope = WriteableScope.create(syms.noSymbol);
@@ -2325,6 +2327,10 @@
      *                   (a subset of VAL, TYP, PCK).
      */
     Symbol findIdent(Env<AttrContext> env, Name name, KindSelector kind) {
+        return checkVarType(findIdentInternal(env, name, kind), name);
+    }
+
+    Symbol findIdentInternal(Env<AttrContext> env, Name name, KindSelector kind) {
         Symbol bestSoFar = typeNotFound;
         Symbol sym;
 
@@ -2354,6 +2360,11 @@
      */
     Symbol findIdentInPackage(Env<AttrContext> env, TypeSymbol pck,
                               Name name, KindSelector kind) {
+        return checkVarType(findIdentInPackageInternal(env, pck, name, kind), name);
+    }
+
+    Symbol findIdentInPackageInternal(Env<AttrContext> env, TypeSymbol pck,
+                              Name name, KindSelector kind) {
         Name fullname = TypeSymbol.formFullName(name, pck);
         Symbol bestSoFar = typeNotFound;
         if (kind.contains(KindSelector.TYP)) {
@@ -2383,6 +2394,11 @@
      */
     Symbol findIdentInType(Env<AttrContext> env, Type site,
                            Name name, KindSelector kind) {
+        return checkVarType(findIdentInTypeInternal(env, site, name, kind), name);
+    }
+
+    Symbol findIdentInTypeInternal(Env<AttrContext> env, Type site,
+                           Name name, KindSelector kind) {
         Symbol bestSoFar = typeNotFound;
         Symbol sym;
         if (kind.contains(KindSelector.VAL)) {
@@ -2399,6 +2415,14 @@
         return bestSoFar;
     }
 
+    private Symbol checkVarType(Symbol bestSoFar, Name name) {
+        if (allowLocalVariableTypeInference && name.equals(names.var) &&
+                (bestSoFar.kind == TYP || bestSoFar.kind == ABSENT_TYP)) {
+            bestSoFar = new BadVarTypeError();
+        }
+        return bestSoFar;
+    }
+
 /* ***************************************************************************
  *  Access checking
  *  The following methods convert ResolveErrors to ErrorSymbols, issuing
@@ -3774,6 +3798,17 @@
         }
     }
 
+    class BadVarTypeError extends ResolveError {
+        BadVarTypeError() {
+            super(Kind.BAD_VAR, "bad var use");
+        }
+
+        @Override
+        JCDiagnostic getDiagnostic(DiagnosticType dkind, DiagnosticPosition pos, Symbol location, Type site, Name name, List<Type> argtypes, List<Type> typeargtypes) {
+            return diags.create(dkind, log.currentSource(), pos, "illegal.ref.to.var.type", name);
+        }
+    }
+
     /**
      * InvalidSymbolError error class indicating that a symbol matching a
      * given name does not exists in a given site.
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Tue Sep 26 12:52:53 2017 +0100
@@ -179,6 +179,7 @@
         this.allowAnnotationsAfterTypeParams = source.allowAnnotationsAfterTypeParams();
         this.allowUnderscoreIdentifier = source.allowUnderscoreIdentifier();
         this.allowPrivateInterfaceMethods = source.allowPrivateInterfaceMethods();
+        this.allowLocalVariableTypeInference = source.allowLocalVariableTypeInference();
         this.keepDocComments = keepDocComments;
         this.parseModuleInfo = parseModuleInfo;
         docComments = newDocCommentTable(keepDocComments, fac);
@@ -270,11 +271,14 @@
      */
     boolean allowThisIdent;
 
+    /** Switch: is local variable inference allowed?
+     */
+    boolean allowLocalVariableTypeInference;
+
     /** The type of the method receiver, as specified by a first "this" parameter.
      */
     JCVariableDecl receiverParam;
 
-
     /** When terms are parsed, the mode determines which is expected:
      *     mode = EXPR        : an expression
      *     mode = TYPE        : a type
@@ -808,12 +812,16 @@
      * parsing annotations.
      */
     public JCExpression parseType() {
-        List<JCAnnotation> annotations = typeAnnotationsOpt();
-        return parseType(annotations);
+        return parseType(false);
     }
 
-    public JCExpression parseType(List<JCAnnotation> annotations) {
-        JCExpression result = unannotatedType();
+    public JCExpression parseType(boolean allowVar) {
+        List<JCAnnotation> annotations = typeAnnotationsOpt();
+        return parseType(allowVar, annotations);
+    }
+
+    public JCExpression parseType(boolean allowVar, List<JCAnnotation> annotations) {
+        JCExpression result = unannotatedType(allowVar);
 
         if (annotations.nonEmpty()) {
             result = insertAnnotationsToMostInner(result, annotations, false);
@@ -822,10 +830,18 @@
         return result;
     }
 
-    public JCExpression unannotatedType() {
-        return term(TYPE);
+    public JCExpression unannotatedType(boolean allowVar) {
+        JCExpression result = term(TYPE);
+
+        if (!allowVar && isRestrictedLocalVarTypeName(result)) {
+            syntaxError(result.pos, "var.not.allowed.here");
+        }
+
+        return result;
     }
 
+
+
     protected JCExpression term(int newmode) {
         int prevmode = mode;
         mode = newmode;
@@ -1152,11 +1168,11 @@
                        accept(LPAREN);
                        mode = TYPE;
                        int pos1 = pos;
-                       List<JCExpression> targets = List.of(t = term3());
+                       List<JCExpression> targets = List.of(t = parseType());
                        while (token.kind == AMP) {
                            checkIntersectionTypesInCast();
                            accept(AMP);
-                           targets = targets.prepend(term3());
+                           targets = targets.prepend(parseType());
                        }
                        if (targets.length() > 1) {
                            t = toP(F.at(pos1).TypeIntersection(targets.reverse()));
@@ -1912,7 +1928,7 @@
      */
     JCExpression typeArgument() {
         List<JCAnnotation> annotations = typeAnnotationsOpt();
-        if (token.kind != QUES) return parseType(annotations);
+        if (token.kind != QUES) return parseType(false, annotations);
         int pos = token.pos;
         nextToken();
         JCExpression result;
@@ -2425,13 +2441,8 @@
                 token.kind == ENUM) {
                 return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
             } else {
-                JCExpression t = parseType();
-                ListBuffer<JCStatement> stats =
-                        variableDeclarators(mods, t, new ListBuffer<JCStatement>());
-                // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
-                accept(SEMI);
-                storeEnd(stats.last(), S.prevToken().endPos);
-                return stats.toList();
+                JCExpression t = parseType(true);
+                return localVariableDeclarations(mods, t);
             }
         }
         case ABSTRACT: case STRICTFP: {
@@ -2458,12 +2469,7 @@
                 pos = token.pos;
                 JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
                 F.at(pos);
-                ListBuffer<JCStatement> stats =
-                        variableDeclarators(mods, t, new ListBuffer<JCStatement>());
-                // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
-                accept(SEMI);
-                storeEnd(stats.last(), S.prevToken().endPos);
-                return stats.toList();
+                return localVariableDeclarations(mods, t);
             } else {
                 // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
                 t = checkExprStat(t);
@@ -2473,6 +2479,15 @@
             }
         }
     }
+    //where
+        private List<JCStatement> localVariableDeclarations(JCModifiers mods, JCExpression type) {
+            ListBuffer<JCStatement> stats =
+                    variableDeclarators(mods, type, new ListBuffer<>(), true);
+            // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
+            accept(SEMI);
+            storeEnd(stats.last(), S.prevToken().endPos);
+            return stats.toList();
+        }
 
     /** Statement =
      *       Block
@@ -2766,11 +2781,11 @@
         ListBuffer<JCStatement> stats = new ListBuffer<>();
         int pos = token.pos;
         if (token.kind == FINAL || token.kind == MONKEYS_AT) {
-            return variableDeclarators(optFinal(0), parseType(), stats).toList();
+            return variableDeclarators(optFinal(0), parseType(true), stats, true).toList();
         } else {
             JCExpression t = term(EXPR | TYPE);
             if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) {
-                return variableDeclarators(modifiersOpt(), t, stats).toList();
+                return variableDeclarators(modifiersOpt(), t, stats, true).toList();
             } else if ((lastmode & TYPE) != 0 && token.kind == COLON) {
                 error(pos, "bad.initializer", "for-loop");
                 return List.of((JCStatement)F.at(pos).VarDef(null, null, t, null));
@@ -2989,9 +3004,10 @@
      */
     public <T extends ListBuffer<? super JCVariableDecl>> T variableDeclarators(JCModifiers mods,
                                                                          JCExpression type,
-                                                                         T vdefs)
+                                                                         T vdefs,
+                                                                         boolean localDecl)
     {
-        return variableDeclaratorsRest(token.pos, mods, type, ident(), false, null, vdefs);
+        return variableDeclaratorsRest(token.pos, mods, type, ident(), false, null, vdefs, localDecl);
     }
 
     /** VariableDeclaratorsRest = VariableDeclaratorRest { "," VariableDeclarator }
@@ -3006,14 +3022,20 @@
                                                                      Name name,
                                                                      boolean reqInit,
                                                                      Comment dc,
-                                                                     T vdefs)
+                                                                     T vdefs,
+                                                                     boolean localDecl)
     {
-        vdefs.append(variableDeclaratorRest(pos, mods, type, name, reqInit, dc));
+        JCVariableDecl head = variableDeclaratorRest(pos, mods, type, name, reqInit, dc, localDecl);
+        boolean implicit = allowLocalVariableTypeInference && head.vartype == null;
+        vdefs.append(head);
         while (token.kind == COMMA) {
+            if (implicit) {
+                reportSyntaxError(pos, "var.not.allowed.compound");
+            }
             // All but last of multiple declarators subsume a comma
             storeEnd((JCTree)vdefs.last(), token.endPos);
             nextToken();
-            vdefs.append(variableDeclarator(mods, type, reqInit, dc));
+            vdefs.append(variableDeclarator(mods, type, reqInit, dc, localDecl));
         }
         return vdefs;
     }
@@ -3021,8 +3043,8 @@
     /** VariableDeclarator = Ident VariableDeclaratorRest
      *  ConstantDeclarator = Ident ConstantDeclaratorRest
      */
-    JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, Comment dc) {
-        return variableDeclaratorRest(token.pos, mods, type, ident(), reqInit, dc);
+    JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, Comment dc, boolean localDecl) {
+        return variableDeclaratorRest(token.pos, mods, type, ident(), reqInit, dc, localDecl);
     }
 
     /** VariableDeclaratorRest = BracketsOpt ["=" VariableInitializer]
@@ -3032,7 +3054,7 @@
      *  @param dc       The documentation comment for the variable declarations, or null.
      */
     JCVariableDecl variableDeclaratorRest(int pos, JCModifiers mods, JCExpression type, Name name,
-                                  boolean reqInit, Comment dc) {
+                                  boolean reqInit, Comment dc, boolean localDecl) {
         type = bracketsOpt(type);
         JCExpression init = null;
         if (token.kind == EQ) {
@@ -3040,12 +3062,40 @@
             init = variableInitializer();
         }
         else if (reqInit) syntaxError(token.pos, "expected", EQ);
+        JCTree elemType = TreeInfo.innermostType(type, true);
+        if (allowLocalVariableTypeInference && elemType.hasTag(IDENT)) {
+            Name typeName = ((JCIdent)elemType).name;
+            if (isRestrictedLocalVarTypeName(typeName)) {
+                if (type.hasTag(TYPEARRAY)) {
+                    //error - 'var' and arrays
+                    reportSyntaxError(pos, "var.not.allowed.array");
+                } else {
+                    //implicit type
+                    type = null;
+                }
+            }
+        }
         JCVariableDecl result =
             toP(F.at(pos).VarDef(mods, name, type, init));
         attach(result, dc);
         return result;
     }
 
+    boolean isRestrictedLocalVarTypeName(JCExpression e) {
+        switch (e.getTag()) {
+            case IDENT:
+                return isRestrictedLocalVarTypeName(((JCIdent)e).name);
+            case TYPEARRAY:
+                return isRestrictedLocalVarTypeName(((JCArrayTypeTree)e).elemtype);
+            default:
+                return false;
+        }
+    }
+
+    boolean isRestrictedLocalVarTypeName(Name name) {
+        return allowLocalVariableTypeInference && name == names.var;
+    }
+
     /** VariableDeclaratorId = Ident BracketsOpt
      */
     JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type) {
@@ -3111,13 +3161,13 @@
         int startPos = token.pos;
         if (token.kind == FINAL || token.kind == MONKEYS_AT) {
             JCModifiers mods = optFinal(Flags.FINAL);
-            JCExpression t = parseType();
-            return variableDeclaratorRest(token.pos, mods, t, ident(), true, null);
+            JCExpression t = parseType(true);
+            return variableDeclaratorRest(token.pos, mods, t, ident(), true, null, true);
         }
         JCExpression t = term(EXPR | TYPE);
         if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) {
             JCModifiers mods = toP(F.at(startPos).Modifiers(Flags.FINAL));
-            return variableDeclaratorRest(token.pos, mods, t, ident(), true, null);
+            return variableDeclaratorRest(token.pos, mods, t, ident(), true, null, true);
         } else {
             checkVariableInTryWithResources(startPos);
             if (!t.hasTag(IDENT) && !t.hasTag(SELECT)) {
@@ -3397,7 +3447,7 @@
     protected JCClassDecl classDeclaration(JCModifiers mods, Comment dc) {
         int pos = token.pos;
         accept(CLASS);
-        Name name = ident();
+        Name name = typeName();
 
         List<JCTypeParameter> typarams = typeParametersOpt();
 
@@ -3418,6 +3468,15 @@
         return result;
     }
 
+    Name typeName() {
+        int pos = token.pos;
+        Name name = ident();
+        if (isRestrictedLocalVarTypeName(name)) {
+            reportSyntaxError(pos, "var.not.allowed", name);
+        }
+        return name;
+    }
+
     /** InterfaceDeclaration = INTERFACE Ident TypeParametersOpt
      *                         [EXTENDS TypeList] InterfaceBody
      *  @param mods    The modifiers starting the interface declaration
@@ -3426,7 +3485,8 @@
     protected JCClassDecl interfaceDeclaration(JCModifiers mods, Comment dc) {
         int pos = token.pos;
         accept(INTERFACE);
-        Name name = ident();
+
+        Name name = typeName();
 
         List<JCTypeParameter> typarams = typeParametersOpt();
 
@@ -3449,7 +3509,8 @@
     protected JCClassDecl enumDeclaration(JCModifiers mods, Comment dc) {
         int pos = token.pos;
         accept(ENUM);
-        Name name = ident();
+
+        Name name = typeName();
 
         List<JCExpression> implementing = List.nil();
         if (token.kind == IMPLEMENTS) {
@@ -3647,7 +3708,7 @@
                     nextToken();
                 } else {
                     // method returns types are un-annotated types
-                    type = unannotatedType();
+                    type = unannotatedType(false);
                 }
                 if (token.kind == LPAREN && !isInterface && type.hasTag(IDENT)) {
                     if (isInterface || tk.name() != className)
@@ -3667,7 +3728,7 @@
                     } else if (!isVoid && typarams.isEmpty()) {
                         List<JCTree> defs =
                             variableDeclaratorsRest(pos, mods, type, name, isInterface, dc,
-                                                    new ListBuffer<JCTree>()).toList();
+                                                    new ListBuffer<JCTree>(), false).toList();
                         accept(SEMI);
                         storeEnd(defs.last(), S.prevToken().endPos);
                         return defs;
@@ -3809,7 +3870,7 @@
     JCTypeParameter typeParameter() {
         int pos = token.pos;
         List<JCAnnotation> annos = typeAnnotationsOpt();
-        Name name = ident();
+        Name name = typeName();
         ListBuffer<JCExpression> bounds = new ListBuffer<>();
         if (token.kind == EXTENDS) {
             nextToken();
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Tue Sep 26 12:52:53 2017 +0100
@@ -1190,6 +1190,47 @@
 compiler.err.undef.label=\
     undefined label: {0}
 
+# 0: name (type)
+compiler.err.illegal.ref.to.var.type=\
+    illegal reference to restricted type ''{0}''
+
+# 0: token
+compiler.err.var.not.allowed=\
+    ''{0}'' not allowed here\n\
+    as of release 10, ''{0}'' is a restricted local variable type and cannot be used for type declarations
+
+# 0: name (variable), 1: message segment
+compiler.err.cant.infer.local.var.type=\
+    cannot infer type for local variable {0}\n\
+    ({1})
+
+compiler.err.var.not.allowed.here=\
+    ''var'' is not allowed here
+
+compiler.err.var.not.allowed.array=\
+    ''var'' is not allowed as an element type of an array
+
+compiler.err.var.not.allowed.compound=\
+    ''var'' is not allowed in a compound declaration
+
+compiler.misc.local.cant.infer.null=\
+    variable initializer is ''null''
+
+compiler.misc.local.missing.init=\
+    cannot use ''var'' on variable without initializer
+
+compiler.misc.local.lambda.missing.target=\
+    lambda expression needs an explicit target-type
+
+compiler.misc.local.mref.missing.target=\
+    method reference needs an explicit target-type
+
+compiler.misc.local.array.missing.target=\
+    array initializer needs an explicit target-type
+
+compiler.misc.local.self.ref=\
+    cannot use ''var'' on self-referencing variable
+
 # 0: message segment, 1: unused
 compiler.err.cant.apply.diamond=\
     cannot infer type arguments for {0}
@@ -1873,6 +1914,9 @@
 compiler.warn.diamond.redundant.args=\
     Redundant type arguments in new expression (use diamond operator instead).
 
+compiler.warn.local.redundant.type=\
+    Redundant type for local variable (replace explicit type with ''var'').
+
 compiler.warn.potential.lambda.found=\
     This anonymous inner class creation can be turned into a lambda expression.
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Tue Sep 26 12:52:53 2017 +0100
@@ -946,6 +946,10 @@
             }
         }
 
+        public boolean isImplicitlyTyped() {
+            return vartype == null;
+        }
+
         @Override
         public void accept(Visitor v) { v.visitVarDef(this); }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java	Tue Sep 26 12:52:53 2017 +0100
@@ -1359,7 +1359,7 @@
 
     // Prints the inner element type of a nested array
     private void printBaseElementType(JCTree tree) throws IOException {
-        printExpr(TreeInfo.innermostType(tree));
+        printExpr(TreeInfo.innermostType(tree, false));
     }
 
     // prints the brackets of a nested array in reverse order
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Tue Sep 26 12:52:53 2017 +0100
@@ -1136,7 +1136,7 @@
      * For an array that contains an annotated type, return that annotated type.
      * TODO: currently only used by Pretty. Describe behavior better.
      */
-    public static JCTree innermostType(JCTree type) {
+    public static JCTree innermostType(JCTree type, boolean skipAnnos) {
         JCTree lastAnnotatedType = null;
         JCTree cur = type;
         loop: while (true) {
@@ -1157,7 +1157,7 @@
                 break loop;
             }
         }
-        if (lastAnnotatedType!=null) {
+        if (!skipAnnos && lastAnnotatedType!=null) {
             return lastAnnotatedType;
         } else {
             return cur;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java	Tue Sep 26 12:52:53 2017 +0100
@@ -63,6 +63,7 @@
     public final Name _default;
     public final Name _super;
     public final Name _this;
+    public final Name var;
     public final Name exports;
     public final Name opens;
     public final Name module;
@@ -224,6 +225,7 @@
         _default = fromString("default");
         _super = fromString("super");
         _this = fromString("this");
+        var = fromString("var");
         exports = fromString("exports");
         opens = fromString("opens");
         module = fromString("module");
--- a/src/jdk.compiler/share/classes/module-info.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.compiler/share/classes/module-info.java	Tue Sep 26 12:52:53 2017 +0100
@@ -106,7 +106,8 @@
     exports com.sun.tools.javac.jvm to
         jdk.javadoc;
     exports com.sun.tools.javac.main to
-        jdk.javadoc;
+        jdk.javadoc,
+        jdk.jshell;
     exports com.sun.tools.javac.model to
         jdk.javadoc;
     exports com.sun.tools.javac.parser to
--- a/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Tue Sep 26 12:52:53 2017 +0100
@@ -40,6 +40,7 @@
 import com.sun.source.tree.IdentifierTree;
 import com.sun.source.tree.MethodTree;
 import com.sun.source.tree.ModifiersTree;
+import com.sun.source.tree.NewClassTree;
 import com.sun.source.tree.Tree;
 import com.sun.source.tree.VariableTree;
 import com.sun.tools.javac.tree.JCTree;
@@ -59,6 +60,7 @@
 import jdk.jshell.TaskFactory.BaseTask;
 import jdk.jshell.TaskFactory.CompileTask;
 import jdk.jshell.TaskFactory.ParseTask;
+import jdk.jshell.Wrap.CompoundWrap;
 import jdk.jshell.Wrap.Range;
 import jdk.jshell.Snippet.Status;
 import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
@@ -274,26 +276,119 @@
         for (Tree unitTree : units) {
             VariableTree vt = (VariableTree) unitTree;
             String name = vt.getName().toString();
-            String typeName = EvalPretty.prettyExpr((JCTree) vt.getType(), false);
-            Tree baseType = vt.getType();
+            String typeName;
+            String fullTypeName;
             TreeDependencyScanner tds = new TreeDependencyScanner();
-            tds.scan(baseType); // Not dependent on initializer
+            Wrap typeWrap;
+            Wrap anonDeclareWrap = null;
+            Wrap winit = null;
             StringBuilder sbBrackets = new StringBuilder();
-            while (baseType instanceof ArrayTypeTree) {
-                //TODO handle annotations too
-                baseType = ((ArrayTypeTree) baseType).getType();
-                sbBrackets.append("[]");
+            Tree baseType = vt.getType();
+            if (baseType != null) {
+                tds.scan(baseType); // Not dependent on initializer
+                fullTypeName = typeName = EvalPretty.prettyExpr((JCTree) vt.getType(), false);
+                while (baseType instanceof ArrayTypeTree) {
+                    //TODO handle annotations too
+                    baseType = ((ArrayTypeTree) baseType).getType();
+                    sbBrackets.append("[]");
+                }
+                Range rtype = dis.treeToRange(baseType);
+                typeWrap = Wrap.rangeWrap(compileSource, rtype);
+            } else {
+                Tree init = vt.getInitializer();
+                if (init != null) {
+                    Range rinit = dis.treeToRange(init);
+                    String initCode = rinit.part(compileSource);
+                    ExpressionInfo ei =
+                            ExpressionToTypeInfo.localVariableTypeForInitializer(initCode, state);
+                    typeName = ei == null ? "java.lang.Object" : ei.typeName;
+                    fullTypeName = ei == null ? "java.lang.Object" : ei.fullTypeName;
+                    if (ei != null && init.getKind() == Tree.Kind.NEW_CLASS &&
+                        ((NewClassTree) init).getClassBody() != null) {
+                        NewClassTree nct = (NewClassTree) init;
+                        StringBuilder constructor = new StringBuilder();
+                        constructor.append(fullTypeName).append("(");
+                        String sep = "";
+                        if (ei.enclosingInstanceType != null) {
+                            constructor.append(ei.enclosingInstanceType);
+                            constructor.append(" encl");
+                            sep = ", ";
+                        }
+                        int idx = 0;
+                        for (String type : ei.parameterTypes) {
+                            constructor.append(sep);
+                            constructor.append(type);
+                            constructor.append(" ");
+                            constructor.append("arg" + idx++);
+                            sep = ", ";
+                        }
+                        if (ei.enclosingInstanceType != null) {
+                            constructor.append(") { encl.super (");
+                        } else {
+                            constructor.append(") { super (");
+                        }
+                        sep = "";
+                        for (int i = 0; i < idx; i++) {
+                            constructor.append(sep);
+                            constructor.append("arg" + i++);
+                            sep = ", ";
+                        }
+                        constructor.append("); }");
+                        List<? extends Tree> members = nct.getClassBody().getMembers();
+                        Range bodyRange = dis.treeListToRange(members);
+                        Wrap bodyWrap;
+
+                        if (bodyRange != null) {
+                            bodyWrap = Wrap.rangeWrap(compileSource, bodyRange);
+                        } else {
+                            bodyWrap = Wrap.simpleWrap(" ");
+                        }
+
+                        Range argRange = dis.treeListToRange(nct.getArguments());
+                        Wrap argWrap;
+
+                        if (argRange != null) {
+                            argWrap = Wrap.rangeWrap(compileSource, argRange);
+                        } else {
+                            argWrap = Wrap.simpleWrap(" ");
+                        }
+
+                        if (ei.enclosingInstanceType != null) {
+                            Range enclosingRanges =
+                                    dis.treeToRange(nct.getEnclosingExpression());
+                            Wrap enclosingWrap = Wrap.rangeWrap(compileSource, enclosingRanges);
+                            argWrap = argRange != null ? new CompoundWrap(enclosingWrap,
+                                                                          Wrap.simpleWrap(","),
+                                                                          argWrap)
+                                                       : enclosingWrap;
+                        }
+                        Wrap hwrap = Wrap.simpleWrap("public static class " + fullTypeName +
+                                                     (ei.isClass ? " extends " : " implements ") +
+                                                     typeName + " { " + constructor);
+                        anonDeclareWrap = new CompoundWrap(hwrap, bodyWrap, Wrap.simpleWrap("}"));
+                        winit = new CompoundWrap("new " + fullTypeName + "(", argWrap, ")");
+
+                        String superType = typeName;
+
+                        typeName = fullTypeName;
+                        fullTypeName = ei.isClass ? "<anonymous class extending " + superType + ">"
+                                                  : "<anonymous class implementing " + superType + ">";
+                    }
+                    tds.scan(init);
+                } else {
+                    fullTypeName = typeName = "java.lang.Object";
+                }
+                typeWrap = Wrap.identityWrap(typeName);
             }
-            Range rtype = dis.treeToRange(baseType);
             Range runit = dis.treeToRange(vt);
             runit = new Range(runit.begin, runit.end - 1);
             ExpressionTree it = vt.getInitializer();
-            Range rinit = null;
             int nameMax = runit.end - 1;
             SubKind subkind;
             if (it != null) {
                 subkind = SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND;
-                rinit = dis.treeToRange(it);
+                Range rinit = dis.treeToRange(it);
+                winit = winit == null ? Wrap.rangeWrap(compileSource, rinit) : winit;
                 nameMax = rinit.begin - 1;
             } else {
                 subkind = SubKind.VAR_DECLARATION_SUBKIND;
@@ -304,10 +399,11 @@
             }
             int nameEnd = nameStart + name.length();
             Range rname = new Range(nameStart, nameEnd);
-            Wrap guts = Wrap.varWrap(compileSource, rtype, sbBrackets.toString(), rname, rinit);
-            DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true);
+            Wrap guts = Wrap.varWrap(compileSource, typeWrap, sbBrackets.toString(), rname,
+                                     winit, anonDeclareWrap);
+                        DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true);
             Snippet snip = new VarSnippet(state.keyMap.keyForVariable(name), userSource, guts,
-                    name, subkind, typeName,
+                    name, subkind, fullTypeName,
                     tds.declareReferences(), modDiag);
             snippets.add(snip);
         }
--- a/src/jdk.jshell/share/classes/jdk/jshell/ExpressionToTypeInfo.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.jshell/share/classes/jdk/jshell/ExpressionToTypeInfo.java	Tue Sep 26 12:52:53 2017 +0100
@@ -29,14 +29,20 @@
 import com.sun.source.tree.ClassTree;
 import com.sun.source.tree.CompilationUnitTree;
 import com.sun.source.tree.ConditionalExpressionTree;
+import com.sun.source.tree.ExpressionStatementTree;
 import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.MethodInvocationTree;
 import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.NewClassTree;
 import com.sun.source.tree.Tree;
+import com.sun.source.tree.Tree.Kind;
+import com.sun.source.tree.VariableTree;
 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 com.sun.tools.javac.util.List;
 import jdk.jshell.TaskFactory.AnalyzeTask;
 
 /**
@@ -63,6 +69,10 @@
     public static class ExpressionInfo {
         ExpressionTree tree;
         String typeName;
+        String fullTypeName;
+        List<String> parameterTypes;
+        String enclosingInstanceType;
+        boolean isClass;
         boolean isNonVoid;
     }
 
@@ -111,6 +121,16 @@
                 return null;
             }
         }
+
+        @Override
+        public TreePath visitVariable(VariableTree node, Boolean isTargetContext) {
+            if (isTargetContext) {
+                throw new Result(getCurrentPath());
+            } else {
+                return null;
+            }
+        }
+
     }
 
     private Type pathToType(TreePath tp) {
@@ -156,6 +176,30 @@
         }
     }
 
+    /**
+     * Entry method: get expression info corresponding to a local variable declaration if its type
+     * has been inferred automatically from the given initializer.
+     * @param code the initializer as a string
+     * @param state a JShell instance
+     * @return type information
+     */
+    public static ExpressionInfo localVariableTypeForInitializer(String code, JShell state) {
+        if (code == null || code.isEmpty()) {
+            return null;
+        }
+        try {
+            OuterWrap codeWrap = state.outerMap.wrapInTrialClass(Wrap.methodWrap("var $$$ = " + 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());
     }
@@ -172,9 +216,11 @@
     private ExpressionInfo treeToInfo(TreePath tp) {
         if (tp != null) {
             Tree tree = tp.getLeaf();
-            if (tree instanceof ExpressionTree) {
+            boolean isExpression = tree instanceof ExpressionTree;
+            if (isExpression || tree.getKind() == Kind.VARIABLE) {
                 ExpressionInfo ei = new ExpressionInfo();
-                ei.tree = (ExpressionTree) tree;
+                if (isExpression)
+                    ei.tree = (ExpressionTree) tree;
                 Type type = pathToType(tp, tree);
                 if (type != null) {
                     switch (type.getKind()) {
@@ -189,27 +235,56 @@
                             break;
                         default: {
                             ei.isNonVoid = true;
-                            ei.typeName = varTypeName(type);
-                            if (ei.typeName == null) {
-                                ei.typeName = OBJECT_TYPE_NAME;
-                            }
+                            ei.typeName = varTypeName(type, false);
+                            ei.fullTypeName = varTypeName(type, true);
                             break;
                         }
                     }
                 }
+                if (tree.getKind() == Tree.Kind.VARIABLE) {
+                    Tree init = ((VariableTree) tree).getInitializer();
+                    if (init.getKind() == Tree.Kind.NEW_CLASS &&
+                        ((NewClassTree) init).getClassBody() != null) {
+                        NewClassTree nct = (NewClassTree) init;
+                        ClassTree clazz = nct.getClassBody();
+                        MethodTree constructor = (MethodTree) clazz.getMembers().get(0);
+                        ExpressionStatementTree superCallStatement =
+                                (ExpressionStatementTree) constructor.getBody().getStatements().get(0);
+                        MethodInvocationTree superCall =
+                                (MethodInvocationTree) superCallStatement.getExpression();
+                        TreePath superCallPath =
+                                at.trees().getPath(tp.getCompilationUnit(), superCall.getMethodSelect());
+                        Type constrType = pathToType(superCallPath);
+                        ei.parameterTypes = constrType.getParameterTypes()
+                                                      .stream()
+                                                      .map(t -> varTypeName(t, false))
+                                                      .collect(List.collector());
+                        if (nct.getEnclosingExpression() != null) {
+                            TreePath enclPath = new TreePath(tp, nct.getEnclosingExpression());
+                            ei.enclosingInstanceType = varTypeName(pathToType(enclPath), false);
+                        }
+                        ei.isClass = at.task.getTypes().directSupertypes(type).size() == 1;
+                    }
+                }
                 return ei;
             }
         }
         return null;
     }
 
-    private String varTypeName(Type type) {
+    private String varTypeName(Type type, boolean printIntersectionTypes) {
         try {
-            TypePrinter tp = new VarTypePrinter(at.messages(),
-                    state.maps::fullClassNameAndPackageToClass, syms, types);
-            return tp.toString(type);
+            TypePrinter tp = new TypePrinter(at.messages(),
+                    state.maps::fullClassNameAndPackageToClass, printIntersectionTypes);
+            List<Type> captures = types.captures(type);
+            String res = tp.toString(types.upward(type, captures));
+
+            if (res == null)
+                res = OBJECT_TYPE_NAME;
+
+            return res;
         } catch (Exception ex) {
-            return null;
+            return OBJECT_TYPE_NAME;
         }
     }
 
--- a/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java	Tue Sep 26 12:52:53 2017 +0100
@@ -232,7 +232,7 @@
                             //mods.flags |= Flags.STATIC;
                             List<JCTree> defs
                                     = variableDeclaratorsRest(pos, mods, t, name, false, dc,
-                                            new ListBuffer<JCTree>()).toList();
+                                            new ListBuffer<JCTree>(), true).toList();
                             accept(SEMI);
                             storeEnd(defs.last(), S.prevToken().endPos);
                             return defs;
--- a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java	Tue Sep 26 12:52:53 2017 +0100
@@ -134,6 +134,8 @@
 
 import static java.util.stream.Collectors.joining;
 
+import javax.lang.model.type.IntersectionType;
+
 /**
  * The concrete implementation of SourceCodeAnalysis.
  * @author Robert Field
@@ -715,6 +717,13 @@
             return Collections.emptyList();
 
         switch (site.getKind()) {
+            case INTERSECTION: {
+                List<Element> result = new ArrayList<>();
+                for (TypeMirror bound : ((IntersectionType) site).getBounds()) {
+                    result.addAll(membersOf(at, bound, shouldGenerateDotClassItem));
+                }
+                return result;
+            }
             case DECLARED: {
                 TypeElement element = (TypeElement) at.getTypes().asElement(site);
                 List<Element> result = new ArrayList<>();
--- a/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java	Tue Sep 26 12:52:53 2017 +0100
@@ -61,7 +61,20 @@
 import javax.tools.FileObject;
 import jdk.jshell.MemoryFileManager.SourceMemoryJavaFileObject;
 import java.lang.Runtime.Version;
+import java.nio.CharBuffer;
 import com.sun.source.tree.Tree.Kind;
+import com.sun.tools.javac.code.Kinds;
+import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import com.sun.tools.javac.code.Symbol.VarSymbol;
+import com.sun.tools.javac.parser.Parser;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCTypeCast;
+import com.sun.tools.javac.tree.JCTree.Tag;
+import com.sun.tools.javac.util.Context.Factory;
+import com.sun.tools.javac.util.Log.DiscardDiagnosticHandler;
+import jdk.jshell.Snippet.Status;
 
 /**
  * The primary interface to the compiler API.  Parsing, analysis, and
@@ -355,6 +368,7 @@
             Iterable<? extends JavaFileObject> compilationUnits = inputs
                             .map(in -> sh.sourceToFileObject(fileManager, in))
                             .collect(Collectors.toList());
+            JShellJavaCompiler.preRegister(context, state);
             this.task = (JavacTaskImpl) ((JavacTool) compiler).getTask(null,
                     fileManager, diagnostics, options, null,
                     compilationUnits, context);
@@ -464,4 +478,57 @@
         }
     }
 
+    private static final class JShellJavaCompiler extends com.sun.tools.javac.main.JavaCompiler {
+
+        public static void preRegister(Context c, JShell state) {
+            c.put(compilerKey, (Factory<com.sun.tools.javac.main.JavaCompiler>) i -> new JShellJavaCompiler(i, state));
+        }
+
+        private final JShell state;
+
+        public JShellJavaCompiler(Context context, JShell state) {
+            super(context);
+            this.state = state;
+        }
+
+        @Override
+        public void processAnnotations(com.sun.tools.javac.util.List<JCCompilationUnit> roots, Collection<String> classnames) {
+            super.processAnnotations(roots, classnames);
+            state.maps
+                 .snippetList()
+                 .stream()
+                 .filter(s -> s.status() == Status.VALID)
+                 .filter(s -> s.kind() == Snippet.Kind.VAR)
+                 .filter(s -> s.subKind() == Snippet.SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND)
+                 .forEach(s -> setVariableType(roots, (VarSnippet) s));
+        }
+
+        private void setVariableType(com.sun.tools.javac.util.List<JCCompilationUnit> roots, VarSnippet s) {
+            ClassSymbol clazz = syms.getClass(syms.unnamedModule, names.fromString(s.classFullName()));
+            if (clazz == null || !clazz.isCompleted())
+                return;
+            VarSymbol field = (VarSymbol) clazz.members().findFirst(names.fromString(s.name()), sym -> sym.kind == Kinds.Kind.VAR);
+            if (field != null) {
+                JavaFileObject prev = log.useSource(null);
+                DiscardDiagnosticHandler h = new DiscardDiagnosticHandler(log);
+                try {
+                    String typeName = s.typeName();
+                    CharBuffer buf = CharBuffer.wrap(("(" + typeName +")x\u0000").toCharArray(), 0, typeName.length() + 3);
+                    Parser parser = parserFactory.newParser(buf, false, false, false);
+                    JCExpression expr = parser.parseExpression();
+                    if (expr.hasTag(Tag.TYPECAST)) {
+                        JCTypeCast tree = (JCTypeCast) expr;
+                        if (tree.clazz.hasTag(Tag.TYPEINTERSECTION)) {
+                            field.type = attr.attribType(tree.clazz,
+                                                         ((JCClassDecl) roots.head.getTypeDecls().head).sym);
+                        }
+                    }
+                } finally {
+                    log.popDiagnosticHandler(h);
+                    log.useSource(prev);
+                }
+            }
+        }
+    }
+
 }
--- a/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java	Tue Sep 26 12:52:53 2017 +0100
@@ -227,7 +227,7 @@
         Type typeImpl = (Type) type;
         try {
             TypePrinter tp = new TypePrinter(at.messages(),
-                    state.maps::fullClassNameAndPackageToClass);
+                    state.maps::fullClassNameAndPackageToClass, true);
             return tp.toString(typeImpl);
         } catch (Exception ex) {
             return null;
--- a/src/jdk.jshell/share/classes/jdk/jshell/TypePrinter.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.jshell/share/classes/jdk/jshell/TypePrinter.java	Tue Sep 26 12:52:53 2017 +0100
@@ -32,9 +32,11 @@
 import com.sun.tools.javac.code.Symbol.PackageSymbol;
 import com.sun.tools.javac.code.Type;
 import com.sun.tools.javac.code.Type.ClassType;
+import com.sun.tools.javac.code.Type.IntersectionClassType;
 import com.sun.tools.javac.util.JavacMessages;
 import java.util.Locale;
 import java.util.function.BinaryOperator;
+import java.util.stream.Collectors;
 
 /**
  * Print types in source form.
@@ -45,10 +47,14 @@
 
     private final JavacMessages messages;
     private final BinaryOperator<String> fullClassNameAndPackageToClass;
+    private final boolean printEnhancedTypes;
 
-    TypePrinter(JavacMessages messages, BinaryOperator<String> fullClassNameAndPackageToClass) {
+    TypePrinter(JavacMessages messages,
+                BinaryOperator<String> fullClassNameAndPackageToClass,
+                boolean printEnhancedTypes) {
         this.messages = messages;
         this.fullClassNameAndPackageToClass = fullClassNameAndPackageToClass;
+        this.printEnhancedTypes = printEnhancedTypes;
     }
 
     String toString(Type t) {
@@ -92,8 +98,18 @@
     protected String className(ClassType t, boolean longform, Locale locale) {
         Symbol sym = t.tsym;
         if (sym.name.length() == 0 && (sym.flags() & COMPOUND) != 0) {
-            return OBJECT;
+            if (printEnhancedTypes) {
+                return ((IntersectionClassType) t).getExplicitComponents()
+                                                  .stream()
+                                                  .map(i -> visit(i, locale))
+                                                  .collect(Collectors.joining("&"));
+            } else {
+                return OBJECT;
+            }
         } else if (sym.name.length() == 0) {
+            if (printEnhancedTypes) {
+                return t.tsym.flatName().toString().substring(t.tsym.outermostClass().flatName().length());
+            }
             // Anonymous
             String s;
             ClassType norm = (ClassType) t.tsym.type;
--- a/src/jdk.jshell/share/classes/jdk/jshell/VarTypePrinter.java	Tue Sep 26 15:08:56 2017 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,265 +0,0 @@
-/*
- * 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.StructuralTypeMapping;
-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 StructuralTypeMapping<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.map(ta -> mapTypeArgument(ta, upward));
-                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/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java	Tue Sep 26 12:52:53 2017 +0100
@@ -74,16 +74,15 @@
      * @param rdecl Type name and name
      * @return
      */
-    public static Wrap varWrap(String source, Range rtype, String brackets, Range rname, Range rinit) {
+    public static Wrap varWrap(String source, Wrap wtype, String brackets,
+                               Range rname, Wrap winit, Wrap anonDeclareWrap) {
         RangeWrap wname = new RangeWrap(source, rname);
-        RangeWrap wtype = new RangeWrap(source, rtype);
         Wrap wVarDecl = new VarDeclareWrap(wtype, brackets, wname);
         Wrap wmeth;
 
-        if (rinit == null) {
+        if (winit == null) {
             wmeth = new CompoundWrap(new NoWrap(" "), "   return null;\n");
         } else {
-            RangeWrap winit = new RangeWrap(source, rinit);
         // int x = y
             // int x_ = y; return x = x_;
             // decl + "_ = " + init ; + "return " + name + "=" + name + "_ ;"
@@ -93,7 +92,8 @@
             );
         }
         Wrap wInitMeth = new DoitMethodWrap(wmeth);
-        return new CompoundWrap(wVarDecl, wInitMeth);
+        return anonDeclareWrap != null ? new CompoundWrap(wVarDecl, wInitMeth, anonDeclareWrap)
+                                       : new CompoundWrap(wVarDecl, wInitMeth);
     }
 
     public static Wrap tempVarWrap(String source, String typename, String name) {
@@ -112,6 +112,14 @@
         return new NoWrap(source);
     }
 
+    public static Wrap identityWrap(String source) {
+        return new NoWrap(source);
+    }
+
+    public static Wrap rangeWrap(String source, Range range) {
+        return new RangeWrap(source, range);
+    }
+
     public static Wrap classMemberWrap(String source) {
         Wrap w = new NoWrap(source);
         return new CompoundWrap("    public static\n    ", w);
--- a/test/langtools/jdk/jshell/CompletionSuggestionTest.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/test/langtools/jdk/jshell/CompletionSuggestionTest.java	Tue Sep 26 12:52:53 2017 +0100
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8131025 8141092 8153761 8145263 8131019 8175886 8176184 8176241 8176110
+ * @bug 8131025 8141092 8153761 8145263 8131019 8175886 8176184 8176241 8176110 8177466
  * @summary Test Completion and Documentation
  * @library /tools/lib
  * @modules jdk.compiler/com.sun.tools.javac.api
@@ -645,6 +645,22 @@
         assertCompletion("Foo.m(new Baz<>(|", true, "str");
     }
 
+    public void testIntersection() {
+        assertEval("<Z extends Runnable & CharSequence> Z get() { return null; }");
+        assertEval("var v = get();");
+        assertCompletionIncludesExcludes("v.|", true, Set.of("run()", "length()"), Set.of());
+        assertCompletion("Runnable r = |", true, "get()", "v");
+        assertCompletion("CharSequence r = |", true, "get()", "v");
+        assertCompletion("Number r = |", true);
+    }
+
+    public void testAnonymous() {
+        assertEval("var v = new Runnable() { public void run() { } public int length() { return 0; } };");
+        assertCompletionIncludesExcludes("v.|", true, Set.of("run()", "length()"), Set.of());
+        assertCompletion("Runnable r = |", true, "v");
+        assertCompletion("CharSequence r = |", true);
+    }
+
     @BeforeMethod
     public void setUp() {
         super.setUp();
--- a/test/langtools/jdk/jshell/ToolSimpleTest.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/test/langtools/jdk/jshell/ToolSimpleTest.java	Tue Sep 26 12:52:53 2017 +0100
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102 8172103  8165405 8173073 8173848 8174041 8173916 8174028 8174262 8174797 8177079 8180508
+ * @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102 8172103  8165405 8173073 8173848 8174041 8173916 8174028 8174262 8174797 8177079 8180508 8177466
  * @summary Simple jshell tool tests
  * @modules jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.main
@@ -740,4 +740,26 @@
                 (a) -> assertCommandOutputContains(a, "1234", "==> 1234")
         );
     }
+
+    @Test
+    public void testIntersection() {
+        test(
+                (a) -> assertCommandOutputContains(a, "<Z extends Runnable&CharSequence> Z get1() { return null; }", "get1()"),
+                (a) -> assertCommandOutputContains(a, "var g1 = get1()", "g1"),
+                (a) -> assertCommand(a, "/vars g1", "|    CharSequence&Runnable g1 = null"),
+                (a) -> assertCommandOutputContains(a, "<Z extends Number&CharSequence> Z get2() { return null; }", "get2()"),
+                (a) -> assertCommandOutputContains(a, "var g2 = get2()", "g2"),
+                (a) -> assertCommand(a, "/vars g2", "|    Number&CharSequence g2 = null")
+        );
+    }
+
+    @Test
+    public void testAnonymous() {
+        test(
+                (a) -> assertCommandOutputContains(a, "var r1 = new Object() {}", "r1"),
+                (a) -> assertCommandOutputContains(a, "/vars r1", "|    <anonymous class extending Object> r1 = "),
+                (a) -> assertCommandOutputContains(a, "var r2 = new Runnable() { public void run() { } }", "r2"),
+                (a) -> assertCommandOutputContains(a, "/vars r2", "|    <anonymous class implementing Runnable> r2 = ")
+        );
+    }
 }
--- a/test/langtools/jdk/jshell/VariablesTest.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/test/langtools/jdk/jshell/VariablesTest.java	Tue Sep 26 12:52:53 2017 +0100
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8144903
+ * @bug 8144903 8177466
  * @summary Tests for EvaluationState.variables
  * @build KullaTesting TestingInputStream ExpectedDiagnostic
  * @run testng VariablesTest
@@ -337,4 +337,30 @@
         assertEquals(unr.get(0), "class undefined");
         assertVariables(variable("undefined", "d"));
     }
+
+    public void lvti() {
+        assertEval("var d = 234;", "234");
+        assertEval("class Test<T> { T[][] get() { return null; } }", added(VALID));
+        assertEval("Test<? extends String> test() { return new Test<>(); }", added(VALID));
+        assertEval("var t = test().get();", added(VALID));
+        assertEval("<Z extends Runnable & CharSequence> Z get1() { return null; }", added(VALID));
+        assertEval("var i1 = get1();", added(VALID));
+        assertEval("void t1() { i1.run(); i1.length(); }", added(VALID));
+        assertEval("i1 = 1;", DiagCheck.DIAG_ERROR, DiagCheck.DIAG_OK, ste(MAIN_SNIPPET, NONEXISTENT, REJECTED, false, null));
+        assertEval("<Z extends Number & CharSequence> Z get2() { return null; }", added(VALID));
+        assertEval("var i2 = get2();", added(VALID));
+        assertEval("void t2() { i2.length(); }", added(VALID));
+        assertEval("var r1 = new Runnable() { public void run() { } public String get() { return \"good\"; } };", added(VALID));
+        assertEval("Runnable r2 = r1;");
+        assertEval("r1.get()", "\"good\"");
+        assertEval("var v = r1.get();", "\"good\"");
+        assertEval("var r3 = new java.util.ArrayList<String>(42) { public String get() { return \"good\"; } };", added(VALID));
+        assertEval("r3.get()", "\"good\"");
+        assertEval("class O { public class Inner { public String test() { return \"good\"; } } }");
+        assertEval("var r4 = new O().new Inner() { public String get() { return \"good\"; } };");
+        assertEval("r4.get()", "\"good\"");
+        assertEval("class O2 { public class Inner { public Inner(int i) { } public String test() { return \"good\"; } } }");
+        assertEval("var r5 = new O2().new Inner(1) { public String get() { return \"good\"; } };");
+        assertEval("r5.get()", "\"good\"");
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/IllegalRefToVarType.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+// key: compiler.err.illegal.ref.to.var.type
+
+import java.util.List;
+
+class IllegalRefToVarType {
+    var<String> list() { return null; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/LocalArrayMissingTarget.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+// key: compiler.err.cant.infer.local.var.type
+// key: compiler.misc.local.array.missing.target
+
+class LocalArrayMissingTarget {
+    void test() {
+        var x = { 1, 2, 3 };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/LocalCantInferNull.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+// key: compiler.err.cant.infer.local.var.type
+// key: compiler.misc.local.cant.infer.null
+
+class LocalCantInferNull {
+    void test() {
+        var s = null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/LocalLambdaMissingTarget.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+// key: compiler.err.cant.infer.local.var.type
+// key: compiler.misc.local.lambda.missing.target
+
+class LocalLambdaMissingTarget {
+    void test() {
+        var x = () -> { };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/LocalMissingInit.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+// key: compiler.err.cant.infer.local.var.type
+// key: compiler.misc.local.missing.init
+
+class LocalMissingInit {
+    void test() {
+        var s;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/LocalMrefMissingTarget.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+// key: compiler.err.cant.infer.local.var.type
+// key: compiler.misc.local.mref.missing.target
+
+class LocalMrefMissingTarget {
+    void test() {
+        var x = this::test;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/LocalRedundantType.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+// options: -XDfind=local
+// key: compiler.warn.local.redundant.type
+
+class LocalRedundantType {
+    void test() {
+        String s = "";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/LocalSelfRef.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+// key: compiler.err.cant.infer.local.var.type
+// key: compiler.misc.local.self.ref
+
+class LocalSelfRef {
+    void test() {
+        var x = m(x);
+    }
+
+    String m(String s) { return s; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/VarNotAllowed.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+// key: compiler.err.var.not.allowed
+
+class var { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/VarNotAllowedArray.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+// key: compiler.err.var.not.allowed.array
+
+class VarNotAllowedArray {
+    void test(String[] s) {
+        var[] x = s;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/VarNotAllowedCompound.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+
+// key: compiler.err.var.not.allowed.compound
+
+class VarNotAllowedCompound {
+    void test() {
+        var x = 1, y = 2;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/VarNotAllowedHere.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+// key: compiler.err.var.not.allowed.here
+
+class VarNotAllowedField {
+    var s = "";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/BadLocalVarInferenceTest.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,33 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8177466
+ * @summary Add compiler support for local variable type-inference
+ * @compile/fail/ref=BadLocalVarInferenceTest.out -XDrawDiagnostics BadLocalVarInferenceTest.java
+ */
+
+class BadLocalVarInferenceTest {
+
+    interface Foo<X> {
+        void m(X x);
+    }
+
+    interface Supplier<X> {
+        void m(X x);
+    }
+
+    void test() {
+        var x;
+        var f = () -> { };
+        var m = this::l;
+        var g = null;
+        var d = d = 1;
+        var k = { 1 , 2 };
+        var l = new Foo<>() { //LHS was Foo<String>
+            @Override
+            void m(String s) { }
+        };
+        var s = f(x -> { x.charAt(0); }); //LHS was String
+    }
+
+    <Z> Z f(Supplier<Z> sz) { return null; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/BadLocalVarInferenceTest.out	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,10 @@
+BadLocalVarInferenceTest.java:19:13: compiler.err.cant.infer.local.var.type: x, (compiler.misc.local.missing.init)
+BadLocalVarInferenceTest.java:20:13: compiler.err.cant.infer.local.var.type: f, (compiler.misc.local.lambda.missing.target)
+BadLocalVarInferenceTest.java:21:13: compiler.err.cant.infer.local.var.type: m, (compiler.misc.local.mref.missing.target)
+BadLocalVarInferenceTest.java:22:13: compiler.err.cant.infer.local.var.type: g, (compiler.misc.local.cant.infer.null)
+BadLocalVarInferenceTest.java:23:13: compiler.err.cant.infer.local.var.type: d, (compiler.misc.local.self.ref)
+BadLocalVarInferenceTest.java:24:13: compiler.err.cant.infer.local.var.type: k, (compiler.misc.local.array.missing.target)
+BadLocalVarInferenceTest.java:25:29: compiler.err.does.not.override.abstract: compiler.misc.anonymous.class: BadLocalVarInferenceTest$1, m(java.lang.Object), BadLocalVarInferenceTest.Foo
+BadLocalVarInferenceTest.java:26:13: compiler.err.method.does.not.override.superclass
+BadLocalVarInferenceTest.java:29:27: compiler.err.cant.resolve.location.args: kindname.method, charAt, , int, (compiler.misc.location.1: kindname.variable, x, java.lang.Object)
+9 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/FoldingTest.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,47 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8177466
+ * @summary Add compiler support for local variable type-inference
+ * @compile/fail/ref=FoldingTest.out -XDrawDiagnostics FoldingTest.java
+ */
+class FoldingTest {
+
+        void testReachability() {
+        for(var i = 0; i < 3; i++) {
+              // ok
+        }
+            System.out.println("foo");   //this should be reachable
+        }
+
+    void testCase(String s) {
+        var c = "";
+        final String c2 = "" + c;
+        switch (s) {
+            case c: break; //error!
+            case c2: break; //error!
+        }
+    }
+
+    void testAnno() {
+        @Anno1(s1) //error
+        var s1 = "";
+        @Anno2(s2) //error
+        var s2 = "";
+        @Anno3(s3) //error
+        var s3 = "";
+    }
+
+    @interface Anno1 {
+        String value();
+    }
+    @interface Anno2 {
+        Class<?> value();
+    }
+    @interface Anno3 {
+        Foo value();
+    }
+
+    enum Foo {
+        A, B;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/FoldingTest.out	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,6 @@
+FoldingTest.java:20:18: compiler.err.string.const.req
+FoldingTest.java:21:18: compiler.err.string.const.req
+FoldingTest.java:26:16: compiler.err.attribute.value.must.be.constant
+FoldingTest.java:28:16: compiler.err.annotation.value.must.be.class.literal
+FoldingTest.java:30:16: compiler.err.enum.annotation.must.be.enum.constant
+5 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/ParserTest.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,71 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8177466
+ * @summary Add compiler support for local variable type-inference
+ * @compile -source 9 ParserTest.java
+ * @compile/fail/ref=ParserTest.out -XDrawDiagnostics ParserTest.java
+ */
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+import java.util.function.Function;
+import java.util.List;
+
+class ParserTest<var> {
+    static class TestClass {
+        static class var { } //illegal
+    }
+
+    static class TestInterface {
+        interface var { } //illegal
+    }
+
+    static class TestEnum {
+        enum var { } //illegal
+    }
+
+    static class TestAnno {
+        @interface var { } //illegal
+    }
+
+    @Target(ElementType.TYPE_USE)
+    @interface TA { }
+
+    @interface DA { }
+
+    static class var extends RuntimeException { } //illegal
+
+    var x = null; //illegal
+
+    void test() {
+        var[] x1 = null; //illegal
+        var x2[] = null; //illegal
+        var[][] x3 = null; //illegal
+        var x4[][] = null; //illegal
+        var[] x5 = null; //illegal
+        var x6[] = null; //illegal
+        var@TA[]@TA[] x7 = null; //illegal
+        var x8@TA[]@TA[] = null; //illegal
+        var x9 = null, y = null; //illegal
+        final @DA var x10 = m(); //ok
+        @DA final var x11 = m(); //ok
+    }
+
+    var m() { //illegal
+        return null;
+    }
+
+    void test2(var x) { //error
+        List<var> l1; //error
+        List<? extends var> l2; //error
+        List<? super var> l3; //error
+        try {
+            Function<var, String> f = (var x2) -> ""; //error
+        } catch (var ex) { } //error
+    }
+
+    void test3(Object o) {
+        boolean b1 = o instanceof var; //error
+        Object o2 = (var)o; //error
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/ParserTest.out	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,25 @@
+ParserTest.java:14:18: compiler.err.var.not.allowed: var
+ParserTest.java:16:22: compiler.err.var.not.allowed: var
+ParserTest.java:20:19: compiler.err.var.not.allowed: var
+ParserTest.java:24:14: compiler.err.var.not.allowed: var
+ParserTest.java:28:20: compiler.err.var.not.allowed: var
+ParserTest.java:36:18: compiler.err.var.not.allowed: var
+ParserTest.java:38:5: compiler.err.var.not.allowed.here
+ParserTest.java:41:15: compiler.err.var.not.allowed.array
+ParserTest.java:42:13: compiler.err.var.not.allowed.array
+ParserTest.java:43:17: compiler.err.var.not.allowed.array
+ParserTest.java:44:13: compiler.err.var.not.allowed.array
+ParserTest.java:45:15: compiler.err.var.not.allowed.array
+ParserTest.java:46:13: compiler.err.var.not.allowed.array
+ParserTest.java:49:13: compiler.err.var.not.allowed.compound
+ParserTest.java:54:5: compiler.err.var.not.allowed.here
+ParserTest.java:58:16: compiler.err.var.not.allowed.here
+ParserTest.java:59:14: compiler.err.var.not.allowed.here
+ParserTest.java:60:24: compiler.err.var.not.allowed.here
+ParserTest.java:61:22: compiler.err.var.not.allowed.here
+ParserTest.java:63:22: compiler.err.var.not.allowed.here
+ParserTest.java:63:40: compiler.err.var.not.allowed.here
+ParserTest.java:64:18: compiler.err.var.not.allowed.here
+ParserTest.java:68:35: compiler.err.var.not.allowed.here
+ParserTest.java:69:22: compiler.err.var.not.allowed.here
+24 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/SelfRefTest.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,23 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8177466
+ * @summary Add compiler support for local variable type-inference
+ * @compile/fail/ref=SelfRefTest.out -XDrawDiagnostics SelfRefTest.java
+ */
+
+import java.util.function.Function;
+
+class SelfRefTest {
+
+        int q() { return 42; }
+    int m(int t) { return t; }
+
+    void test(boolean cond) {
+       var x = cond ? x : x; //error - self reference
+       var y = (Function<Integer, Integer>)(Integer y) -> y; //error - bad shadowing
+       var z = (Runnable)() -> { int z2 = m(z); }; //error - self reference
+       var w = new Object() { int w = 42; void test() { int w2 = w; } }; //ok
+       int u = u; //ok
+       int q = q(); //ok
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/SelfRefTest.out	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,4 @@
+SelfRefTest.java:16:12: compiler.err.cant.infer.local.var.type: x, (compiler.misc.local.self.ref)
+SelfRefTest.java:17:53: compiler.err.already.defined: kindname.variable, y, kindname.method, test(boolean)
+SelfRefTest.java:18:12: compiler.err.cant.infer.local.var.type: z, (compiler.misc.local.self.ref)
+3 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/badTypeReference/BadTypeReference.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+
+/*
+ * @test /nodynamioccopyright/
+ * @bug 8177466
+ * @summary Add compiler support for local variable type-inference
+ * @compile -source 8 pkg/var.java
+ * @compile pkg/nested/var/A.java
+ * @compile/fail/ref=BadTypeReference.out -XDrawDiagnostics BadTypeReference.java
+ */
+
+import pkg.*;
+
+public class BadTypeReference {
+    void test(Object o) {
+        var<String> vs = null; //error
+        Object o2 = var.x; //error
+        pkg.nested.var.A a = new pkg.nested.var.A(); //ok
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/badTypeReference/BadTypeReference.out	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,3 @@
+BadTypeReference.java:39:9: compiler.err.illegal.ref.to.var.type: var
+BadTypeReference.java:40:21: compiler.err.illegal.ref.to.var.type: var
+2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/badTypeReference/pkg/nested/var/A.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017, 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 pkg.nested.var;
+
+public class A {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/badTypeReference/pkg/var.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017, 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 pkg;
+
+public class var {
+    public static Object x = "";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/harness/InferredType.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+public @interface InferredType {
+    String value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/harness/LocalVariableInferenceTester.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2016, 2017 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.VariableTree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.TreePathScanner;
+import com.sun.tools.javac.api.JavacTaskImpl;
+import com.sun.tools.javac.api.JavacTrees;
+import com.sun.tools.javac.code.Printer;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Type.CapturedType;
+import com.sun.tools.javac.code.Type.ClassType;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.util.Log;
+
+import static javax.tools.StandardLocation.SOURCE_PATH;
+
+public class LocalVariableInferenceTester {
+
+    static final JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+    static final StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
+
+    public static void main(String[] args) throws IOException {
+        try {
+            if (args.length != 1) {
+                System.err.println("Usage: LocalVariableInferenceTester <sourcefile>");
+                System.exit(1);
+            }
+            File path = new File(System.getProperty("test.src"));
+            fm.setLocation(SOURCE_PATH, Arrays.asList(path));
+            File input = new File(path, args[0]);
+            JavaFileObject jfo = fm.getJavaFileObjects(input).iterator().next();
+            new LocalVariableInferenceTester().compileAndCheck(jfo);
+        } finally {
+            fm.close();
+        }
+    }
+
+    int errors = 0;
+    int checks = 0;
+
+    void compileAndCheck(JavaFileObject input) throws IOException {
+        JavaCompiler c = ToolProvider.getSystemJavaCompiler();
+        JavacTask task = (JavacTask) c.getTask(null, fm, null, null, null, Arrays.asList(input));
+        JavacTrees trees = JavacTrees.instance(task);
+        Types types = Types.instance(((JavacTaskImpl)task).getContext());
+        Iterable<? extends CompilationUnitTree> roots = task.parse();
+        task.analyze(); //force attribution
+        Log log = Log.instance(((JavacTaskImpl)task).getContext());
+        errors += log.nerrors;
+        new LocalVarTypeChecker(trees, types).scan(roots, null);
+        System.err.println("Checks executed: " + checks);
+        if (errors != 0) {
+            throw new AssertionError("Errors were found");
+        }
+    }
+
+    void error(Tree node, String msg) {
+        System.err.println(node);
+        System.err.println("ERROR: " + msg);
+        errors++;
+    }
+
+    class LocalVarTypeChecker extends TreePathScanner<Void, Void> {
+
+        JavacTrees trees;
+        Types types;
+
+        LocalVarTypeChecker(JavacTrees trees, Types types) {
+            this.trees = trees;
+            this.types = types;
+        }
+
+        @Override
+        public Void visitVariable(VariableTree node, Void aVoid) {
+            Element e = trees.getElement(getCurrentPath());
+            if (e.getKind() == ElementKind.LOCAL_VARIABLE) {
+                TypeMirror type = e.asType();
+                InferredType inferredAnno = e.getAnnotation(InferredType.class);
+                if (inferredAnno != null) {
+                    checks++;
+                    String req = inferredAnno.value();
+                    String found = new TypePrinter().visit((Type)type, null);
+                    if (!req.equals(found)) {
+                        error(node, "Inferred type mismatch; expected: " + req + " - found: " + found);
+                    }
+                }
+            }
+            return super.visitVariable(node, null);
+        }
+
+        class TypePrinter extends Printer {
+
+            Map<Type, Integer> capturedIdMap = new HashMap<>();
+
+            @Override
+            protected String localize(Locale locale, String key, Object... args) {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public String visitCapturedType(CapturedType t, Locale locale) {
+                return "CAP#" + capturedVarId(t, locale);
+            }
+
+            @Override
+            protected String capturedVarId(CapturedType t, Locale locale) {
+                return String.valueOf(capturedIdMap.getOrDefault(t, capturedIdMap.size()));
+            }
+
+            @Override
+            public String visitClassType(ClassType t, Locale locale) {
+                if (!t.isCompound() && t.tsym.name.isEmpty()) {
+                    return "#ANON(" + types.directSupertypes(t) + ")";
+                } else if (t.isCompound()) {
+                    return "#INT(" + types.directSupertypes(t) + ")";
+                } else {
+                    return super.visitClassType(t, locale);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/harness/NonDenotableTest.java	Tue Sep 26 12:52:53 2017 +0100
@@ -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.
+ */
+
+/*
+ * @test
+ * @bug 8177466
+ * @summary Add compiler support for local variable type-inference
+ * @modules jdk.compiler/com.sun.source.tree
+ *          jdk.compiler/com.sun.source.util
+ *          jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @build LocalVariableInferenceTester
+ * @run main LocalVariableInferenceTester NonDenotableTest.java
+ */
+import java.util.List;
+
+class NonDenotableTest {
+
+    static final String OBJECT = "java.lang.Object";
+    static final String STRING = "java.lang.String";
+    static final String ANON_OBJECT = "#ANON(java.lang.Object)";
+    static final String ANON_RUNNABLE = "#ANON(java.lang.Object,java.lang.Runnable)";
+    static final String LIST_EXT = "java.util.List<? extends java.lang.String>";
+    static final String LIST_SUP = "java.util.List<? super java.lang.String>";
+    static final String LIST_UNB = "java.util.List<?>";
+    static final String COMP_UNB = "java.lang.Comparable<?>";
+    static final String LIST_EXT_COMP_UNB = "java.util.List<? extends java.lang.Comparable<?>>";
+    static final String LIST_SUP_COMP_UNB = "java.util.List<? super java.lang.Comparable<?>>";
+    static final String INT_INTEGER_DOUBLE = "#INT(java.lang.Number,java.lang.Comparable<? extends java.lang.Number&java.lang.Comparable<?>>)";
+
+    void testExtends() {
+        @InferredType(LIST_EXT)
+        var s = extString();
+        for (@InferredType(LIST_EXT) var s2 = extString() ; ; ) { break; }
+        for (@InferredType(LIST_EXT) var s2 : extStringArr()) { break; }
+        for (@InferredType(LIST_EXT) var s2 : extStringIter()) { break; }
+        for (@InferredType(STRING) var s2 : extString()) { break; }
+    }
+
+    void testExtendsFbound() {
+        @InferredType(LIST_EXT_COMP_UNB)
+        var s = extFbound();
+        for (@InferredType(LIST_EXT_COMP_UNB) var s2 = extFbound() ; ; ) { break; }
+        for (@InferredType(LIST_EXT_COMP_UNB) var s2 : extFboundArr()) { break; }
+        for (@InferredType(LIST_EXT_COMP_UNB) var s2 : extFboundIter()) { break; }
+        for (@InferredType(COMP_UNB) var s2 : extFbound()) { break; }
+    }
+
+    void testSuperFbound() {
+        @InferredType(LIST_UNB)
+        var s = supFbound();
+        for (@InferredType(LIST_UNB) var s2 = supFbound() ; ; ) { break; }
+        for (@InferredType(LIST_UNB) var s2 : supFboundArr()) { break; }
+        for (@InferredType(LIST_UNB) var s2 : supFboundIter()) { break; }
+        for (@InferredType(OBJECT) var s2 : supFbound()) { break; }
+    }
+
+    void testSuper() {
+        @InferredType(LIST_SUP)
+        var s = supString();
+        for (@InferredType(LIST_SUP) var s2 = supString() ; ; ) { break; }
+        for (@InferredType(LIST_SUP) var s2 : supStringArr()) { break; }
+        for (@InferredType(LIST_SUP) var s2 : supStringIter()) { break; }
+        for (@InferredType(OBJECT) var s2 : supString()) { break; }
+    }
+
+    void testUnbound() {
+        @InferredType(LIST_UNB)
+        var s = unbString();
+        for (@InferredType(LIST_UNB) var s2 = unbString() ; ; ) { break; }
+        for (@InferredType(LIST_UNB) var s2 : unbStringArr()) { break; }
+        for (@InferredType(LIST_UNB) var s2 : unbStringIter()) { break; }
+        for (@InferredType(OBJECT) var s2 : unbString()) { break; }
+    }
+
+    void testAnonymousClass() {
+        @InferredType(ANON_OBJECT)
+        var o = new Object() { };
+        for (@InferredType(ANON_OBJECT) var s2 = new Object() { } ; ; ) { break; }
+        for (@InferredType(ANON_OBJECT) var s2 : arrayOf(new Object() { })) { break; }
+        for (@InferredType(ANON_OBJECT) var s2 : listOf(new Object() { })) { break; }
+    }
+
+    void testAnonymousInterface() {
+        @InferredType(ANON_RUNNABLE)
+        var r = new Runnable() { public void run() { } };
+        for (@InferredType(ANON_RUNNABLE) var s2 = new Runnable() { public void run() { } } ; ; ) { break; }
+        for (@InferredType(ANON_RUNNABLE) var s2 : arrayOf(new Runnable() { public void run() { } })) { break; }
+        for (@InferredType(ANON_RUNNABLE) var s2 : listOf(new Runnable() { public void run() { } })) { break; }
+    }
+
+    void testIntersection() {
+        @InferredType(INT_INTEGER_DOUBLE)
+        var c = choose(1, 1L);
+        for (@InferredType(INT_INTEGER_DOUBLE) var s2 = choose(1, 1L) ; ;) { break; }
+        for (@InferredType(INT_INTEGER_DOUBLE) var s2 : arrayOf(choose(1, 1L))) { break; }
+        for (@InferredType(INT_INTEGER_DOUBLE) var s2 : listOf(choose(1, 1L))) { break; }
+    }
+
+    List<? extends String> extString() { return null; }
+    List<? super String> supString() { return null; }
+    List<?> unbString() { return null; }
+
+    List<? extends String>[] extStringArr() { return null; }
+    List<? super String>[] supStringArr() { return null; }
+    List<?>[] unbStringArr() { return null; }
+
+    Iterable<? extends List<? extends String>> extStringIter() { return null; }
+    Iterable<? extends List<? super String>> supStringIter() { return null; }
+    Iterable<? extends List<?>> unbStringIter() { return null; }
+
+    <Z extends Comparable<Z>> List<? extends Z> extFbound() { return null; }
+    <Z extends Comparable<Z>> List<? super Z> supFbound() { return null; }
+
+    <Z extends Comparable<Z>> List<? extends Z>[] extFboundArr() { return null; }
+    <Z extends Comparable<Z>> List<? super Z>[] supFboundArr() { return null; }
+
+    <Z extends Comparable<Z>> Iterable<? extends List<? extends Z>> extFboundIter() { return null; }
+    <Z extends Comparable<Z>> Iterable<? extends List<? super Z>> supFboundIter() { return null; }
+
+    <Z> List<Z> listOf(Z z) { return null; }
+    <Z> Z[] arrayOf(Z z) { return null; }
+
+    <Z> Z choose(Z z1, Z z2) { return z1; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/harness/PrimitiveTypeTest.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8177466
+ * @summary Add compiler support for local variable type-inference
+ * @modules jdk.compiler/com.sun.source.tree
+ *          jdk.compiler/com.sun.source.util
+ *          jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @build LocalVariableInferenceTester
+ * @run main LocalVariableInferenceTester PrimitiveTypeTest.java
+ */
+class PrimitiveTypeTest {
+
+    byte[] b_arr = { 0 };
+    short[] s_arr = { 0 };
+    int[] i_arr = { 0 };
+    long[] l_arr = { 0 };
+    float[] f_arr = { 0 };
+    double[] d_arr = { 0 };
+    char[] c_arr = { 0 };
+    boolean[] z_arr = { false };
+
+    void testPrimitive() {
+        @InferredType("byte")
+        var b = (byte)0;
+        @InferredType("short")
+        var s = (short)0;
+        @InferredType("int")
+        var i = 0;
+        @InferredType("long")
+        var l = 0L;
+        @InferredType("float")
+        var f = 0f;
+        @InferredType("double")
+        var d = 0d;
+        @InferredType("char")
+        var c = 'c';
+        @InferredType("boolean")
+        var z = false;
+    }
+
+    void testPrimitiveArray() {
+        @InferredType("byte[]")
+        var b = b_arr;
+        @InferredType("short[]")
+        var s = s_arr;
+        @InferredType("int[]")
+        var i = i_arr;
+        @InferredType("long[]")
+        var l = l_arr;
+        @InferredType("float[]")
+        var f = f_arr;
+        @InferredType("double[]")
+        var d = d_arr;
+        @InferredType("char[]")
+        var c = c_arr;
+        @InferredType("boolean[]")
+        var z = z_arr;
+    }
+
+    void testForEachPrimitive() {
+        for (@InferredType("byte") var b : b_arr) { break; }
+        for (@InferredType("short") var s : s_arr) { break;  }
+        for (@InferredType("int") var i : i_arr) { break; }
+        for (@InferredType("long") var l : l_arr) { break; }
+        for (@InferredType("float") var f : f_arr) { break; }
+        for (@InferredType("double") var d : d_arr) { break; }
+        for (@InferredType("char") var c : c_arr) { break; }
+        for (@InferredType("boolean") var z : z_arr) { break; }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/harness/ReferenceTypeTest.java	Tue Sep 26 12:52:53 2017 +0100
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8177466
+ * @summary Add compiler support for local variable type-inference
+ * @modules jdk.compiler/com.sun.source.tree
+ *          jdk.compiler/com.sun.source.util
+ *          jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @build LocalVariableInferenceTester
+ * @run main LocalVariableInferenceTester ReferenceTypeTest.java
+ */
+class ReferenceTypeTest {
+
+    static final String STRING = "java.lang.String";
+    static final String FOO = "ReferenceTypeTest.Foo";
+
+    void test() {
+        @InferredType(STRING)
+        var s = "";
+        for (@InferredType(STRING) var s2 = "" ; ; ) { break; }
+        for (@InferredType(STRING) var s2 : stringArray()) { break; }
+        for (@InferredType(STRING) var s2 : stringIterable()) { break; }
+        try (@InferredType(FOO) var s2 = new Foo()) { } finally { }
+        try (@InferredType(FOO) var s2 = new Foo(); @InferredType(FOO) var s3 = new Foo()) { } finally { }
+    }
+
+    String[] stringArray() { return null; }
+    Iterable<String> stringIterable() { return null; }
+
+    static class Foo implements AutoCloseable {
+        @Override
+        public void close() { }
+    }
+}
--- a/test/langtools/tools/javac/parser/extend/TrialParser.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/test/langtools/tools/javac/parser/extend/TrialParser.java	Tue Sep 26 12:52:53 2017 +0100
@@ -224,7 +224,7 @@
                             //mods.flags |= Flags.STATIC;
                             List<JCTree> defs
                                     = variableDeclaratorsRest(pos, mods, t, name, false, dc,
-                                            new ListBuffer<JCTree>()).toList();
+                                            new ListBuffer<JCTree>(), true).toList();
                             accept(SEMI);
                             storeEnd(defs.last(), S.prevToken().endPos);
                             return defs;
--- a/test/langtools/tools/lib/types/TypeHarness.java	Tue Sep 26 15:08:56 2017 +0530
+++ b/test/langtools/tools/lib/types/TypeHarness.java	Tue Sep 26 12:52:53 2017 +0100
@@ -354,7 +354,7 @@
 
         public TypeVar TypeVariable(Type bound) {
             TypeSymbol tvsym = new TypeVariableSymbol(0, syntheticName(), null, predef.noSymbol);
-            tvsym.type = new TypeVar(tvsym, bound, null);
+            tvsym.type = new TypeVar(tvsym, bound, Type.noType);
             return (TypeVar)tvsym.type;
         }