Merge
authorlana
Tue, 23 Dec 2014 13:58:01 -0800
changeset 28149 518c958a4dfa
parent 28139 4459e5bddd9c (current diff)
parent 28148 6415a95b07fd (diff)
child 28150 afbb8a4d3d58
Merge
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java	Tue Dec 23 13:58:01 2014 -0800
@@ -0,0 +1,509 @@
+/*
+ * Copyright (c) 2014, 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 com.sun.tools.javac.comp;
+
+import com.sun.source.tree.LambdaExpressionTree;
+import com.sun.tools.javac.code.Source;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCBlock;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop;
+import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop;
+import com.sun.tools.javac.tree.JCTree.JCForLoop;
+import com.sun.tools.javac.tree.JCTree.JCIf;
+import com.sun.tools.javac.tree.JCTree.JCLambda;
+import com.sun.tools.javac.tree.JCTree.JCLambda.ParameterKind;
+import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
+import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
+import com.sun.tools.javac.tree.JCTree.JCNewClass;
+import com.sun.tools.javac.tree.JCTree.JCStatement;
+import com.sun.tools.javac.tree.JCTree.JCSwitch;
+import com.sun.tools.javac.tree.JCTree.JCTypeApply;
+import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
+import com.sun.tools.javac.tree.JCTree.JCWhileLoop;
+import com.sun.tools.javac.tree.JCTree.Tag;
+import com.sun.tools.javac.tree.TreeCopier;
+import com.sun.tools.javac.tree.TreeInfo;
+import com.sun.tools.javac.tree.TreeMaker;
+import com.sun.tools.javac.tree.TreeScanner;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.DefinedBy;
+import com.sun.tools.javac.util.DefinedBy.Api;
+import com.sun.tools.javac.util.Filter;
+import com.sun.tools.javac.util.JCDiagnostic;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.ListBuffer;
+import com.sun.tools.javac.util.Log;
+import com.sun.tools.javac.util.Names;
+import com.sun.tools.javac.util.Options;
+
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Predicate;
+
+import static com.sun.tools.javac.code.Flags.GENERATEDCONSTR;
+import static com.sun.tools.javac.code.Flags.SYNTHETIC;
+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.CLASSDEF;
+import static com.sun.tools.javac.tree.JCTree.Tag.METHODDEF;
+import static com.sun.tools.javac.tree.JCTree.Tag.NEWCLASS;
+import static com.sun.tools.javac.tree.JCTree.Tag.TYPEAPPLY;
+
+/**
+ * Helper class for defining custom code analysis, such as finding instance creation expression
+ * that can benefit from diamond syntax.
+ */
+public class Analyzer {
+    protected static final Context.Key<Analyzer> analyzerKey = new Context.Key<>();
+
+    final Types types;
+    final Log log;
+    final Attr attr;
+    final DeferredAttr deferredAttr;
+    final TreeMaker make;
+    final Names names;
+
+    final EnumSet<AnalyzerMode> analyzerModes;
+
+    public static Analyzer instance(Context context) {
+        Analyzer instance = context.get(analyzerKey);
+        if (instance == null)
+            instance = new Analyzer(context);
+        return instance;
+    }
+
+    protected Analyzer(Context context) {
+        context.put(analyzerKey, this);
+        types = Types.instance(context);
+        log = Log.instance(context);
+        attr = Attr.instance(context);
+        deferredAttr = DeferredAttr.instance(context);
+        make = TreeMaker.instance(context);
+        names = Names.instance(context);
+        Options options = Options.instance(context);
+        String findOpt = options.get("find");
+        //parse modes
+        Source source = Source.instance(context);
+        analyzerModes = AnalyzerMode.getAnalyzerModes(findOpt, source);
+    }
+
+    /**
+     * This enum defines supported analyzer modes, as well as defining the logic for decoding
+     * the {@code -XDfind} option.
+     */
+    enum AnalyzerMode {
+        DIAMOND("diamond", Source::allowDiamond),
+        LAMBDA("lambda", Source::allowLambda),
+        METHOD("method", Source::allowGraphInference);
+
+        final String opt;
+        final Predicate<Source> sourceFilter;
+
+        AnalyzerMode(String opt, Predicate<Source> sourceFilter) {
+            this.opt = opt;
+            this.sourceFilter = sourceFilter;
+        }
+
+        /**
+         * This method is used to parse the {@code find} option.
+         * Possible modes are separated by colon; a mode can be excluded by
+         * prepending '-' to its name. Finally, the special mode 'all' can be used to
+         * add all modes to the resulting enum.
+         */
+        static EnumSet<AnalyzerMode> getAnalyzerModes(String opt, Source source) {
+            if (opt == null) {
+                return EnumSet.noneOf(AnalyzerMode.class);
+            }
+            List<String> modes = List.from(opt.split(","));
+            EnumSet<AnalyzerMode> res = EnumSet.noneOf(AnalyzerMode.class);
+            if (modes.contains("all")) {
+                res = EnumSet.allOf(AnalyzerMode.class);
+            }
+            for (AnalyzerMode mode : values()) {
+                if (modes.contains(mode.opt)) {
+                    res.add(mode);
+                } else if (modes.contains("-" + mode.opt) || !mode.sourceFilter.test(source)) {
+                    res.remove(mode);
+                }
+            }
+            return res;
+        }
+    }
+
+    /**
+     * A statement analyzer is a work-unit that matches certain AST nodes (of given type {@code S}),
+     * rewrites them to different AST nodes (of type {@code T}) and then generates some meaningful
+     * messages in case the analysis has been successful.
+     */
+    abstract class StatementAnalyzer<S extends JCTree, T extends JCTree> {
+
+        AnalyzerMode mode;
+        JCTree.Tag tag;
+
+        StatementAnalyzer(AnalyzerMode mode, Tag tag) {
+            this.mode = mode;
+            this.tag = tag;
+        }
+
+        /**
+         * Is this analyzer allowed to run?
+         */
+        boolean isEnabled() {
+            return analyzerModes.contains(mode);
+        }
+
+        /**
+         * Should this analyzer be rewriting the given tree?
+         */
+        abstract boolean match(S tree);
+
+        /**
+         * Rewrite a given AST node into a new one
+         */
+        abstract T map(S oldTree, S newTree);
+
+        /**
+         * Entry-point for comparing results and generating diagnostics.
+         */
+        abstract void process(S oldTree, T newTree, boolean hasErrors);
+
+    }
+
+    /**
+     * This analyzer checks if generic instance creation expression can use diamond syntax.
+     */
+    class DiamondInitializer extends StatementAnalyzer<JCNewClass, JCNewClass> {
+
+        DiamondInitializer() {
+            super(AnalyzerMode.DIAMOND, NEWCLASS);
+        }
+
+        @Override
+        boolean match(JCNewClass tree) {
+            return tree.clazz.hasTag(TYPEAPPLY) &&
+                    !TreeInfo.isDiamond(tree) &&
+                    tree.def == null;
+        }
+
+        @Override
+        JCNewClass map(JCNewClass oldTree, JCNewClass newTree) {
+            if (newTree.clazz.hasTag(TYPEAPPLY)) {
+                ((JCTypeApply)newTree.clazz).arguments = List.nil();
+            }
+            return newTree;
+        }
+
+        @Override
+        void process(JCNewClass oldTree, JCNewClass newTree, boolean hasErrors) {
+            if (!hasErrors) {
+                List<Type> inferredArgs = newTree.type.getTypeArguments();
+                List<Type> explicitArgs = oldTree.type.getTypeArguments();
+                for (Type t : inferredArgs) {
+                    if (!types.isSameType(t, explicitArgs.head)) {
+                        log.warning(oldTree.clazz, "diamond.redundant.args.1",
+                                oldTree.clazz.type, newTree.clazz.type);
+                        return;
+                    }
+                    explicitArgs = explicitArgs.tail;
+                }
+                //exact match
+                log.warning(oldTree.clazz, "diamond.redundant.args");
+            }
+        }
+    }
+
+    /**
+     * This analyzer checks if anonymous instance creation expression can replaced by lambda.
+     */
+    class LambdaAnalyzer extends StatementAnalyzer<JCNewClass, JCLambda> {
+
+        LambdaAnalyzer() {
+            super(AnalyzerMode.LAMBDA, NEWCLASS);
+        }
+
+        @Override
+        boolean match (JCNewClass tree){
+            Type clazztype = tree.clazz.type;
+            return tree.def != null &&
+                    clazztype.hasTag(CLASS) &&
+                    types.isFunctionalInterface(clazztype.tsym) &&
+                    decls(tree.def).length() == 1;
+        }
+        //where
+            private List<JCTree> decls(JCClassDecl decl) {
+                ListBuffer<JCTree> decls = new ListBuffer<>();
+                for (JCTree t : decl.defs) {
+                    if (t.hasTag(METHODDEF)) {
+                        JCMethodDecl md = (JCMethodDecl)t;
+                        if ((md.getModifiers().flags & GENERATEDCONSTR) == 0) {
+                            decls.add(md);
+                        }
+                    } else {
+                        decls.add(t);
+                    }
+                }
+                return decls.toList();
+            }
+
+        @Override
+        JCLambda map (JCNewClass oldTree, JCNewClass newTree){
+            JCMethodDecl md = (JCMethodDecl)decls(newTree.def).head;
+            List<JCVariableDecl> params = md.params;
+            JCBlock body = md.body;
+            return make.Lambda(params, body);
+        }
+        @Override
+        void process (JCNewClass oldTree, JCLambda newTree, boolean hasErrors){
+            if (!hasErrors) {
+                log.warning(oldTree.def, "potential.lambda.found");
+            }
+        }
+    }
+
+    /**
+     * This analyzer checks if generic method call has redundant type arguments.
+     */
+    class RedundantTypeArgAnalyzer extends StatementAnalyzer<JCMethodInvocation, JCMethodInvocation> {
+
+        RedundantTypeArgAnalyzer() {
+            super(AnalyzerMode.METHOD, APPLY);
+        }
+
+        @Override
+        boolean match (JCMethodInvocation tree){
+            return tree.typeargs != null &&
+                    tree.typeargs.nonEmpty();
+        }
+        @Override
+        JCMethodInvocation map (JCMethodInvocation oldTree, JCMethodInvocation newTree){
+            newTree.typeargs = List.nil();
+            return newTree;
+        }
+        @Override
+        void process (JCMethodInvocation oldTree, JCMethodInvocation newTree, boolean hasErrors){
+            if (!hasErrors) {
+                //exact match
+                log.warning(oldTree, "method.redundant.typeargs");
+            }
+        }
+    }
+
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    StatementAnalyzer<JCTree, JCTree>[] analyzers = new StatementAnalyzer[] {
+            new DiamondInitializer(),
+            new LambdaAnalyzer(),
+            new RedundantTypeArgAnalyzer()
+    };
+
+    /**
+     * Analyze an AST node if needed.
+     */
+    void analyzeIfNeeded(JCTree tree, Env<AttrContext> env) {
+        if (!analyzerModes.isEmpty() &&
+                !env.info.isSpeculative &&
+                TreeInfo.isStatement(tree)) {
+            JCStatement stmt = (JCStatement)tree;
+            analyze(stmt, env);
+        }
+    }
+
+    /**
+     * Analyze an AST node; this involves collecting a list of all the nodes that needs rewriting,
+     * and speculatively type-check the rewritten code to compare results against previously attributed code.
+     */
+    void analyze(JCStatement statement, Env<AttrContext> env) {
+        AnalysisContext context = new AnalysisContext();
+        StatementScanner statementScanner = new StatementScanner(context);
+        statementScanner.scan(statement);
+
+        if (!context.treesToAnalyzer.isEmpty()) {
+
+            //add a block to hoist potential dangling variable declarations
+            JCBlock fakeBlock = make.Block(SYNTHETIC, List.of(statement));
+
+            TreeMapper treeMapper = new TreeMapper(context);
+            //TODO: to further refine the analysis, try all rewriting combinations
+            deferredAttr.attribSpeculative(fakeBlock, env, attr.statInfo, treeMapper,
+                    t -> new AnalyzeDeferredDiagHandler(context));
+
+            context.treeMap.entrySet().forEach(e -> {
+                context.treesToAnalyzer.get(e.getKey())
+                        .process(e.getKey(), e.getValue(), context.errors.nonEmpty());
+            });
+        }
+    }
+
+    /**
+     * Simple deferred diagnostic handler which filters out all messages and keep track of errors.
+     */
+    class AnalyzeDeferredDiagHandler extends Log.DeferredDiagnosticHandler {
+        AnalysisContext context;
+
+        public AnalyzeDeferredDiagHandler(AnalysisContext context) {
+            super(log, d -> {
+                if (d.getType() == DiagnosticType.ERROR) {
+                    context.errors.add(d);
+                }
+                return true;
+            });
+            this.context = context;
+        }
+    }
+
+    /**
+     * This class is used to pass around contextual information bewteen analyzer classes, such as
+     * trees to be rewritten, errors occurred during the speculative attribution step, etc.
+     */
+    class AnalysisContext {
+        /** Map from trees to analyzers. */
+        Map<JCTree, StatementAnalyzer<JCTree, JCTree>> treesToAnalyzer = new HashMap<>();
+
+        /** Map from original AST nodes to rewritten AST nodes */
+        Map<JCTree, JCTree> treeMap = new HashMap<>();
+
+        /** Errors in rewritten tree */
+        ListBuffer<JCDiagnostic> errors = new ListBuffer<>();
+    }
+
+    /**
+     * Subclass of {@link com.sun.tools.javac.tree.TreeScanner} which visit AST-nodes w/o crossing
+     * statement boundaries.
+     */
+    class StatementScanner extends TreeScanner {
+
+        /** context */
+        AnalysisContext context;
+
+        StatementScanner(AnalysisContext context) {
+            this.context = context;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public void scan(JCTree tree) {
+            if (tree != null) {
+                for (StatementAnalyzer<JCTree, JCTree> analyzer : analyzers) {
+                    if (analyzer.isEnabled() &&
+                            tree.hasTag(analyzer.tag) &&
+                            analyzer.match(tree)) {
+                        context.treesToAnalyzer.put(tree, analyzer);
+                        break; //TODO: cover cases where multiple matching analyzers are found
+                    }
+                }
+            }
+            super.scan(tree);
+        }
+
+        @Override
+        public void visitClassDef(JCClassDecl tree) {
+            //do nothing (prevents seeing same stuff twice
+        }
+
+        @Override
+        public void visitMethodDef(JCMethodDecl tree) {
+            //do nothing (prevents seeing same stuff twice
+        }
+
+        @Override
+        public void visitBlock(JCBlock tree) {
+            //do nothing (prevents seeing same stuff twice
+        }
+
+        @Override
+        public void visitSwitch(JCSwitch tree) {
+            scan(tree.getExpression());
+        }
+
+        @Override
+        public void visitForLoop(JCForLoop tree) {
+            scan(tree.getInitializer());
+            scan(tree.getCondition());
+            scan(tree.getUpdate());
+        }
+
+        @Override
+        public void visitForeachLoop(JCEnhancedForLoop tree) {
+            scan(tree.getExpression());
+        }
+
+        @Override
+        public void visitWhileLoop(JCWhileLoop tree) {
+            scan(tree.getCondition());
+        }
+
+        @Override
+        public void visitDoLoop(JCDoWhileLoop tree) {
+            scan(tree.getCondition());
+        }
+
+        @Override
+        public void visitIf(JCIf tree) {
+            scan(tree.getCondition());
+        }
+    }
+
+    /**
+     * Subclass of TreeCopier that maps nodes matched by analyzers onto new AST nodes.
+     */
+    class TreeMapper extends TreeCopier<Void> {
+
+        AnalysisContext context;
+
+        TreeMapper(AnalysisContext context) {
+            super(make);
+            this.context = context;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public <Z extends JCTree> Z copy(Z tree, Void _unused) {
+            Z newTree = super.copy(tree, _unused);
+            StatementAnalyzer<JCTree, JCTree> analyzer = context.treesToAnalyzer.get(tree);
+            if (analyzer != null) {
+                newTree = (Z)analyzer.map(tree, newTree);
+                context.treeMap.put(tree, newTree);
+            }
+            return newTree;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public JCTree visitLambdaExpression(LambdaExpressionTree node, Void _unused) {
+            JCLambda oldLambda = (JCLambda)node;
+            JCLambda newLambda = (JCLambda)super.visitLambdaExpression(node, _unused);
+            if (oldLambda.paramKind == ParameterKind.IMPLICIT) {
+                //reset implicit lambda parameters (whose type might have been set during attr)
+                newLambda.paramKind = ParameterKind.IMPLICIT;
+                newLambda.params.forEach(p -> p.vartype = null);
+            }
+            return newLambda;
+        }
+    }
+}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Dec 18 19:57:56 2014 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Dec 23 13:58:01 2014 -0800
@@ -83,6 +83,7 @@
     final Symtab syms;
     final Resolve rs;
     final Infer infer;
+    final Analyzer analyzer;
     final DeferredAttr deferredAttr;
     final Check chk;
     final Flow flow;
@@ -121,6 +122,7 @@
         make = TreeMaker.instance(context);
         enter = Enter.instance(context);
         infer = Infer.instance(context);
+        analyzer = Analyzer.instance(context);
         deferredAttr = DeferredAttr.instance(context);
         cfolder = ConstFold.instance(context);
         target = Target.instance(context);
@@ -143,11 +145,8 @@
         allowStaticInterfaceMethods = source.allowStaticInterfaceMethods();
         sourceName = source.name;
         relax = (options.isSet("-retrofit") ||
-                 options.isSet("-relax"));
-        findDiamonds = options.get("findDiamond") != null &&
-                 source.allowDiamond();
+                options.isSet("-relax"));
         useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
-        identifyLambdaCandidate = options.getBoolean("identifyLambdaCandidate", false);
 
         statInfo = new ResultInfo(KindSelector.NIL, Type.noType);
         varAssignmentInfo = new ResultInfo(KindSelector.ASG, Type.noType);
@@ -156,6 +155,8 @@
         unknownTypeInfo = new ResultInfo(KindSelector.TYP, Type.noType);
         unknownTypeExprInfo = new ResultInfo(KindSelector.VAL_TYP, Type.noType);
         recoveryInfo = new RecoveryInfo(deferredAttr.emptyDeferredAttrContext);
+
+        noCheckTree = make.at(-1).Skip();
     }
 
     /** Switch: relax some constraints for retrofit mode.
@@ -182,16 +183,6 @@
      */
     boolean allowStaticInterfaceMethods;
 
-    /** Switch: generates a warning if diamond can be safely applied
-     *  to a given new expression
-     */
-    boolean findDiamonds;
-
-    /**
-     * Internally enables/disables diamond finder feature
-     */
-    static final boolean allowDiamondFinder = true;
-
     /**
      * Switch: warn about use of variable before declaration?
      * RFE: 6425594
@@ -199,12 +190,6 @@
     boolean useBeforeDeclarationWarning;
 
     /**
-     * Switch: generate warnings whenever an anonymous inner class that is convertible
-     * to a lambda expression is found
-     */
-    boolean identifyLambdaCandidate;
-
-    /**
      * Switch: allow strings in switch?
      */
     boolean allowStringsInSwitch;
@@ -231,31 +216,32 @@
                final ResultInfo resultInfo) {
         InferenceContext inferenceContext = resultInfo.checkContext.inferenceContext();
         Type owntype;
-        if (!found.hasTag(ERROR) && !resultInfo.pt.hasTag(METHOD) && !resultInfo.pt.hasTag(FORALL)) {
-            if (!ownkind.subset(resultInfo.pkind)) {
-                log.error(tree.pos(), "unexpected.type",
-                        resultInfo.pkind.kindNames(),
-                        ownkind.kindNames());
-                owntype = types.createErrorType(found);
-            } else if (allowPoly && inferenceContext.free(found)) {
-                //delay the check if there are inference variables in the found type
-                //this means we are dealing with a partially inferred poly expression
-                owntype = resultInfo.pt;
-                inferenceContext.addFreeTypeListener(List.of(found, resultInfo.pt), new FreeTypeListener() {
-                    @Override
-                    public void typesInferred(InferenceContext inferenceContext) {
+        boolean shouldCheck = !found.hasTag(ERROR) &&
+                !resultInfo.pt.hasTag(METHOD) &&
+                !resultInfo.pt.hasTag(FORALL);
+        if (shouldCheck && !ownkind.subset(resultInfo.pkind)) {
+            log.error(tree.pos(), "unexpected.type",
+            resultInfo.pkind.kindNames(),
+            ownkind.kindNames());
+            owntype = types.createErrorType(found);
+        } else if (allowPoly && inferenceContext.free(found)) {
+            //delay the check if there are inference variables in the found type
+            //this means we are dealing with a partially inferred poly expression
+            owntype = shouldCheck ? resultInfo.pt : found;
+            inferenceContext.addFreeTypeListener(List.of(found, resultInfo.pt),
+                    instantiatedContext -> {
                         ResultInfo pendingResult =
                                 resultInfo.dup(inferenceContext.asInstType(resultInfo.pt));
                         check(tree, inferenceContext.asInstType(found), ownkind, pendingResult);
-                    }
-                });
-            } else {
-                owntype = resultInfo.check(tree, found);
-            }
+                    });
         } else {
-            owntype = found;
+            owntype = shouldCheck ?
+            resultInfo.check(tree, found) :
+            found;
         }
-        tree.type = owntype;
+        if (tree != noCheckTree) {
+            tree.type = owntype;
+        }
         return owntype;
     }
 
@@ -531,6 +517,10 @@
      */
     Type result;
 
+    /** Synthetic tree to be used during 'fake' checks.
+     */
+    JCTree noCheckTree;
+
     /** Visitor method: attribute a tree, catching any completion failure
      *  exceptions. Return the tree's type.
      *
@@ -610,7 +600,13 @@
     /** Derived visitor method: attribute a statement or definition tree.
      */
     public Type attribStat(JCTree tree, Env<AttrContext> env) {
-        return attribTree(tree, env, statInfo);
+        Env<AttrContext> analyzeEnv =
+                env.dup(tree, env.info.dup(env.info.scope.dupUnshared(env.info.scope.owner)));
+        try {
+            return attribTree(tree, env, statInfo);
+        } finally {
+            analyzer.analyzeIfNeeded(tree, analyzeEnv);
+        }
     }
 
     /** Attribute a list of expressions, returning a list of types.
@@ -792,8 +788,8 @@
 
     Type attribIdentAsEnumType(Env<AttrContext> env, JCIdent id) {
         Assert.check((env.enclClass.sym.flags() & ENUM) != 0);
-        id.type = env.info.scope.owner.type;
-        id.sym = env.info.scope.owner;
+        id.type = env.info.scope.owner.enclClass().type;
+        id.sym = env.info.scope.owner.enclClass();
         return id.type;
     }
 
@@ -2018,7 +2014,7 @@
                     }
                 });
                 Type constructorType = tree.constructorType = types.createErrorType(clazztype);
-                constructorType = checkId(tree, site,
+                constructorType = checkId(noCheckTree, site,
                         constructor,
                         diamondEnv,
                         diamondResult);
@@ -2044,7 +2040,7 @@
                 tree.constructor = rs.resolveConstructor(
                     tree.pos(), rsEnv, clazztype, argtypes, typeargtypes);
                 if (cdef == null) { //do not check twice!
-                    tree.constructorType = checkId(tree,
+                    tree.constructorType = checkId(noCheckTree,
                             clazztype,
                             tree.constructor,
                             rsEnv,
@@ -2052,12 +2048,6 @@
                     if (rsEnv.info.lastResolveVarargs())
                         Assert.check(tree.constructorType.isErroneous() || tree.varargsElement != null);
                 }
-                if (cdef == null &&
-                        !clazztype.isErroneous() &&
-                        clazztype.getTypeArguments().nonEmpty() &&
-                        findDiamonds) {
-                    findDiamond(localEnv, tree, clazztype);
-                }
             }
 
             if (cdef != null) {
@@ -2105,8 +2095,6 @@
 
                 attribStat(cdef, localEnv);
 
-                checkLambdaCandidate(tree, cdef.sym, clazztype);
-
                 // If an outer instance is given,
                 // prefix it to the constructor arguments
                 // and delete it from the new expression
@@ -2122,7 +2110,7 @@
                     tree.pos(), localEnv, clazztype, argtypes, typeargtypes);
                 Assert.check(!sym.kind.isOverloadError());
                 tree.constructor = sym;
-                tree.constructorType = checkId(tree,
+                tree.constructorType = checkId(noCheckTree,
                     clazztype,
                     tree.constructor,
                     localEnv,
@@ -2133,60 +2121,16 @@
                 owntype = clazztype;
         }
         result = check(tree, owntype, KindSelector.VAL, resultInfo);
+        InferenceContext inferenceContext = resultInfo.checkContext.inferenceContext();
+        if (tree.constructorType != null && inferenceContext.free(tree.constructorType)) {
+            //we need to wait for inference to finish and then replace inference vars in the constructor type
+            inferenceContext.addFreeTypeListener(List.of(tree.constructorType),
+                    instantiatedContext -> {
+                        tree.constructorType = instantiatedContext.asInstType(tree.constructorType);
+                    });
+        }
         chk.validate(tree.typeargs, localEnv);
     }
-    //where
-        void findDiamond(Env<AttrContext> env, JCNewClass tree, Type clazztype) {
-            JCTypeApply ta = (JCTypeApply)tree.clazz;
-            List<JCExpression> prevTypeargs = ta.arguments;
-            try {
-                //create a 'fake' diamond AST node by removing type-argument trees
-                ta.arguments = List.nil();
-                ResultInfo findDiamondResult = new ResultInfo(KindSelector.VAL,
-                        resultInfo.checkContext.inferenceContext().free(resultInfo.pt) ? Type.noType : pt());
-                Type inferred = deferredAttr.attribSpeculative(tree, env, findDiamondResult).type;
-                Type polyPt = allowPoly ?
-                        syms.objectType :
-                        clazztype;
-                if (!inferred.isErroneous() &&
-                    (allowPoly && pt() == Infer.anyPoly ?
-                        types.isSameType(inferred, clazztype) :
-                        types.isAssignable(inferred, pt().hasTag(NONE) ? polyPt : pt(), types.noWarnings))) {
-                    String key = types.isSameType(clazztype, inferred) ?
-                        "diamond.redundant.args" :
-                        "diamond.redundant.args.1";
-                    log.warning(tree.clazz.pos(), key, clazztype, inferred);
-                }
-            } finally {
-                ta.arguments = prevTypeargs;
-            }
-        }
-
-            private void checkLambdaCandidate(JCNewClass tree, ClassSymbol csym, Type clazztype) {
-                if (allowLambda &&
-                        identifyLambdaCandidate &&
-                        clazztype.hasTag(CLASS) &&
-                        !pt().hasTag(NONE) &&
-                        types.isFunctionalInterface(clazztype.tsym)) {
-                    Symbol descriptor = types.findDescriptorSymbol(clazztype.tsym);
-                    int count = 0;
-                    boolean found = false;
-                    for (Symbol sym : csym.members().getSymbols()) {
-                        if ((sym.flags() & SYNTHETIC) != 0 ||
-                                sym.isConstructor()) continue;
-                        count++;
-                        if (sym.kind != MTH ||
-                                !sym.name.equals(descriptor.name)) continue;
-                        Type mtype = types.memberType(clazztype, sym);
-                        if (types.overrideEquivalent(mtype, types.memberType(clazztype, descriptor))) {
-                            found = true;
-                        }
-                    }
-                    if (found && count == 1) {
-                        log.note(tree.def, "potential.lambda.found");
-                    }
-                }
-            }
 
     /** Make an attributed null check tree.
      */
@@ -2361,6 +2305,7 @@
             preFlow(that);
             flow.analyzeLambda(env, that, make, isSpeculativeRound);
 
+            that.type = currentTarget; //avoids recovery at this stage
             checkLambdaCompatible(that, lambdaType, resultInfo.checkContext);
 
             if (!isSpeculativeRound) {
@@ -2801,7 +2746,7 @@
                         that.kind.isUnbound() ? argtypes.tail : argtypes, typeargtypes),
                         new FunctionalReturnContext(resultInfo.checkContext));
 
-            Type refType = checkId(that, lookupHelper.site, refSym, localEnv, checkInfo);
+            Type refType = checkId(noCheckTree, lookupHelper.site, refSym, localEnv, checkInfo);
 
             if (that.kind.isUnbound() &&
                     resultInfo.checkContext.inferenceContext().free(argtypes.head)) {
@@ -2823,6 +2768,8 @@
             //is a no-op (as this has been taken care during method applicability)
             boolean isSpeculativeRound =
                     resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.SPECULATIVE;
+
+            that.type = currentTarget; //avoids recovery at this stage
             checkReferenceCompatible(that, desc, refType, resultInfo.checkContext, isSpeculativeRound);
             if (!isSpeculativeRound) {
                 checkAccessibleTypes(that, localEnv, resultInfo.checkContext.inferenceContext(), desc, currentTarget);
@@ -3953,7 +3900,7 @@
                 all_multicatchTypes.append(ctype);
             }
         }
-        Type t = check(tree, types.lub(multicatchTypes.toList()),
+        Type t = check(noCheckTree, types.lub(multicatchTypes.toList()),
                 KindSelector.TYP, resultInfo);
         if (t.hasTag(CLASS)) {
             List<Type> alternatives =
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java	Thu Dec 18 19:57:56 2014 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java	Tue Dec 23 13:58:01 2014 -0800
@@ -59,6 +59,10 @@
      */
     boolean isSerializable = false;
 
+    /** Is this a speculative attribution environment?
+     */
+    boolean isSpeculative = false;
+
     /** Are arguments to current function applications boxed into an array for varargs?
      */
     Resolve.MethodResolutionPhase pendingResolutionPhase = null;
@@ -95,6 +99,7 @@
         info.returnResult = returnResult;
         info.defaultSuperCallSite = defaultSuperCallSite;
         info.isSerializable = isSerializable;
+        info.isSpeculative = isSpeculative;
         return info;
     }
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Thu Dec 18 19:57:56 2014 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Tue Dec 23 13:58:01 2014 -0800
@@ -37,6 +37,7 @@
 import com.sun.tools.javac.comp.Infer.InferenceContext;
 import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
 import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.util.Log.DeferredDiagnosticHandler;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -46,6 +47,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.WeakHashMap;
+import java.util.function.Function;
 
 import static com.sun.tools.javac.code.TypeTag.*;
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
@@ -364,28 +366,16 @@
      * disabled during speculative type-checking.
      */
     JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
-        final JCTree newTree = new TreeCopier<>(make).copy(tree);
-        Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared(env.info.scope.owner)));
-        Log.DeferredDiagnosticHandler deferredDiagnosticHandler =
-                new Log.DeferredDiagnosticHandler(log, new Filter<JCDiagnostic>() {
-            public boolean accepts(final JCDiagnostic d) {
-                class PosScanner extends TreeScanner {
-                    boolean found = false;
+        return attribSpeculative(tree, env, resultInfo, new TreeCopier<>(make),
+                (newTree)->new DeferredAttrDiagHandler(log, newTree));
+    }
 
-                    @Override
-                    public void scan(JCTree tree) {
-                        if (tree != null &&
-                                tree.pos() == d.getDiagnosticPosition()) {
-                            found = true;
-                        }
-                        super.scan(tree);
-                    }
-                }
-                PosScanner posScanner = new PosScanner();
-                posScanner.scan(newTree);
-                return posScanner.found;
-            }
-        });
+    <Z> JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo, TreeCopier<Z> deferredCopier,
+                                 Function<JCTree, DeferredDiagnosticHandler> diagHandlerCreator) {
+        final JCTree newTree = deferredCopier.copy(tree);
+        Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared(env.info.scope.owner)));
+        speculativeEnv.info.isSpeculative = true;
+        Log.DeferredDiagnosticHandler deferredDiagnosticHandler = diagHandlerCreator.apply(newTree);
         try {
             attr.attribTree(newTree, speculativeEnv, resultInfo);
             unenterScanner.scan(newTree);
@@ -413,6 +403,37 @@
             }
         }
 
+        static class DeferredAttrDiagHandler extends Log.DeferredDiagnosticHandler {
+
+            static class PosScanner extends TreeScanner {
+                DiagnosticPosition pos;
+                boolean found = false;
+
+                PosScanner(DiagnosticPosition pos) {
+                    this.pos = pos;
+                }
+
+                @Override
+                public void scan(JCTree tree) {
+                    if (tree != null &&
+                            tree.pos() == pos) {
+                        found = true;
+                    }
+                    super.scan(tree);
+                }
+            }
+
+            DeferredAttrDiagHandler(Log log, JCTree newTree) {
+                super(log, new Filter<JCDiagnostic>() {
+                    public boolean accepts(JCDiagnostic d) {
+                        PosScanner posScanner = new PosScanner(d.getDiagnosticPosition());
+                        posScanner.scan(newTree);
+                        return posScanner.found;
+                    }
+                });
+            }
+        }
+
     /**
      * A deferred context is created on each method check. A deferred context is
      * used to keep track of information associated with the method check, such as
@@ -1221,7 +1242,7 @@
 
         @Override
         public void visitNewClass(JCNewClass tree) {
-            result = (TreeInfo.isDiamond(tree) || attr.findDiamonds) ?
+            result = TreeInfo.isDiamond(tree) ?
                     ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY;
         }
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Thu Dec 18 19:57:56 2014 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Tue Dec 23 13:58:01 2014 -0800
@@ -1176,12 +1176,14 @@
         @Override
         public void visitClassDef(JCClassDecl tree) {
             List<Frame> prevStack = frameStack;
+            int prevLambdaCount = lambdaCount;
             SyntheticMethodNameCounter prevSyntheticMethodNameCounts =
                     syntheticMethodNameCounts;
             Map<ClassSymbol, Symbol> prevClinits = clinits;
             DiagnosticSource prevSource = log.currentSource();
             try {
                 log.useSource(tree.sym.sourcefile);
+                lambdaCount = 0;
                 syntheticMethodNameCounts = new SyntheticMethodNameCounter();
                 prevClinits = new HashMap<>();
                 if (tree.sym.owner.kind == MTH) {
@@ -1208,6 +1210,7 @@
             finally {
                 log.useSource(prevSource.getFile());
                 frameStack = prevStack;
+                lambdaCount = prevLambdaCount;
                 syntheticMethodNameCounts = prevSyntheticMethodNameCounts;
                 clinits = prevClinits;
             }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Thu Dec 18 19:57:56 2014 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Tue Dec 23 13:58:01 2014 -0800
@@ -251,19 +251,19 @@
      *     mode = NOPARAMS    : no parameters allowed for type
      *     mode = TYPEARG     : type argument
      */
-    static final int EXPR = 0x1;
-    static final int TYPE = 0x2;
-    static final int NOPARAMS = 0x4;
-    static final int TYPEARG = 0x8;
-    static final int DIAMOND = 0x10;
+    protected static final int EXPR = 0x1;
+    protected static final int TYPE = 0x2;
+    protected static final int NOPARAMS = 0x4;
+    protected static final int TYPEARG = 0x8;
+    protected static final int DIAMOND = 0x10;
 
     /** The current mode.
      */
-    private int mode = 0;
+    protected int mode = 0;
 
     /** The mode of the term that was parsed last.
      */
-    private int lastmode = 0;
+    protected int lastmode = 0;
 
     /* ---------- token management -------------- */
 
@@ -326,7 +326,7 @@
 
     /** Skip forward until a suitable stop token is found.
      */
-    private void skip(boolean stopAtImport, boolean stopAtMemberDecl, boolean stopAtIdentifier, boolean stopAtStatement) {
+    protected void skip(boolean stopAtImport, boolean stopAtMemberDecl, boolean stopAtIdentifier, boolean stopAtStatement) {
          while (true) {
              switch (token.kind) {
                 case SEMI:
@@ -403,11 +403,11 @@
         }
     }
 
-    private JCErroneous syntaxError(int pos, String key, TokenKind... args) {
+    protected JCErroneous syntaxError(int pos, String key, TokenKind... args) {
         return syntaxError(pos, List.<JCTree>nil(), key, args);
     }
 
-    private JCErroneous syntaxError(int pos, List<JCTree> errs, String key, TokenKind... args) {
+    protected JCErroneous syntaxError(int pos, List<JCTree> errs, String key, TokenKind... args) {
         setErrorEndPos(pos);
         JCErroneous err = F.at(pos).Erroneous(errs);
         reportSyntaxError(err, key, (Object[])args);
@@ -427,7 +427,7 @@
      * Report a syntax using the given the position parameter and arguments,
      * unless one was already reported at the same position.
      */
-    private void reportSyntaxError(int pos, String key, Object... args) {
+    protected void reportSyntaxError(int pos, String key, Object... args) {
         JCDiagnostic.DiagnosticPosition diag = new JCDiagnostic.SimpleDiagnosticPosition(pos);
         reportSyntaxError(diag, key, args);
     }
@@ -436,7 +436,7 @@
      * Report a syntax error using the given DiagnosticPosition object and
      * arguments, unless one was already reported at the same position.
      */
-    private void reportSyntaxError(JCDiagnostic.DiagnosticPosition diagPos, String key, Object... args) {
+    protected void reportSyntaxError(JCDiagnostic.DiagnosticPosition diagPos, String key, Object... args) {
         int pos = diagPos.getPreferredPosition();
         if (pos > S.errPos() || pos == Position.NOPOS) {
             if (token.kind == EOF) {
@@ -459,14 +459,14 @@
     /** Generate a syntax error at current position unless one was already
      *  reported at the same position.
      */
-    private JCErroneous syntaxError(String key) {
+    protected JCErroneous syntaxError(String key) {
         return syntaxError(token.pos, key);
     }
 
     /** Generate a syntax error at current position unless one was
      *  already reported at the same position.
      */
-    private JCErroneous syntaxError(String key, TokenKind arg) {
+    protected JCErroneous syntaxError(String key, TokenKind arg) {
         return syntaxError(token.pos, key, arg);
     }
 
@@ -500,7 +500,7 @@
     }
 
     /** Diagnose a modifier flag from the set, if any. */
-    void checkNoMods(long mods) {
+    protected void checkNoMods(long mods) {
         if (mods != 0) {
             long lowestMod = mods & -mods;
             error(token.pos, "mod.not.allowed.here",
@@ -521,7 +521,7 @@
      *  @param tree   The tree to be used as index in the hashtable
      *  @param dc     The doc comment to associate with the tree, or null.
      */
-    void attach(JCTree tree, Comment dc) {
+    protected void attach(JCTree tree, Comment dc) {
         if (keepDocComments && dc != null) {
 //          System.out.println("doc comment = ");System.out.println(dc);//DEBUG
             docComments.putComment(tree, dc);
@@ -530,19 +530,19 @@
 
 /* -------- source positions ------- */
 
-    private void setErrorEndPos(int errPos) {
+    protected void setErrorEndPos(int errPos) {
         endPosTable.setErrorEndPos(errPos);
     }
 
-    private void storeEnd(JCTree tree, int endpos) {
+    protected void storeEnd(JCTree tree, int endpos) {
         endPosTable.storeEnd(tree, endpos);
     }
 
-    private <T extends JCTree> T to(T t) {
+    protected <T extends JCTree> T to(T t) {
         return endPosTable.to(t);
     }
 
-    private <T extends JCTree> T toP(T t) {
+    protected <T extends JCTree> T toP(T t) {
         return endPosTable.toP(t);
     }
 
@@ -574,7 +574,7 @@
     /**
      * Ident = IDENTIFIER
      */
-    Name ident() {
+    protected Name ident() {
         if (token.kind == IDENTIFIER) {
             Name name = token.name();
             nextToken();
@@ -789,7 +789,7 @@
         return term(TYPE);
     }
 
-    JCExpression term(int newmode) {
+    protected JCExpression term(int newmode) {
         int prevmode = mode;
         mode = newmode;
         JCExpression t = term();
@@ -1669,7 +1669,7 @@
     }
 
     /** Accepts all identifier-like tokens */
-    Filter<TokenKind> LAX_IDENTIFIER = new Filter<TokenKind>() {
+    protected Filter<TokenKind> LAX_IDENTIFIER = new Filter<TokenKind>() {
         public boolean accepts(TokenKind t) {
             return t == IDENTIFIER || t == UNDERSCORE || t == ASSERT || t == ENUM;
         }
@@ -2408,7 +2408,7 @@
      *     | ASSERT Expression [ ":" Expression ] ";"
      *     | ";"
      */
-    JCStatement parseSimpleStatement() {
+    public JCStatement parseSimpleStatement() {
         int pos = token.pos;
         switch (token.kind) {
         case LBRACE:
@@ -2706,7 +2706,7 @@
      *
      * @param kind Whether to parse an ANNOTATION or TYPE_ANNOTATION
      */
-    List<JCAnnotation> annotationsOpt(Tag kind) {
+    protected List<JCAnnotation> annotationsOpt(Tag kind) {
         if (token.kind != MONKEYS_AT) return List.nil(); // optimization
         ListBuffer<JCAnnotation> buf = new ListBuffer<>();
         int prevmode = mode;
@@ -2732,7 +2732,7 @@
      *           | NATIVE | SYNCHRONIZED | TRANSIENT | VOLATILE | "@"
      *           | "@" Annotation
      */
-    JCModifiers modifiersOpt() {
+    protected JCModifiers modifiersOpt() {
         return modifiersOpt(null);
     }
     protected JCModifiers modifiersOpt(JCModifiers partial) {
@@ -2914,7 +2914,7 @@
      *  @param reqInit  Is an initializer always required?
      *  @param dc       The documentation comment for the variable declarations, or null.
      */
-    <T extends ListBuffer<? super JCVariableDecl>> T variableDeclaratorsRest(int pos,
+    protected <T extends ListBuffer<? super JCVariableDecl>> T variableDeclaratorsRest(int pos,
                                                                      JCModifiers mods,
                                                                      JCExpression type,
                                                                      Name name,
@@ -3117,7 +3117,7 @@
 
     /** ImportDeclaration = IMPORT [ STATIC ] Ident { "." Ident } [ "." "*" ] ";"
      */
-    JCTree importDeclaration() {
+    protected JCTree importDeclaration() {
         int pos = token.pos;
         nextToken();
         boolean importStatic = false;
@@ -3159,7 +3159,7 @@
      *  @param mods     Any modifiers starting the class or interface declaration
      *  @param dc       The documentation comment for the class, or null.
      */
-    JCStatement classOrInterfaceOrEnumDeclaration(JCModifiers mods, Comment dc) {
+    protected JCStatement classOrInterfaceOrEnumDeclaration(JCModifiers mods, Comment dc) {
         if (token.kind == CLASS) {
             return classDeclaration(mods, dc);
         } else if (token.kind == INTERFACE) {
@@ -3569,7 +3569,7 @@
      *  TypeParametersOpt = ["<" TypeParameter {"," TypeParameter} ">"]
      *  }
      */
-    List<JCTypeParameter> typeParametersOpt() {
+    protected List<JCTypeParameter> typeParametersOpt() {
         if (token.kind == LT) {
             ListBuffer<JCTypeParameter> typarams = new ListBuffer<>();
             nextToken();
@@ -4004,7 +4004,7 @@
             allowTypeAnnotations = true;
         }
     }
-    void checkAnnotationsAfterTypeParams(int pos) {
+    protected void checkAnnotationsAfterTypeParams(int pos) {
         if (!allowAnnotationsAfterTypeParams) {
             log.error(pos, "annotations.after.type.params.not.supported.in.source", source.name);
             allowAnnotationsAfterTypeParams = true;
@@ -4092,7 +4092,7 @@
         /**
          * Store the last error position.
          */
-        protected int errorEndPos = Position.NOPOS;
+        public int errorEndPos = Position.NOPOS;
 
         public AbstractEndPosTable(JavacParser parser) {
             this.parser = parser;
@@ -4119,13 +4119,13 @@
          * will be set only if it is greater than the last stored error position.
          * @param errPos The error position
          */
-        protected void setErrorEndPos(int errPos) {
+        public void setErrorEndPos(int errPos) {
             if (errPos > errorEndPos) {
                 errorEndPos = errPos;
             }
         }
 
-        protected void setParser(JavacParser parser) {
+        public void setParser(JavacParser parser) {
             this.parser = parser;
         }
     }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Thu Dec 18 19:57:56 2014 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Tue Dec 23 13:58:01 2014 -0800
@@ -1196,9 +1196,6 @@
 compiler.note.compressed.diags=\
     Some messages have been simplified; recompile with -Xdiags:verbose to get full output
 
-compiler.note.potential.lambda.found=\
-    This anonymous inner class creation can be turned into a lambda expression.
-
 # 0: boolean, 1: symbol
 compiler.note.lambda.stat=\
     Translating lambda expression\n\
@@ -1640,14 +1637,20 @@
 
 # 0: unused, 1: unused
 compiler.warn.diamond.redundant.args=\
-    redundant type arguments in new expression (use diamond operator instead).
-
-# 0: type, 1: type
+    Redundant type arguments in new expression (use diamond operator instead).
+
+# 0: type, 1: list of type
 compiler.warn.diamond.redundant.args.1=\
-    redundant type arguments in new expression (use diamond operator instead).\n\
+    Redundant type arguments in new expression (use diamond operator instead).\n\
     explicit: {0}\n\
     inferred: {1}
 
+compiler.warn.potential.lambda.found=\
+    This anonymous inner class creation can be turned into a lambda expression.
+
+compiler.warn.method.redundant.typeargs=\
+    Redundant type arguments in method call.
+
 # 0: symbol, 1: message segment
 compiler.warn.varargs.redundant.trustme.anno=\
     Redundant {0} annotation. {1}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Thu Dec 18 19:57:56 2014 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Tue Dec 23 13:58:01 2014 -0800
@@ -313,6 +313,14 @@
         }
     }
 
+    /** Return true if the tree corresponds to a statement */
+    public static boolean isStatement(JCTree tree) {
+        return (tree instanceof JCStatement) &&
+                !tree.hasTag(CLASSDEF) &&
+                !tree.hasTag(Tag.BLOCK) &&
+                !tree.hasTag(METHODDEF);
+    }
+
     /**
      * Return true if the AST corresponds to a static select of the kind A.B
      */
--- a/langtools/src/jdk.dev/share/classes/com/sun/tools/jdeps/JdepsTask.java	Thu Dec 18 19:57:56 2014 -0800
+++ b/langtools/src/jdk.dev/share/classes/com/sun/tools/jdeps/JdepsTask.java	Tue Dec 23 13:58:01 2014 -0800
@@ -554,8 +554,9 @@
         classpaths.addAll(PlatformClassPath.getModules(options.mpath));
         if (options.mpath != null) {
             initialArchives.addAll(PlatformClassPath.getModules(options.mpath));
+        } else {
+            classpaths.addAll(PlatformClassPath.getJarFiles());
         }
-        classpaths.addAll(PlatformClassPath.getJarFiles());
         // add all classpath archives to the source locations for reporting
         sourceLocations.addAll(classpaths);
     }
--- a/langtools/test/Makefile	Thu Dec 18 19:57:56 2014 -0800
+++ b/langtools/test/Makefile	Tue Dec 23 13:58:01 2014 -0800
@@ -21,7 +21,6 @@
 ifeq ($(OSNAME), SunOS)
   SLASH_JAVA = /java
   PLATFORM = solaris
-  JT_PLATFORM = solaris
   ARCH = $(shell uname -p)
   ifeq ($(ARCH), i386)
     ARCH=i586
@@ -30,7 +29,6 @@
 ifeq ($(OSNAME), Linux)
   SLASH_JAVA = /java
   PLATFORM = linux
-  JT_PLATFORM = linux
   ARCH = $(shell uname -m)
   ifeq ($(ARCH), i386)
     ARCH=i586
@@ -38,7 +36,6 @@
 endif
 ifeq ($(OSNAME), Darwin)
   PLATFORM = bsd
-  JT_PLATFORM = linux
   ARCH = $(shell uname -m)
   ifeq ($(ARCH), i386)
     ARCH=i586
@@ -55,7 +52,6 @@
 
 ifeq ($(PLATFORM), windows)
   SLASH_JAVA = J:
-  JT_PLATFORM = win32
   ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)),ia64)
     ARCH=ia64
   else
@@ -93,8 +89,8 @@
 else
   JTREG_HOME = $(SLASH_JAVA)/re/jtreg/4.1/promoted/latest/binaries/jtreg
 endif
-JTREG = $(JTREG_HOME)/$(JT_PLATFORM)/bin/jtreg
-JTDIFF = $(JTREG_HOME)/$(JT_PLATFORM)/bin/jtdiff
+JTREG = $(JTREG_HOME)/bin/jtreg
+JTDIFF = $(JTREG_HOME)/bin/jtdiff
 
 # Default JCK to run
 ifdef JPRT_JCK_HOME
@@ -105,21 +101,19 @@
 
 # Default JDK for JTREG and JCK
 #
-# JT_JAVA is the version of java used to run jtreg/JCK. Since it is now
-# standard to execute tests in sameVM mode, it should normally be set the
-# same as TESTJAVA (although not necessarily so.)
+# JT_JAVA is the version of java used to run jtreg/JCK. 
 #
 ifdef JPRT_JAVA_HOME
   JT_JAVA = $(JPRT_JAVA_HOME)
 else
-  JT_JAVA = $(SLASH_JAVA)/re/jdk/1.7.0/archive/fcs/binaries/$(PLATFORM)-$(ARCH)
+  JT_JAVA = $(SLASH_JAVA)/re/jdk/1.9.0/archive/fcs/binaries/$(PLATFORM)-$(ARCH)
 endif
 
 # Default JDK to test
 ifdef JPRT_IMPORT_PRODUCT_HOME
   TESTJAVA = $(JPRT_IMPORT_PRODUCT_HOME)
 else
-  TESTJAVA = $(SLASH_JAVA)/re/jdk/1.7.0/promoted/latest/binaries/$(PLATFORM)-$(ARCH)
+  TESTJAVA = $(SLASH_JAVA)/re/jdk/1.9.0/promoted/latest/binaries/$(PLATFORM)-$(ARCH)
 endif
 
 # PRODUCT_HOME is a JPRT variable pointing to a directory containing the output from
@@ -152,7 +146,7 @@
 ifdef CONCURRENCY
   JTREG_OPTIONS += -agentvm -concurrency:$(CONCURRENCY)
 else
-  JTREG_OPTIONS += -samevm
+  JTREG_OPTIONS += -agentvm
 endif
 
 ifdef JCK_CONCURRENCY
--- a/langtools/test/tools/javac/diags/examples/DiamondRedundantArgs.java	Thu Dec 18 19:57:56 2014 -0800
+++ b/langtools/test/tools/javac/diags/examples/DiamondRedundantArgs.java	Tue Dec 23 13:58:01 2014 -0800
@@ -22,8 +22,8 @@
  */
 
 // key: compiler.warn.diamond.redundant.args
-// options: -XDfindDiamond
+// options: -XDfind=diamond
 
-class Foo<X> {
-   Foo<String> fs = new Foo<String>();
+class DiamondRedundantArgs<X> {
+   DiamondRedundantArgs<String> fs = new DiamondRedundantArgs<String>();
 }
--- a/langtools/test/tools/javac/diags/examples/DiamondRedundantArgs1.java	Thu Dec 18 19:57:56 2014 -0800
+++ b/langtools/test/tools/javac/diags/examples/DiamondRedundantArgs1.java	Tue Dec 23 13:58:01 2014 -0800
@@ -22,8 +22,8 @@
  */
 
 // key: compiler.warn.diamond.redundant.args.1
-// options: -XDfindDiamond
+// options: -XDfind=diamond
 
-class Foo<X> {
-   Foo<?> fs = new Foo<String>();
+class DiamondRedundantArgs1<X> {
+   DiamondRedundantArgs1<?> fs = new DiamondRedundantArgs1<String>();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/MethodRedundantTypeargs.java	Tue Dec 23 13:58:01 2014 -0800
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014, 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.warn.method.redundant.typeargs
+// options: -XDfind=method
+
+class MethodRedundantTypeargs {
+    <Z> Z id(Z z) { return z; }
+
+    void test() {
+        String s = this.<String>id("");
+    }
+}
--- a/langtools/test/tools/javac/diags/examples/PotentialLambdaFound.java	Thu Dec 18 19:57:56 2014 -0800
+++ b/langtools/test/tools/javac/diags/examples/PotentialLambdaFound.java	Tue Dec 23 13:58:01 2014 -0800
@@ -21,8 +21,8 @@
  * questions.
  */
 
-// key: compiler.note.potential.lambda.found
-// options: -XDidentifyLambdaCandidate=true
+// key: compiler.warn.potential.lambda.found
+// options: -XDfind=lambda
 
 class PotentialLambdaFound {
 
--- a/langtools/test/tools/javac/generics/diamond/6939780/T6939780.java	Thu Dec 18 19:57:56 2014 -0800
+++ b/langtools/test/tools/javac/generics/diamond/6939780/T6939780.java	Tue Dec 23 13:58:01 2014 -0800
@@ -1,11 +1,11 @@
 /*
  * @test /nodynamiccopyright/
- * @bug 6939780 7020044 8009459 8021338
+ * @bug 6939780 7020044 8009459 8021338 8064365
  *
  * @summary  add a warning to detect diamond sites
  * @author mcimadamore
- * @compile/ref=T6939780_7.out -Xlint:-options -source 7 T6939780.java -XDrawDiagnostics -XDfindDiamond
- * @compile/ref=T6939780_8.out T6939780.java -XDrawDiagnostics -XDfindDiamond
+ * @compile/ref=T6939780_7.out -Xlint:-options -source 7 T6939780.java -XDrawDiagnostics -XDfind=diamond
+ * @compile/ref=T6939780_8.out T6939780.java -XDrawDiagnostics -XDfind=diamond
  *
  */
 
--- a/langtools/test/tools/javac/generics/diamond/6939780/T6939780_7.out	Thu Dec 18 19:57:56 2014 -0800
+++ b/langtools/test/tools/javac/generics/diamond/6939780/T6939780_7.out	Tue Dec 23 13:58:01 2014 -0800
@@ -1,4 +1,5 @@
-T6939780.java:21:28: compiler.warn.diamond.redundant.args: T6939780.Foo<java.lang.Number>, T6939780.Foo<java.lang.Number>
+T6939780.java:21:28: compiler.warn.diamond.redundant.args
 T6939780.java:22:28: compiler.warn.diamond.redundant.args.1: T6939780.Foo<java.lang.Integer>, T6939780.Foo<java.lang.Number>
-T6939780.java:30:19: compiler.warn.diamond.redundant.args: T6939780.Foo<java.lang.Number>, T6939780.Foo<java.lang.Number>
-3 warnings
+T6939780.java:30:19: compiler.warn.diamond.redundant.args
+T6939780.java:31:19: compiler.warn.diamond.redundant.args.1: T6939780.Foo<java.lang.Integer>, T6939780.Foo<java.lang.Number>
+4 warnings
--- a/langtools/test/tools/javac/generics/diamond/6939780/T6939780_8.out	Thu Dec 18 19:57:56 2014 -0800
+++ b/langtools/test/tools/javac/generics/diamond/6939780/T6939780_8.out	Tue Dec 23 13:58:01 2014 -0800
@@ -1,7 +1,7 @@
-T6939780.java:20:33: compiler.warn.diamond.redundant.args: T6939780.Foo<java.lang.Number>, T6939780.Foo<java.lang.Number>
-T6939780.java:21:28: compiler.warn.diamond.redundant.args: T6939780.Foo<java.lang.Number>, T6939780.Foo<java.lang.Number>
+T6939780.java:20:33: compiler.warn.diamond.redundant.args
+T6939780.java:21:28: compiler.warn.diamond.redundant.args
 T6939780.java:22:28: compiler.warn.diamond.redundant.args.1: T6939780.Foo<java.lang.Integer>, T6939780.Foo<java.lang.Number>
-T6939780.java:29:19: compiler.warn.diamond.redundant.args: T6939780.Foo<java.lang.Number>, T6939780.Foo<java.lang.Number>
-T6939780.java:30:19: compiler.warn.diamond.redundant.args: T6939780.Foo<java.lang.Number>, T6939780.Foo<java.lang.Number>
+T6939780.java:29:19: compiler.warn.diamond.redundant.args
+T6939780.java:30:19: compiler.warn.diamond.redundant.args
 T6939780.java:31:19: compiler.warn.diamond.redundant.args.1: T6939780.Foo<java.lang.Integer>, T6939780.Foo<java.lang.Number>
 6 warnings
--- a/langtools/test/tools/javac/generics/diamond/7002837/T7002837.java	Thu Dec 18 19:57:56 2014 -0800
+++ b/langtools/test/tools/javac/generics/diamond/7002837/T7002837.java	Tue Dec 23 13:58:01 2014 -0800
@@ -1,10 +1,10 @@
 /*
  * @test /nodynamiccopyright/
- * @bug 7002837
+ * @bug 7002837 8064365
  *
  * @summary  Diamond: javac generates diamond inference errors when in 'finder' mode
  * @author mcimadamore
- * @compile/fail/ref=T7002837.out -Werror -XDrawDiagnostics -XDfindDiamond T7002837.java
+ * @compile/fail/ref=T7002837.out -Werror -XDrawDiagnostics -XDfind=diamond T7002837.java
  *
  */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8066974/T8066974.java	Tue Dec 23 13:58:01 2014 -0800
@@ -0,0 +1,44 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8066974
+ * @summary Compiler doesn't infer method's generic type information in lambda body
+ * @compile/fail/ref=T8066974.out -XDrawDiagnostics T8066974.java
+ */
+class T8066974 {
+    static class Throwing<E extends Throwable> { }
+    static class RuntimeThrowing extends Throwing<RuntimeException> { }
+    static class CheckedThrowing extends Throwing<Exception> { }
+
+    interface Parameter {
+        <E extends Throwable> Object m(Throwing<E> tw) throws E;
+    }
+
+    interface Mapper<R> {
+        R m(Parameter p);
+    }
+
+    <Z> Z map(Mapper<Z> mz) { return null; }
+
+    <Z extends Throwable> Mapper<Throwing<Z>> mapper(Throwing<Z> tz) throws Z { return null; }
+
+    static class ThrowingMapper<X extends Throwable> implements Mapper<Throwing<X>> {
+        ThrowingMapper(Throwing<X> arg) throws X { }
+
+        @Override
+        public Throwing<X> m(Parameter p) {
+        return null;
+        }
+    }
+
+    void testRuntime(RuntimeThrowing rt) {
+        map(p->p.m(rt));
+        map(mapper(rt));
+        map(new ThrowingMapper<>(rt));
+    }
+
+    void testChecked(CheckedThrowing ct) {
+        map(p->p.m(ct));
+        map(mapper(ct));
+        map(new ThrowingMapper<>(ct));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8066974/T8066974.out	Tue Dec 23 13:58:01 2014 -0800
@@ -0,0 +1,4 @@
+T8066974.java:40:19: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
+T8066974.java:41:19: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
+T8066974.java:42:13: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
+3 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8067792/T8067792.java	Tue Dec 23 13:58:01 2014 -0800
@@ -0,0 +1,19 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8067792
+ * @summary Javac crashes in finder mode with nested implicit lambdas
+ * @compile/fail/ref=T8067792.out -XDrawDiagnostics -Werror -XDfind=lambda T8067792.java
+ */
+
+import java.util.stream.*;
+import java.util.*;
+
+class T8067792 {
+    void test(Stream<List<?>> sl) {
+        Runnable r = new Runnable() {
+            public void run() {
+                Stream<List<?>> constructor = sl.filter(c -> true);
+            }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8067792/T8067792.out	Tue Dec 23 13:58:01 2014 -0800
@@ -0,0 +1,4 @@
+T8067792.java:13:37: compiler.warn.potential.lambda.found
+- compiler.err.warnings.and.werror
+1 error
+1 warning
--- a/langtools/test/tools/javac/lambda/LambdaConv18.java	Thu Dec 18 19:57:56 2014 -0800
+++ b/langtools/test/tools/javac/lambda/LambdaConv18.java	Tue Dec 23 13:58:01 2014 -0800
@@ -1,9 +1,9 @@
 /*
  * @test /nodynamiccopyright/
- * @bug 8003280
+ * @bug 8003280 8064365
  * @summary Add lambda tests
  *  simple test for lambda candidate check
- * @compile/fail/ref=LambdaConv18.out -XDrawDiagnostics -XDidentifyLambdaCandidate=true LambdaConv18.java
+ * @compile/fail/ref=LambdaConv18.out -XDrawDiagnostics -XDfind=lambda LambdaConv18.java
  */
 
 class LambdaConv18 {
--- a/langtools/test/tools/javac/lambda/LambdaConv18.out	Thu Dec 18 19:57:56 2014 -0800
+++ b/langtools/test/tools/javac/lambda/LambdaConv18.out	Tue Dec 23 13:58:01 2014 -0800
@@ -1,4 +1,5 @@
 LambdaConv18.java:23:5: compiler.err.cant.resolve.location: kindname.class, NonExistent, , , (compiler.misc.location: kindname.class, LambdaConv18, null)
-LambdaConv18.java:20:24: compiler.note.potential.lambda.found
+LambdaConv18.java:20:24: compiler.warn.potential.lambda.found
 LambdaConv18.java:23:26: compiler.err.cant.resolve.location: kindname.class, NonExistent, , , (compiler.misc.location: kindname.class, LambdaConv18, null)
 2 errors
+1 warning
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/lambdaNaming/TestNonSerializableLambdaNameStability.java	Tue Dec 23 13:58:01 2014 -0800
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+/*
+ * @test
+ * @bug 8067422
+ * @summary Check that the lambda names are not unnecessarily unstable
+ * @library /tools/lib
+ * @build ToolBox
+ * @run main TestNonSerializableLambdaNameStability
+ */
+
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.Method;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import javax.tools.StandardLocation;
+
+public class TestNonSerializableLambdaNameStability {
+
+    public static void main(String... args) throws Exception {
+        new TestNonSerializableLambdaNameStability().run();
+    }
+
+    String lambdaSource = "public class L%d {\n" +
+                          "    public static class A {\n" +
+                          "        private Runnable r = () -> { };\n" +
+                          "    }\n" +
+                          "    public static class B {\n" +
+                          "        private Runnable r = () -> { };\n" +
+                          "    }\n" +
+                          "    private Runnable r = () -> { };\n" +
+                          "}\n";
+
+    String expectedLambdaMethodName = "lambda$new$0";
+
+    void run() throws Exception {
+        List<String> sources = new ArrayList<>();
+
+        for (int i = 0; i < 3; i++) {
+            sources.add(String.format(lambdaSource, i));
+        }
+
+        ToolBox tb = new ToolBox();
+
+        try (ToolBox.MemoryFileManager fm = new ToolBox.MemoryFileManager()) {
+            tb.new JavacTask()
+              .sources(sources.toArray(new String[sources.size()]))
+              .fileManager(fm)
+              .run();
+
+            for (String file : fm.files.get(StandardLocation.CLASS_OUTPUT).keySet()) {
+                byte[] fileBytes = fm.getFileBytes(StandardLocation.CLASS_OUTPUT, file);
+                try (InputStream in = new ByteArrayInputStream(fileBytes)) {
+                    boolean foundLambdaMethod = false;
+                    ClassFile cf = ClassFile.read(in);
+                    StringBuilder seenMethods = new StringBuilder();
+                    String sep = "";
+                    for (Method m : cf.methods) {
+                        String methodName = m.getName(cf.constant_pool);
+                        if (expectedLambdaMethodName.equals(methodName)) {
+                            foundLambdaMethod = true;
+                            break;
+                        }
+                        seenMethods.append(sep);
+                        seenMethods.append(methodName);
+                        sep = ", ";
+                    }
+
+                    if (!foundLambdaMethod) {
+                        throw new AbstractMethodError("Did not find the lambda method, " +
+                                                      "found methods: " + seenMethods.toString());
+                    }
+                }
+            }
+        }
+    }
+}
--- a/langtools/test/tools/javac/lambda/speculative/DiamondFinder.java	Thu Dec 18 19:57:56 2014 -0800
+++ b/langtools/test/tools/javac/lambda/speculative/DiamondFinder.java	Tue Dec 23 13:58:01 2014 -0800
@@ -23,10 +23,10 @@
 
 /*
  * @test
- * @bug 8003280
+ * @bug 8003280 8064365
  * @summary Add lambda tests
  *  spurious crashes when running in 'diamond finder' mode
- * @compile -XDfindDiamond DiamondFinder.java
+ * @compile -XDfind=diamond DiamondFinder.java
  */
 import java.util.*;