7177387: Add target-typing support in method context
authormcimadamore
Thu, 04 Oct 2012 13:04:53 +0100
changeset 14057 b4b0377b8dba
parent 14056 0ea78d6e0b7b
child 14058 c7ec7facdd20
7177387: Add target-typing support in method context Summary: Add support for deferred types and speculative attribution Reviewed-by: jjg, dlsmith
langtools/src/share/classes/com/sun/tools/javac/code/Printer.java
langtools/src/share/classes/com/sun/tools/javac/code/Source.java
langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java
langtools/src/share/classes/com/sun/tools/javac/code/Type.java
langtools/src/share/classes/com/sun/tools/javac/code/TypeTags.java
langtools/src/share/classes/com/sun/tools/javac/code/Types.java
langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
langtools/src/share/classes/com/sun/tools/javac/comp/AttrContext.java
langtools/src/share/classes/com/sun/tools/javac/comp/Check.java
langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java
langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java
langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java
langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java
langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java
langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java
langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java
langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties
langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java
langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java
langtools/src/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java
langtools/src/share/classes/com/sun/tools/javac/util/List.java
langtools/src/share/classes/com/sun/tools/javac/util/Log.java
langtools/src/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java
langtools/test/tools/javac/conditional/Conditional.java
langtools/test/tools/javac/diags/examples.not-yet.txt
langtools/test/tools/javac/diags/examples/IncompatibleTypesInConditional.java
langtools/test/tools/javac/diags/examples/TypeConditional.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Printer.java	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Printer.java	Thu Oct 04 13:04:53 2012 +0100
@@ -30,6 +30,10 @@
 import com.sun.tools.javac.api.Messages;
 import com.sun.tools.javac.code.Type.*;
 import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.comp.DeferredAttr.DeferredType;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.Pretty;
+import com.sun.tools.javac.util.Assert;
 import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.util.ListBuffer;
 
@@ -50,6 +54,11 @@
 
     List<Type> seenCaptured = List.nil();
     static final int PRIME = 997;  // largest prime less than 1000
+    boolean raw;
+
+    protected Printer(boolean raw) {
+        this.raw = raw;
+    }
 
     /**
      * This method should be overriden in order to provide proper i18n support.
@@ -78,7 +87,7 @@
      * @return printer visitor instance
      */
     public static Printer createStandardPrinter(final Messages messages) {
-        return new Printer() {
+        return new Printer(false) {
             @Override
             protected String localize(Locale locale, String key, Object... args) {
                 return messages.getLocalizedString(locale, key, args);
@@ -165,6 +174,34 @@
         return "<" + visitTypes(t.tvars, locale) + ">" + visit(t.qtype, locale);
     }
 
+    public String visitDeferredType(DeferredType t, Locale locale) {
+        return raw ? localize(locale, getDeferredKey(t.tree)) :
+            deferredTypeTree2String(t.tree);
+    }
+    //where
+        private String deferredTypeTree2String(JCTree tree) {
+            switch(tree.getTag()) {
+                case PARENS:
+                    return deferredTypeTree2String(((JCTree.JCParens)tree).expr);
+                case CONDEXPR:
+                    return Pretty.toSimpleString(tree, 15);
+                default:
+                    Assert.error("unexpected tree kind " + tree.getKind());
+                    return null;
+            }
+        }
+        private String getDeferredKey (JCTree tree) {
+            switch (tree.getTag()) {
+                case PARENS:
+                    return getDeferredKey(((JCTree.JCParens)tree).expr);
+                case CONDEXPR:
+                     return "compiler.misc.type.conditional";
+                default:
+                    Assert.error("unexpected tree kind " + tree.getKind());
+                    return null;
+            }
+        }
+
     @Override
     public String visitUndetVar(UndetVar t, Locale locale) {
         if (t.inst != null) {
@@ -228,10 +265,14 @@
     }
 
     public String visitType(Type t, Locale locale) {
-        String s = (t.tsym == null || t.tsym.name == null)
-                ? localize(locale, "compiler.misc.type.none")
-                : t.tsym.name.toString();
-        return s;
+        if (t.tag == DEFERRED) {
+            return visitDeferredType((DeferredType)t, locale);
+        } else {
+            String s = (t.tsym == null || t.tsym.name == null)
+                    ? localize(locale, "compiler.misc.type.none")
+                    : t.tsym.name.toString();
+            return s;
+        }
     }
 
     /**
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java	Thu Oct 04 13:04:53 2012 +0100
@@ -194,6 +194,9 @@
     public boolean allowObjectToPrimitiveCast() {
         return compareTo(JDK1_7) >= 0;
     }
+    public boolean allowPoly() {
+        return compareTo(JDK1_8) >= 0;
+    }
     public boolean allowLambda() {
         return compareTo(JDK1_8) >= 0;
     }
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java	Thu Oct 04 13:04:53 2012 +0100
@@ -183,6 +183,10 @@
      */
     public final Name[] boxedName = new Name[TypeTags.TypeTagCount];
 
+    /** A set containing all operator names.
+     */
+    public final Set<Name> operatorNames = new HashSet<Name>();
+
     /** A hashtable containing the encountered top-level and member classes,
      *  indexed by flat names. The table does not contain local classes.
      *  It should be updated from the outside to reflect classes defined
@@ -244,7 +248,7 @@
                             int opcode) {
         predefClass.members().enter(
             new OperatorSymbol(
-                names.fromString(name),
+                makeOperatorName(name),
                 new MethodType(List.of(left, right), res,
                                List.<Type>nil(), methodClass),
                 opcode,
@@ -275,7 +279,7 @@
                                      Type res,
                                      int opcode) {
         OperatorSymbol sym =
-            new OperatorSymbol(names.fromString(name),
+            new OperatorSymbol(makeOperatorName(name),
                                new MethodType(List.of(arg),
                                               res,
                                               List.<Type>nil(),
@@ -286,6 +290,16 @@
         return sym;
     }
 
+    /**
+     * Create a new operator name from corresponding String representation
+     * and add the name to the set of known operator names.
+     */
+    private Name makeOperatorName(String name) {
+        Name opName = names.fromString(name);
+        operatorNames.add(opName);
+        return opName;
+    }
+
     /** Enter a class into symbol table.
      *  @param    The name of the class.
      */
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java	Thu Oct 04 13:04:53 2012 +0100
@@ -75,6 +75,9 @@
     /** Constant type: no type at all. */
     public static final JCNoType noType = new JCNoType(NONE);
 
+    /** Constant type: special type to be used during recovery of deferred expressions. */
+    public static final JCNoType recoveryType = new JCNoType(NONE);
+
     /** If this switch is turned on, the names of type variables
      *  and anonymous classes are printed with hashcodes appended.
      */
--- a/langtools/src/share/classes/com/sun/tools/javac/code/TypeTags.java	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/TypeTags.java	Thu Oct 04 13:04:53 2012 +0100
@@ -102,9 +102,13 @@
      */
     public static final int FORALL = WILDCARD+1;
 
+    /** The tag of deferred expression types in method context
+     */
+    public static final int DEFERRED = FORALL+1;
+
     /** The tag of the bottom type <null>.
      */
-    public static final int BOT = FORALL+1;
+    public static final int BOT = DEFERRED+1;
 
     /** The tag of a missing type.
      */
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java	Thu Oct 04 13:04:53 2012 +0100
@@ -3154,6 +3154,14 @@
         }
         return Type.noType;
     }
+
+    /**
+     * Return the unboxed type if 't' is a boxed class, otherwise return 't' itself.
+     */
+    public Type unboxedTypeOrType(Type t) {
+        Type unboxedType = unboxedType(t);
+        return unboxedType.tag == NONE ? t : unboxedType;
+    }
     // </editor-fold>
 
     // <editor-fold defaultstate="collapsed" desc="Capture conversion">
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Oct 04 13:04:53 2012 +0100
@@ -25,12 +25,10 @@
 
 package com.sun.tools.javac.comp;
 
-import java.util.*;
-import java.util.Set;
-import javax.lang.model.element.ElementKind;
-import javax.tools.JavaFileObject;
-
 import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
+import com.sun.tools.javac.comp.Infer.InferenceContext;
+import com.sun.tools.javac.comp.Infer.InferenceContext.FreeTypeListener;
 import com.sun.tools.javac.jvm.*;
 import com.sun.tools.javac.tree.*;
 import com.sun.tools.javac.util.*;
@@ -49,6 +47,11 @@
 import com.sun.source.tree.TreeVisitor;
 import com.sun.source.util.SimpleTreeVisitor;
 
+import java.util.*;
+import java.util.Set;
+import javax.lang.model.element.ElementKind;
+import javax.tools.JavaFileObject;
+
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Flags.ANNOTATION;
 import static com.sun.tools.javac.code.Flags.BLOCK;
@@ -80,6 +83,7 @@
     final Symtab syms;
     final Resolve rs;
     final Infer infer;
+    final DeferredAttr deferredAttr;
     final Check chk;
     final MemberEnter memberEnter;
     final TreeMaker make;
@@ -110,6 +114,7 @@
         make = TreeMaker.instance(context);
         enter = Enter.instance(context);
         infer = Infer.instance(context);
+        deferredAttr = DeferredAttr.instance(context);
         cfolder = ConstFold.instance(context);
         target = Target.instance(context);
         types = Types.instance(context);
@@ -127,6 +132,7 @@
         allowCovariantReturns = source.allowCovariantReturns();
         allowAnonOuterThis = source.allowAnonOuterThis();
         allowStringsInSwitch = source.allowStringsInSwitch();
+        allowPoly = source.allowPoly() && options.isSet("allowPoly");
         sourceName = source.name;
         relax = (options.isSet("-retrofit") ||
                  options.isSet("-relax"));
@@ -144,6 +150,10 @@
      */
     boolean relax;
 
+    /** Switch: support target-typing inference
+     */
+    boolean allowPoly;
+
     /** Switch: support generics?
      */
     boolean allowGenerics;
@@ -207,15 +217,29 @@
      *  @param ownkind  The computed kind of the tree
      *  @param resultInfo  The expected result of the tree
      */
-    Type check(JCTree tree, Type owntype, int ownkind, ResultInfo resultInfo) {
+    Type check(final JCTree tree, final Type found, final int ownkind, final ResultInfo resultInfo) {
+        InferenceContext inferenceContext = resultInfo.checkContext.inferenceContext();
+        Type owntype = found;
         if (owntype.tag != ERROR && resultInfo.pt.tag != METHOD && resultInfo.pt.tag != FORALL) {
-            if ((ownkind & ~resultInfo.pkind) == 0) {
-                owntype = resultInfo.check(tree, owntype);
+            if (inferenceContext.free(found)) {
+                inferenceContext.addFreeTypeListener(List.of(found, resultInfo.pt), new FreeTypeListener() {
+                    @Override
+                    public void typesInferred(InferenceContext inferenceContext) {
+                        ResultInfo pendingResult =
+                                    resultInfo.dup(inferenceContext.asInstType(resultInfo.pt, types));
+                        check(tree, inferenceContext.asInstType(found, types), ownkind, pendingResult);
+                    }
+                });
+                return tree.type = resultInfo.pt;
             } else {
-                log.error(tree.pos(), "unexpected.type",
-                          kindNames(resultInfo.pkind),
-                          kindName(ownkind));
-                owntype = types.createErrorType(owntype);
+                if ((ownkind & ~resultInfo.pkind) == 0) {
+                    owntype = resultInfo.check(tree, owntype);
+                } else {
+                    log.error(tree.pos(), "unexpected.type",
+                            kindNames(resultInfo.pkind),
+                            kindName(ownkind));
+                    owntype = types.createErrorType(owntype);
+                }
             }
         }
         tree.type = owntype;
@@ -297,8 +321,6 @@
             } else {
                 log.error(pos, "cant.assign.val.to.final.var", v);
             }
-        } else if ((v.flags() & EFFECTIVELY_FINAL) != 0) {
-            v.flags_field &= ~EFFECTIVELY_FINAL;
         }
     }
 
@@ -431,14 +453,38 @@
         static final long serialVersionUID = -6924771130405446405L;
         private Env<AttrContext> env;
         private BreakAttr(Env<AttrContext> env) {
-            this.env = env;
+            this.env = copyEnv(env);
+        }
+
+        private Env<AttrContext> copyEnv(Env<AttrContext> env) {
+            Env<AttrContext> newEnv =
+                    env.dup(env.tree, env.info.dup(copyScope(env.info.scope)));
+            if (newEnv.outer != null) {
+                newEnv.outer = copyEnv(newEnv.outer);
+            }
+            return newEnv;
+        }
+
+        private Scope copyScope(Scope sc) {
+            Scope newScope = new Scope(sc.owner);
+            List<Symbol> elemsList = List.nil();
+            while (sc != null) {
+                for (Scope.Entry e = sc.elems ; e != null ; e = e.sibling) {
+                    elemsList = elemsList.prepend(e.sym);
+                }
+                sc = sc.next;
+            }
+            for (Symbol s : elemsList) {
+                newScope.enter(s);
+            }
+            return newScope;
         }
     }
 
     class ResultInfo {
-        int pkind;
-        Type pt;
-        CheckContext checkContext;
+        final int pkind;
+        final Type pt;
+        final CheckContext checkContext;
 
         ResultInfo(int pkind, Type pt) {
             this(pkind, pt, chk.basicHandler);
@@ -450,15 +496,19 @@
             this.checkContext = checkContext;
         }
 
-        protected Type check(DiagnosticPosition pos, Type found) {
+        protected Type check(final DiagnosticPosition pos, final Type found) {
             return chk.checkType(pos, found, pt, checkContext);
         }
+
+        protected ResultInfo dup(Type newPt) {
+            return new ResultInfo(pkind, newPt, checkContext);
+        }
     }
 
-    private final ResultInfo statInfo;
-    private final ResultInfo varInfo;
-    private final ResultInfo unknownExprInfo;
-    private final ResultInfo unknownTypeInfo;
+    final ResultInfo statInfo;
+    final ResultInfo varInfo;
+    final ResultInfo unknownExprInfo;
+    final ResultInfo unknownTypeInfo;
 
     Type pt() {
         return resultInfo.pt;
@@ -491,7 +541,7 @@
      *  @param env     The environment visitor argument.
      *  @param resultInfo   The result info visitor argument.
      */
-    private Type attribTree(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
+    Type attribTree(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
         Env<AttrContext> prevEnv = this.env;
         ResultInfo prevResult = this.resultInfo;
         try {
@@ -563,9 +613,12 @@
      */
     List<Type> attribArgs(List<JCExpression> trees, Env<AttrContext> env) {
         ListBuffer<Type> argtypes = new ListBuffer<Type>();
-        for (List<JCExpression> l = trees; l.nonEmpty(); l = l.tail)
-            argtypes.append(chk.checkNonVoid(
-                l.head.pos(), types.upperBound(attribExpr(l.head, env, Infer.anyPoly))));
+        for (JCExpression arg : trees) {
+            Type argtype = allowPoly && TreeInfo.isPoly(arg, env.tree) ?
+                    deferredAttr.new DeferredType(arg, env) :
+                    chk.checkNonVoid(arg, attribExpr(arg, env, Infer.anyPoly));
+            argtypes.append(argtype);
+        }
         return argtypes.toList();
     }
 
@@ -979,8 +1032,11 @@
             // Create a new local environment with a local scope.
             Env<AttrContext> localEnv =
                 env.dup(tree, env.info.dup(env.info.scope.dup()));
-            attribStats(tree.stats, localEnv);
-            localEnv.info.scope.leave();
+            try {
+                attribStats(tree.stats, localEnv);
+            } finally {
+                localEnv.info.scope.leave();
+            }
         }
         result = null;
     }
@@ -1000,43 +1056,51 @@
     public void visitForLoop(JCForLoop tree) {
         Env<AttrContext> loopEnv =
             env.dup(env.tree, env.info.dup(env.info.scope.dup()));
-        attribStats(tree.init, loopEnv);
-        if (tree.cond != null) attribExpr(tree.cond, loopEnv, syms.booleanType);
-        loopEnv.tree = tree; // before, we were not in loop!
-        attribStats(tree.step, loopEnv);
-        attribStat(tree.body, loopEnv);
-        loopEnv.info.scope.leave();
-        result = null;
+        try {
+            attribStats(tree.init, loopEnv);
+            if (tree.cond != null) attribExpr(tree.cond, loopEnv, syms.booleanType);
+            loopEnv.tree = tree; // before, we were not in loop!
+            attribStats(tree.step, loopEnv);
+            attribStat(tree.body, loopEnv);
+            result = null;
+        }
+        finally {
+            loopEnv.info.scope.leave();
+        }
     }
 
     public void visitForeachLoop(JCEnhancedForLoop tree) {
         Env<AttrContext> loopEnv =
             env.dup(env.tree, env.info.dup(env.info.scope.dup()));
-        attribStat(tree.var, loopEnv);
-        Type exprType = types.upperBound(attribExpr(tree.expr, loopEnv));
-        chk.checkNonVoid(tree.pos(), exprType);
-        Type elemtype = types.elemtype(exprType); // perhaps expr is an array?
-        if (elemtype == null) {
-            // or perhaps expr implements Iterable<T>?
-            Type base = types.asSuper(exprType, syms.iterableType.tsym);
-            if (base == null) {
-                log.error(tree.expr.pos(),
-                        "foreach.not.applicable.to.type",
-                        exprType,
-                        diags.fragment("type.req.array.or.iterable"));
-                elemtype = types.createErrorType(exprType);
-            } else {
-                List<Type> iterableParams = base.allparams();
-                elemtype = iterableParams.isEmpty()
-                    ? syms.objectType
-                    : types.upperBound(iterableParams.head);
+        try {
+            attribStat(tree.var, loopEnv);
+            Type exprType = types.upperBound(attribExpr(tree.expr, loopEnv));
+            chk.checkNonVoid(tree.pos(), exprType);
+            Type elemtype = types.elemtype(exprType); // perhaps expr is an array?
+            if (elemtype == null) {
+                // or perhaps expr implements Iterable<T>?
+                Type base = types.asSuper(exprType, syms.iterableType.tsym);
+                if (base == null) {
+                    log.error(tree.expr.pos(),
+                            "foreach.not.applicable.to.type",
+                            exprType,
+                            diags.fragment("type.req.array.or.iterable"));
+                    elemtype = types.createErrorType(exprType);
+                } else {
+                    List<Type> iterableParams = base.allparams();
+                    elemtype = iterableParams.isEmpty()
+                        ? syms.objectType
+                        : types.upperBound(iterableParams.head);
+                }
             }
+            chk.checkType(tree.expr.pos(), elemtype, tree.var.sym.type);
+            loopEnv.tree = tree; // before, we were not in loop!
+            attribStat(tree.body, loopEnv);
+            result = null;
         }
-        chk.checkType(tree.expr.pos(), elemtype, tree.var.sym.type);
-        loopEnv.tree = tree; // before, we were not in loop!
-        attribStat(tree.body, loopEnv);
-        loopEnv.info.scope.leave();
-        result = null;
+        finally {
+            loopEnv.info.scope.leave();
+        }
     }
 
     public void visitLabelled(JCLabeledStatement tree) {
@@ -1062,61 +1126,69 @@
         Env<AttrContext> switchEnv =
             env.dup(tree, env.info.dup(env.info.scope.dup()));
 
-        boolean enumSwitch =
-            allowEnums &&
-            (seltype.tsym.flags() & Flags.ENUM) != 0;
-        boolean stringSwitch = false;
-        if (types.isSameType(seltype, syms.stringType)) {
-            if (allowStringsInSwitch) {
-                stringSwitch = true;
-            } else {
-                log.error(tree.selector.pos(), "string.switch.not.supported.in.source", sourceName);
+        try {
+
+            boolean enumSwitch =
+                allowEnums &&
+                (seltype.tsym.flags() & Flags.ENUM) != 0;
+            boolean stringSwitch = false;
+            if (types.isSameType(seltype, syms.stringType)) {
+                if (allowStringsInSwitch) {
+                    stringSwitch = true;
+                } else {
+                    log.error(tree.selector.pos(), "string.switch.not.supported.in.source", sourceName);
+                }
             }
+            if (!enumSwitch && !stringSwitch)
+                seltype = chk.checkType(tree.selector.pos(), seltype, syms.intType);
+
+            // Attribute all cases and
+            // check that there are no duplicate case labels or default clauses.
+            Set<Object> labels = new HashSet<Object>(); // The set of case labels.
+            boolean hasDefault = false;      // Is there a default label?
+            for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
+                JCCase c = l.head;
+                Env<AttrContext> caseEnv =
+                    switchEnv.dup(c, env.info.dup(switchEnv.info.scope.dup()));
+                try {
+                    if (c.pat != null) {
+                        if (enumSwitch) {
+                            Symbol sym = enumConstant(c.pat, seltype);
+                            if (sym == null) {
+                                log.error(c.pat.pos(), "enum.label.must.be.unqualified.enum");
+                            } else if (!labels.add(sym)) {
+                                log.error(c.pos(), "duplicate.case.label");
+                            }
+                        } else {
+                            Type pattype = attribExpr(c.pat, switchEnv, seltype);
+                            if (pattype.tag != ERROR) {
+                                if (pattype.constValue() == null) {
+                                    log.error(c.pat.pos(),
+                                              (stringSwitch ? "string.const.req" : "const.expr.req"));
+                                } else if (labels.contains(pattype.constValue())) {
+                                    log.error(c.pos(), "duplicate.case.label");
+                                } else {
+                                    labels.add(pattype.constValue());
+                                }
+                            }
+                        }
+                    } else if (hasDefault) {
+                        log.error(c.pos(), "duplicate.default.label");
+                    } else {
+                        hasDefault = true;
+                    }
+                    attribStats(c.stats, caseEnv);
+                } finally {
+                    caseEnv.info.scope.leave();
+                    addVars(c.stats, switchEnv.info.scope);
+                }
+            }
+
+            result = null;
         }
-        if (!enumSwitch && !stringSwitch)
-            seltype = chk.checkType(tree.selector.pos(), seltype, syms.intType);
-
-        // Attribute all cases and
-        // check that there are no duplicate case labels or default clauses.
-        Set<Object> labels = new HashSet<Object>(); // The set of case labels.
-        boolean hasDefault = false;      // Is there a default label?
-        for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
-            JCCase c = l.head;
-            Env<AttrContext> caseEnv =
-                switchEnv.dup(c, env.info.dup(switchEnv.info.scope.dup()));
-            if (c.pat != null) {
-                if (enumSwitch) {
-                    Symbol sym = enumConstant(c.pat, seltype);
-                    if (sym == null) {
-                        log.error(c.pat.pos(), "enum.label.must.be.unqualified.enum");
-                    } else if (!labels.add(sym)) {
-                        log.error(c.pos(), "duplicate.case.label");
-                    }
-                } else {
-                    Type pattype = attribExpr(c.pat, switchEnv, seltype);
-                    if (pattype.tag != ERROR) {
-                        if (pattype.constValue() == null) {
-                            log.error(c.pat.pos(),
-                                      (stringSwitch ? "string.const.req" : "const.expr.req"));
-                        } else if (labels.contains(pattype.constValue())) {
-                            log.error(c.pos(), "duplicate.case.label");
-                        } else {
-                            labels.add(pattype.constValue());
-                        }
-                    }
-                }
-            } else if (hasDefault) {
-                log.error(c.pos(), "duplicate.default.label");
-            } else {
-                hasDefault = true;
-            }
-            attribStats(c.stats, caseEnv);
-            caseEnv.info.scope.leave();
-            addVars(c.stats, switchEnv.info.scope);
+        finally {
+            switchEnv.info.scope.leave();
         }
-
-        switchEnv.info.scope.leave();
-        result = null;
     }
     // where
         /** Add any variables defined in stats to the switch scope. */
@@ -1158,63 +1230,72 @@
     public void visitTry(JCTry tree) {
         // Create a new local environment with a local
         Env<AttrContext> localEnv = env.dup(tree, env.info.dup(env.info.scope.dup()));
-        boolean isTryWithResource = tree.resources.nonEmpty();
-        // Create a nested environment for attributing the try block if needed
-        Env<AttrContext> tryEnv = isTryWithResource ?
-            env.dup(tree, localEnv.info.dup(localEnv.info.scope.dup())) :
-            localEnv;
-        // Attribute resource declarations
-        for (JCTree resource : tree.resources) {
-            CheckContext twrContext = new Check.NestedCheckContext(resultInfo.checkContext) {
-                @Override
-                public void report(DiagnosticPosition pos, JCDiagnostic details) {
-                    chk.basicHandler.report(pos, diags.fragment("try.not.applicable.to.type", details));
+        try {
+            boolean isTryWithResource = tree.resources.nonEmpty();
+            // Create a nested environment for attributing the try block if needed
+            Env<AttrContext> tryEnv = isTryWithResource ?
+                env.dup(tree, localEnv.info.dup(localEnv.info.scope.dup())) :
+                localEnv;
+            try {
+                // Attribute resource declarations
+                for (JCTree resource : tree.resources) {
+                    CheckContext twrContext = new Check.NestedCheckContext(resultInfo.checkContext) {
+                        @Override
+                        public void report(DiagnosticPosition pos, JCDiagnostic details) {
+                            chk.basicHandler.report(pos, diags.fragment("try.not.applicable.to.type", details));
+                        }
+                    };
+                    ResultInfo twrResult = new ResultInfo(VAL, syms.autoCloseableType, twrContext);
+                    if (resource.hasTag(VARDEF)) {
+                        attribStat(resource, tryEnv);
+                        twrResult.check(resource, resource.type);
+
+                        //check that resource type cannot throw InterruptedException
+                        checkAutoCloseable(resource.pos(), localEnv, resource.type);
+
+                        VarSymbol var = (VarSymbol)TreeInfo.symbolFor(resource);
+                        var.setData(ElementKind.RESOURCE_VARIABLE);
+                    } else {
+                        attribTree(resource, tryEnv, twrResult);
+                    }
                 }
-            };
-            ResultInfo twrResult = new ResultInfo(VAL, syms.autoCloseableType, twrContext);
-            if (resource.hasTag(VARDEF)) {
-                attribStat(resource, tryEnv);
-                twrResult.check(resource, resource.type);
-
-                //check that resource type cannot throw InterruptedException
-                checkAutoCloseable(resource.pos(), localEnv, resource.type);
-
-                VarSymbol var = (VarSymbol)TreeInfo.symbolFor(resource);
-                var.setData(ElementKind.RESOURCE_VARIABLE);
-            } else {
-                attribTree(resource, tryEnv, twrResult);
+                // Attribute body
+                attribStat(tree.body, tryEnv);
+            } finally {
+                if (isTryWithResource)
+                    tryEnv.info.scope.leave();
             }
+
+            // Attribute catch clauses
+            for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
+                JCCatch c = l.head;
+                Env<AttrContext> catchEnv =
+                    localEnv.dup(c, localEnv.info.dup(localEnv.info.scope.dup()));
+                try {
+                    Type ctype = attribStat(c.param, catchEnv);
+                    if (TreeInfo.isMultiCatch(c)) {
+                        //multi-catch parameter is implicitly marked as final
+                        c.param.sym.flags_field |= FINAL | UNION;
+                    }
+                    if (c.param.sym.kind == Kinds.VAR) {
+                        c.param.sym.setData(ElementKind.EXCEPTION_PARAMETER);
+                    }
+                    chk.checkType(c.param.vartype.pos(),
+                                  chk.checkClassType(c.param.vartype.pos(), ctype),
+                                  syms.throwableType);
+                    attribStat(c.body, catchEnv);
+                } finally {
+                    catchEnv.info.scope.leave();
+                }
+            }
+
+            // Attribute finalizer
+            if (tree.finalizer != null) attribStat(tree.finalizer, localEnv);
+            result = null;
         }
-        // Attribute body
-        attribStat(tree.body, tryEnv);
-        if (isTryWithResource)
-            tryEnv.info.scope.leave();
-
-        // Attribute catch clauses
-        for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
-            JCCatch c = l.head;
-            Env<AttrContext> catchEnv =
-                localEnv.dup(c, localEnv.info.dup(localEnv.info.scope.dup()));
-            Type ctype = attribStat(c.param, catchEnv);
-            if (TreeInfo.isMultiCatch(c)) {
-                //multi-catch parameter is implicitly marked as final
-                c.param.sym.flags_field |= FINAL | UNION;
-            }
-            if (c.param.sym.kind == Kinds.VAR) {
-                c.param.sym.setData(ElementKind.EXCEPTION_PARAMETER);
-            }
-            chk.checkType(c.param.vartype.pos(),
-                          chk.checkClassType(c.param.vartype.pos(), ctype),
-                          syms.throwableType);
-            attribStat(c.body, catchEnv);
-            catchEnv.info.scope.leave();
+        finally {
+            localEnv.info.scope.leave();
         }
-
-        // Attribute finalizer
-        if (tree.finalizer != null) attribStat(tree.finalizer, localEnv);
-
-        localEnv.info.scope.leave();
-        result = null;
     }
 
     void checkAutoCloseable(DiagnosticPosition pos, Env<AttrContext> env, Type resource) {
@@ -1222,10 +1303,10 @@
             types.asSuper(resource, syms.autoCloseableType.tsym) != null &&
             !types.isSameType(resource, syms.autoCloseableType)) { // Don't emit warning for AutoCloseable itself
             Symbol close = syms.noSymbol;
-            boolean prevDeferDiags = log.deferDiagnostics;
+            Filter<JCDiagnostic> prevDeferDiagsFilter = log.deferredDiagFilter;
             Queue<JCDiagnostic> prevDeferredDiags = log.deferredDiagnostics;
             try {
-                log.deferDiagnostics = true;
+                log.deferAll();
                 log.deferredDiagnostics = ListBuffer.lb();
                 close = rs.resolveQualifiedMethod(pos,
                         env,
@@ -1235,7 +1316,7 @@
                         List.<Type>nil());
             }
             finally {
-                log.deferDiagnostics = prevDeferDiags;
+                log.deferredDiagFilter = prevDeferDiagsFilter;
                 log.deferredDiagnostics = prevDeferredDiags;
             }
             if (close.kind == MTH &&
@@ -1248,50 +1329,71 @@
     }
 
     public void visitConditional(JCConditional tree) {
-        attribExpr(tree.cond, env, syms.booleanType);
-        attribExpr(tree.truepart, env);
-        attribExpr(tree.falsepart, env);
-        result = check(tree,
-                       capture(condType(tree.pos(), tree.cond.type,
-                                        tree.truepart.type, tree.falsepart.type)),
-                       VAL, resultInfo);
+        Type condtype = attribExpr(tree.cond, env, syms.booleanType);
+
+        boolean standaloneConditional = !allowPoly ||
+                pt().tag == NONE && pt() != Type.recoveryType ||
+                isBooleanOrNumeric(env, tree);
+
+        if (!standaloneConditional && resultInfo.pt.tag == VOID) {
+            //cannot get here (i.e. it means we are returning from void method - which is already an error)
+            result = tree.type = types.createErrorType(resultInfo.pt);
+            return;
+        }
+
+        ResultInfo condInfo = standaloneConditional ?
+                unknownExprInfo :
+                new ResultInfo(VAL, pt(), new Check.NestedCheckContext(resultInfo.checkContext) {
+                    //this will use enclosing check context to check compatibility of
+                    //subexpression against target type; if we are in a method check context,
+                    //depending on whether boxing is allowed, we could have incompatibilities
+                    @Override
+                    public void report(DiagnosticPosition pos, JCDiagnostic details) {
+                        enclosingContext.report(pos, diags.fragment("incompatible.type.in.conditional", details));
+                    }
+                });
+
+        Type truetype = attribTree(tree.truepart, env, condInfo);
+        Type falsetype = attribTree(tree.falsepart, env, condInfo);
+
+        Type owntype = standaloneConditional ? condType(tree, truetype, falsetype) : pt();
+        if (condtype.constValue() != null &&
+                truetype.constValue() != null &&
+                falsetype.constValue() != null) {
+            //constant folding
+            owntype = cfolder.coerce(condtype.isTrue() ? truetype : falsetype, owntype);
+        }
+        result = check(tree, owntype, VAL, resultInfo);
     }
     //where
+        @SuppressWarnings("fallthrough")
+        private boolean isBooleanOrNumeric(Env<AttrContext> env, JCExpression tree) {
+            switch (tree.getTag()) {
+                case LITERAL: return ((JCLiteral)tree).typetag < CLASS;
+                case LAMBDA: case REFERENCE: return false;
+                case PARENS: return isBooleanOrNumeric(env, ((JCParens)tree).expr);
+                case CONDEXPR:
+                    JCConditional condTree = (JCConditional)tree;
+                    return isBooleanOrNumeric(env, condTree.truepart) &&
+                            isBooleanOrNumeric(env, condTree.falsepart);
+                default:
+                    Type speculativeType = deferredAttr.attribSpeculative(tree, env, unknownExprInfo).type;
+                    speculativeType = types.unboxedTypeOrType(speculativeType);
+                    return speculativeType.tag <= BOOLEAN;
+            }
+        }
+
         /** Compute the type of a conditional expression, after
-         *  checking that it exists. See Spec 15.25.
-         *
-         *  @param pos      The source position to be used for
-         *                  error diagnostics.
-         *  @param condtype The type of the expression's condition.
-         *  @param thentype The type of the expression's then-part.
-         *  @param elsetype The type of the expression's else-part.
-         */
-        private Type condType(DiagnosticPosition pos,
-                              Type condtype,
-                              Type thentype,
-                              Type elsetype) {
-            Type ctype = condType1(pos, condtype, thentype, elsetype);
-
-            // If condition and both arms are numeric constants,
-            // evaluate at compile-time.
-            return ((condtype.constValue() != null) &&
-                    (thentype.constValue() != null) &&
-                    (elsetype.constValue() != null))
-                ? cfolder.coerce(condtype.isTrue()?thentype:elsetype, ctype)
-                : ctype;
-        }
-        /** Compute the type of a conditional expression, after
-         *  checking that it exists.  Does not take into
+         *  checking that it exists.  See JLS 15.25. Does not take into
          *  account the special case where condition and both arms
          *  are constants.
          *
          *  @param pos      The source position to be used for error
          *                  diagnostics.
-         *  @param condtype The type of the expression's condition.
          *  @param thentype The type of the expression's then-part.
          *  @param elsetype The type of the expression's else-part.
          */
-        private Type condType1(DiagnosticPosition pos, Type condtype,
+        private Type condType(DiagnosticPosition pos,
                                Type thentype, Type elsetype) {
             // If same type, that is the result
             if (types.isSameType(thentype, elsetype))
@@ -1445,22 +1547,19 @@
     public void visitReturn(JCReturn tree) {
         // Check that there is an enclosing method which is
         // nested within than the enclosing class.
-        if (env.enclMethod == null ||
-            env.enclMethod.sym.owner != env.enclClass.sym) {
+        if (env.info.returnResult == null) {
             log.error(tree.pos(), "ret.outside.meth");
-
         } else {
             // Attribute return expression, if it exists, and check that
             // it conforms to result type of enclosing method.
-            Symbol m = env.enclMethod.sym;
-            if (m.type.getReturnType().tag == VOID) {
-                if (tree.expr != null)
+            if (tree.expr != null) {
+                if (env.info.returnResult.pt.tag == VOID) {
                     log.error(tree.expr.pos(),
                               "cant.ret.val.from.meth.decl.void");
-            } else if (tree.expr == null) {
+                }
+                attribTree(tree.expr, env, env.info.returnResult);
+            } else if (env.info.returnResult.pt.tag != VOID) {
                 log.error(tree.pos(), "missing.ret.val");
-            } else {
-                attribExpr(tree.expr, env, m.type.getReturnType());
             }
         }
         result = null;
@@ -1562,7 +1661,7 @@
                     // current instance (JLS ???).
                     boolean selectSuperPrev = localEnv.info.selectSuper;
                     localEnv.info.selectSuper = true;
-                    localEnv.info.varArgs = false;
+                    localEnv.info.pendingResolutionPhase = null;
                     Symbol sym = rs.resolveConstructor(
                         tree.meth.pos(), localEnv, site, argtypes, typeargtypes);
                     localEnv.info.selectSuper = selectSuperPrev;
@@ -1573,8 +1672,7 @@
                     // ...and check that it is legal in the current context.
                     // (this will also set the tree's type)
                     Type mpt = newMethodTemplate(resultInfo.pt, argtypes, typeargtypes);
-                    checkId(tree.meth, site, sym, localEnv, new ResultInfo(MTH, mpt),
-                            tree.varargsElement != null);
+                    checkId(tree.meth, site, sym, localEnv, new ResultInfo(MTH, mpt));
                 }
                 // Otherwise, `site' is an error type and we do nothing
             }
@@ -1589,8 +1687,8 @@
             // whose formal argument types is exactly the list of actual
             // arguments (this will also set the method symbol).
             Type mpt = newMethodTemplate(resultInfo.pt, argtypes, typeargtypes);
-            localEnv.info.varArgs = false;
-            Type mtype = attribExpr(tree.meth, localEnv, mpt);
+            localEnv.info.pendingResolutionPhase = null;
+            Type mtype = attribTree(tree.meth, localEnv, new ResultInfo(VAL, mpt, resultInfo.checkContext));
 
             // Compute the result type.
             Type restype = mtype.getReturnType();
@@ -1625,7 +1723,7 @@
             // current context.  Also, capture the return type
             result = check(tree, capture(restype), VAL, resultInfo);
 
-            if (localEnv.info.varArgs)
+            if (localEnv.info.lastResolveVarargs())
                 Assert.check(result.isErroneous() || tree.varargsElement != null);
         }
         chk.validate(tree.typeargs, localEnv);
@@ -1652,11 +1750,11 @@
         /** Obtain a method type with given argument types.
          */
         Type newMethodTemplate(Type restype, List<Type> argtypes, List<Type> typeargtypes) {
-            MethodType mt = new MethodType(argtypes, restype, null, syms.methodClass);
+            MethodType mt = new MethodType(argtypes, restype, List.<Type>nil(), syms.methodClass);
             return (typeargtypes == null) ? mt : (Type)new ForAll(typeargtypes, mt);
         }
 
-    public void visitNewClass(JCNewClass tree) {
+    public void visitNewClass(final JCNewClass tree) {
         Type owntype = types.createErrorType(tree.type);
 
         // The local environment of a class creation is
@@ -1729,19 +1827,6 @@
         List<Type> argtypes = attribArgs(tree.args, localEnv);
         List<Type> typeargtypes = attribTypes(tree.typeargs, localEnv);
 
-        if (TreeInfo.isDiamond(tree) && !clazztype.isErroneous()) {
-            Pair<Symbol, Type> diamondResult =
-                    attribDiamond(localEnv, tree, clazztype, argtypes, typeargtypes);
-            tree.clazz.type = types.createErrorType(clazztype);
-            tree.constructor = diamondResult.fst;
-            tree.constructorType = diamondResult.snd;
-            if (!diamondResult.snd.isErroneous()) {
-                tree.clazz.type = clazztype = diamondResult.snd.getReturnType();
-                tree.constructorType = types.createMethodTypeWithReturn(diamondResult.snd, syms.voidType);
-            }
-            clazztype = chk.checkClassType(tree.clazz, tree.clazz.type, true);
-        }
-
         // If we have made no mistakes in the class type...
         if (clazztype.tag == CLASS) {
             // Enums may not be instantiated except implicitly
@@ -1768,18 +1853,57 @@
                 // Error recovery: pretend no arguments were supplied.
                 argtypes = List.nil();
                 typeargtypes = List.nil();
+            } else if (TreeInfo.isDiamond(tree)) {
+                ClassType site = new ClassType(clazztype.getEnclosingType(),
+                            clazztype.tsym.type.getTypeArguments(),
+                            clazztype.tsym);
+
+                Env<AttrContext> diamondEnv = localEnv.dup(tree);
+                diamondEnv.info.selectSuper = cdef != null;
+                diamondEnv.info.pendingResolutionPhase = null;
+
+                //if the type of the instance creation expression is a class type
+                //apply method resolution inference (JLS 15.12.2.7). The return type
+                //of the resolved constructor will be a partially instantiated type
+                Symbol constructor = rs.resolveDiamond(tree.pos(),
+                            diamondEnv,
+                            site,
+                            argtypes,
+                            typeargtypes);
+                tree.constructor = constructor.baseSymbol();
+
+                final TypeSymbol csym = clazztype.tsym;
+                ResultInfo diamondResult = new ResultInfo(MTH, newMethodTemplate(resultInfo.pt, argtypes, typeargtypes), new Check.NestedCheckContext(resultInfo.checkContext) {
+                    @Override
+                    public void report(DiagnosticPosition _unused, JCDiagnostic details) {
+                        enclosingContext.report(tree.clazz,
+                                diags.fragment("cant.apply.diamond.1", diags.fragment("diamond", csym), details));
+                    }
+                });
+                Type constructorType = tree.constructorType = types.createErrorType(clazztype);
+                constructorType = checkId(tree, site,
+                        constructor,
+                        diamondEnv,
+                        diamondResult);
+
+                tree.clazz.type = types.createErrorType(clazztype);
+                if (!constructorType.isErroneous()) {
+                    tree.clazz.type = clazztype = constructorType.getReturnType();
+                    tree.constructorType = types.createMethodTypeWithReturn(constructorType, syms.voidType);
+                }
+                clazztype = chk.checkClassType(tree.clazz, tree.clazz.type, true);
             }
 
             // Resolve the called constructor under the assumption
             // that we are referring to a superclass instance of the
             // current instance (JLS ???).
-            else if (!TreeInfo.isDiamond(tree)) {
+            else {
                 //the following code alters some of the fields in the current
                 //AttrContext - hence, the current context must be dup'ed in
                 //order to avoid downstream failures
                 Env<AttrContext> rsEnv = localEnv.dup(tree);
                 rsEnv.info.selectSuper = cdef != null;
-                rsEnv.info.varArgs = false;
+                rsEnv.info.pendingResolutionPhase = null;
                 tree.constructor = rs.resolveConstructor(
                     tree.pos(), rsEnv, clazztype, argtypes, typeargtypes);
                 if (cdef == null) { //do not check twice!
@@ -1787,42 +1911,11 @@
                             clazztype,
                             tree.constructor,
                             rsEnv,
-                            new ResultInfo(MTH, newMethodTemplate(syms.voidType, argtypes, typeargtypes)),
-                            rsEnv.info.varArgs);
-                    if (rsEnv.info.varArgs)
+                            new ResultInfo(MTH, newMethodTemplate(syms.voidType, argtypes, typeargtypes)));
+                    if (rsEnv.info.lastResolveVarargs())
                         Assert.check(tree.constructorType.isErroneous() || tree.varargsElement != null);
                 }
-                if (tree.def == null &&
-                        !clazztype.isErroneous() &&
-                        clazztype.getTypeArguments().nonEmpty() &&
-                        findDiamonds) {
-                    boolean prevDeferDiags = log.deferDiagnostics;
-                    Queue<JCDiagnostic> prevDeferredDiags = log.deferredDiagnostics;
-                    Type inferred = null;
-                    try {
-                        //disable diamond-related diagnostics
-                        log.deferDiagnostics = true;
-                        log.deferredDiagnostics = ListBuffer.lb();
-                        inferred = attribDiamond(localEnv,
-                                tree,
-                                clazztype,
-                                argtypes,
-                                typeargtypes).snd;
-                    } finally {
-                        log.deferDiagnostics = prevDeferDiags;
-                        log.deferredDiagnostics = prevDeferredDiags;
-                    }
-                    if (!inferred.isErroneous()) {
-                        inferred = inferred.getReturnType();
-                    }
-                    if (inferred != null &&
-                            types.isAssignable(inferred, pt().tag == NONE ? syms.objectType : pt(), Warner.noWarnings)) {
-                        String key = types.isSameType(clazztype, inferred) ?
-                            "diamond.redundant.args" :
-                            "diamond.redundant.args.1";
-                        log.warning(tree.clazz.pos(), key, clazztype, inferred);
-                    }
-                }
+                findDiamondIfNeeded(localEnv, tree, clazztype);
             }
 
             if (cdef != null) {
@@ -1887,8 +1980,7 @@
                     clazztype,
                     tree.constructor,
                     localEnv,
-                    new ResultInfo(VAL, newMethodTemplate(syms.voidType, argtypes, typeargtypes)),
-                    localEnv.info.varArgs);
+                    new ResultInfo(VAL, newMethodTemplate(syms.voidType, argtypes, typeargtypes)));
             }
 
             if (tree.constructor != null && tree.constructor.kind == MTH)
@@ -1897,53 +1989,33 @@
         result = check(tree, owntype, VAL, resultInfo);
         chk.validate(tree.typeargs, localEnv);
     }
-
-    Pair<Symbol, Type> attribDiamond(Env<AttrContext> env,
-                        final JCNewClass tree,
-                        final Type clazztype,
-                        List<Type> argtypes,
-                        List<Type> typeargtypes) {
-        if (clazztype.isErroneous() ||
-                clazztype.isInterface()) {
-            //if the type of the instance creation expression is erroneous,
-            //or if it's an interface, or if something prevented us to form a valid
-            //mapping, return the (possibly erroneous) type unchanged
-            return new Pair<Symbol, Type>(syms.noSymbol, clazztype);
+    //where
+        void findDiamondIfNeeded(Env<AttrContext> env, JCNewClass tree, Type clazztype) {
+            if (tree.def == null &&
+                    !clazztype.isErroneous() &&
+                    clazztype.getTypeArguments().nonEmpty() &&
+                    findDiamonds) {
+                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(VAL,
+                            resultInfo.checkContext.inferenceContext().free(resultInfo.pt) ? Type.noType : pt());
+                    Type inferred = deferredAttr.attribSpeculative(tree, env, findDiamondResult).type;
+                    if (!inferred.isErroneous() &&
+                        types.isAssignable(inferred, pt().tag == NONE ? syms.objectType : pt(), Warner.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;
+                }
+            }
         }
 
-        //dup attribution environment and augment the set of inference variables
-        Env<AttrContext> localEnv = env.dup(tree);
-
-        ClassType site = new ClassType(clazztype.getEnclosingType(),
-                    clazztype.tsym.type.getTypeArguments(),
-                    clazztype.tsym);
-
-        //if the type of the instance creation expression is a class type
-        //apply method resolution inference (JLS 15.12.2.7). The return type
-        //of the resolved constructor will be a partially instantiated type
-        Symbol constructor = rs.resolveDiamond(tree.pos(),
-                    localEnv,
-                    site,
-                    argtypes,
-                    typeargtypes);
-
-        Type constructorType = types.createErrorType(clazztype);
-        ResultInfo diamondResult = new ResultInfo(MTH, newMethodTemplate(resultInfo.pt, argtypes, typeargtypes), new Check.NestedCheckContext(resultInfo.checkContext) {
-            @Override
-            public void report(DiagnosticPosition _unused, JCDiagnostic details) {
-                enclosingContext.report(tree.clazz,
-                        diags.fragment("cant.apply.diamond.1", diags.fragment("diamond", clazztype.tsym), details));
-            }
-        });
-        constructorType = checkId(tree, site,
-                constructor,
-                localEnv,
-                diamondResult,
-                localEnv.info.varArgs);
-
-        return new Pair<Symbol, Type>(constructor.baseSymbol(), constructorType);
-    }
-
     /** Make an attributed null check tree.
      */
     public JCExpression makeNullCheck(JCExpression arg) {
@@ -1960,13 +2032,14 @@
 
     public void visitNewArray(JCNewArray tree) {
         Type owntype = types.createErrorType(tree.type);
+        Env<AttrContext> localEnv = env.dup(tree);
         Type elemtype;
         if (tree.elemtype != null) {
-            elemtype = attribType(tree.elemtype, env);
-            chk.validate(tree.elemtype, env);
+            elemtype = attribType(tree.elemtype, localEnv);
+            chk.validate(tree.elemtype, localEnv);
             owntype = elemtype;
             for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) {
-                attribExpr(l.head, env, syms.intType);
+                attribExpr(l.head, localEnv, syms.intType);
                 owntype = new ArrayType(owntype, syms.arrayClass);
             }
         } else {
@@ -1983,7 +2056,7 @@
             }
         }
         if (tree.elems != null) {
-            attribExprs(tree.elems, env, elemtype);
+            attribExprs(tree.elems, localEnv, elemtype);
             owntype = new ArrayType(elemtype, syms.arrayClass);
         }
         if (!types.isReifiable(elemtype))
@@ -2132,18 +2205,34 @@
         result = check(tree, owntype, VAL, resultInfo);
     }
 
-    public void visitTypeCast(JCTypeCast tree) {
+    public void visitTypeCast(final JCTypeCast tree) {
         Type clazztype = attribType(tree.clazz, env);
         chk.validate(tree.clazz, env, false);
         //a fresh environment is required for 292 inference to work properly ---
         //see Infer.instantiatePolymorphicSignatureInstance()
         Env<AttrContext> localEnv = env.dup(tree);
-        Type exprtype = attribExpr(tree.expr, localEnv, Infer.anyPoly);
-        Type owntype = chk.checkCastable(tree.expr.pos(), exprtype, clazztype);
+        //should we propagate the target type?
+        final ResultInfo castInfo;
+        final boolean isPoly = TreeInfo.isPoly(tree.expr, tree);
+        if (isPoly) {
+            //expression is a poly - we need to propagate target type info
+            castInfo = new ResultInfo(VAL, clazztype, new Check.NestedCheckContext(resultInfo.checkContext) {
+                @Override
+                public boolean compatible(Type found, Type req, Warner warn) {
+                    return types.isCastable(found, req, warn);
+                }
+            });
+        } else {
+            //standalone cast - target-type info is not propagated
+            castInfo = unknownExprInfo;
+        }
+        Type exprtype = attribTree(tree.expr, localEnv, castInfo);
+        Type owntype = isPoly ? clazztype : chk.checkCastable(tree.expr.pos(), exprtype, clazztype);
         if (exprtype.constValue() != null)
             owntype = cfolder.coerce(exprtype, owntype);
         result = check(tree, capture(owntype), VAL, resultInfo);
-        chk.checkRedundantCast(localEnv, tree);
+        if (!isPoly)
+            chk.checkRedundantCast(localEnv, tree);
     }
 
     public void visitTypeTest(JCInstanceOf tree) {
@@ -2170,15 +2259,13 @@
 
     public void visitIdent(JCIdent tree) {
         Symbol sym;
-        boolean varArgs = false;
 
         // Find symbol
         if (pt().tag == METHOD || pt().tag == FORALL) {
             // If we are looking for a method, the prototype `pt' will be a
             // method type with the type of the call's arguments as parameters.
-            env.info.varArgs = false;
+            env.info.pendingResolutionPhase = null;
             sym = rs.resolveMethod(tree.pos(), env, tree.name, pt().getParameterTypes(), pt().getTypeArguments());
-            varArgs = env.info.varArgs;
         } else if (tree.sym != null && tree.sym.kind != VAR) {
             sym = tree.sym;
         } else {
@@ -2240,7 +2327,7 @@
             while (env1.outer != null && !rs.isAccessible(env, env1.enclClass.sym.type, sym))
                 env1 = env1.outer;
         }
-        result = checkId(tree, env1.enclClass.sym.type, sym, env, resultInfo, varArgs);
+        result = checkId(tree, env1.enclClass.sym.type, sym, env, resultInfo);
     }
 
     public void visitSelect(JCFieldAccess tree) {
@@ -2283,13 +2370,13 @@
             sitesym.name == names._super;
 
         // Determine the symbol represented by the selection.
-        env.info.varArgs = false;
+        env.info.pendingResolutionPhase = null;
         Symbol sym = selectSym(tree, sitesym, site, env, resultInfo);
         if (sym.exists() && !isType(sym) && (pkind() & (PCK | TYP)) != 0) {
             site = capture(site);
             sym = selectSym(tree, sitesym, site, env, resultInfo);
         }
-        boolean varArgs = env.info.varArgs;
+        boolean varArgs = env.info.lastResolveVarargs();
         tree.sym = sym;
 
         if (site.tag == TYPEVAR && !isType(sym) && sym.kind != ERR) {
@@ -2340,7 +2427,7 @@
                 if ((sym.flags() & STATIC) == 0 &&
                     sym.name != names._super &&
                     (sym.kind == VAR || sym.kind == MTH)) {
-                    rs.access(rs.new StaticError(sym),
+                    rs.accessBase(rs.new StaticError(sym),
                               tree.pos(), site, sym.name, true);
                 }
             }
@@ -2364,7 +2451,7 @@
         }
 
         env.info.selectSuper = selectSuperPrev;
-        result = checkId(tree, site, sym, env, resultInfo, varArgs);
+        result = checkId(tree, site, sym, env, resultInfo);
     }
     //where
         /** Determine symbol referenced by a Select expression,
@@ -2383,7 +2470,7 @@
             Name name = tree.name;
             switch (site.tag) {
             case PACKAGE:
-                return rs.access(
+                return rs.accessBase(
                     rs.findIdentInPackage(env, site.tsym, name, resultInfo.pkind),
                     pos, location, site, name, true);
             case ARRAY:
@@ -2407,7 +2494,7 @@
                     // We are seeing a plain identifier as selector.
                     Symbol sym = rs.findIdentInType(env, site, name, resultInfo.pkind);
                     if ((resultInfo.pkind & ERRONEOUS) == 0)
-                        sym = rs.access(sym, pos, location, site, name, true);
+                        sym = rs.accessBase(sym, pos, location, site, name, true);
                     return sym;
                 }
             case WILDCARD:
@@ -2429,7 +2516,7 @@
                     Symbol sym2 = (sym.flags() & Flags.PRIVATE) != 0 ?
                         rs.new AccessError(env, site, sym) :
                                 sym;
-                    rs.access(sym2, pos, location, site, name, true);
+                    rs.accessBase(sym2, pos, location, site, name, true);
                     return sym;
                 }
             case ERROR:
@@ -2480,9 +2567,18 @@
                      Type site,
                      Symbol sym,
                      Env<AttrContext> env,
-                     ResultInfo resultInfo,
-                     boolean useVarargs) {
-            if (resultInfo.pt.isErroneous()) return types.createErrorType(site);
+                     ResultInfo resultInfo) {
+            Type pt = resultInfo.pt.tag == FORALL || resultInfo.pt.tag == METHOD ?
+                    resultInfo.pt.map(deferredAttr.new DeferredTypeMap(AttrMode.SPECULATIVE, sym, env.info.pendingResolutionPhase)) :
+                    resultInfo.pt;
+
+            DeferredAttr.DeferredTypeMap recoveryMap =
+                    deferredAttr.new RecoveryDeferredTypeMap(AttrMode.CHECK, sym, env.info.pendingResolutionPhase);
+
+            if (pt.isErroneous()) {
+                Type.map(resultInfo.pt.getParameterTypes(), recoveryMap);
+                return types.createErrorType(site);
+            }
             Type owntype; // The computed type of this identifier occurrence.
             switch (sym.kind) {
             case TYP:
@@ -2560,10 +2656,11 @@
                 owntype = checkMethod(site, sym,
                         new ResultInfo(VAL, resultInfo.pt.getReturnType(), resultInfo.checkContext),
                         env, TreeInfo.args(env.tree), resultInfo.pt.getParameterTypes(),
-                        resultInfo.pt.getTypeArguments(), env.info.varArgs);
+                        resultInfo.pt.getTypeArguments());
                 break;
             }
             case PCK: case ERR:
+                Type.map(resultInfo.pt.getParameterTypes(), recoveryMap);
                 owntype = sym.type;
                 break;
             default:
@@ -2703,8 +2800,7 @@
                             Env<AttrContext> env,
                             final List<JCExpression> argtrees,
                             List<Type> argtypes,
-                            List<Type> typeargtypes,
-                            boolean useVarargs) {
+                            List<Type> typeargtypes) {
         // Test (5): if symbol is an instance method of a raw type, issue
         // an unchecked warning if its argument types change under erasure.
         if (allowGenerics &&
@@ -2726,18 +2822,16 @@
         // any type arguments and value arguments.
         noteWarner.clear();
         try {
-            Type owntype = rs.rawInstantiate(
+            Type owntype = rs.checkMethod(
                     env,
                     site,
                     sym,
                     resultInfo,
                     argtypes,
                     typeargtypes,
-                    allowBoxing,
-                    useVarargs,
                     noteWarner);
 
-            return chk.checkMethod(owntype, sym, env, argtrees, argtypes, useVarargs,
+            return chk.checkMethod(owntype, sym, env, argtrees, argtypes, env.info.lastResolveVarargs(),
                     noteWarner.hasNonSilentLint(LintCategory.UNCHECKED));
         } catch (Infer.InferenceException ex) {
             //invalid target type - propagate exception outwards or report error
@@ -2745,7 +2839,7 @@
             resultInfo.checkContext.report(env.tree.pos(), ex.getDiagnostic());
             return types.createErrorType(site);
         } catch (Resolve.InapplicableMethodException ex) {
-            Assert.error();
+            Assert.error(ex.getDiagnostic().getMessage(Locale.getDefault()));
             return null;
         }
     }
@@ -3053,8 +3147,10 @@
 
             Lint prevLint = chk.setLint(env.info.lint);
             JavaFileObject prev = log.useSource(c.sourcefile);
+            ResultInfo prevReturnRes = env.info.returnResult;
 
             try {
+                env.info.returnResult = null;
                 // java.lang.Enum may not be subclassed by a non-enum
                 if (st.tsym == syms.enumSym &&
                     ((c.flags_field & (Flags.ENUM|Flags.COMPOUND)) == 0))
@@ -3071,6 +3167,7 @@
 
                 chk.checkDeprecatedAnnotation(env.tree.pos(), c);
             } finally {
+                env.info.returnResult = prevReturnRes;
                 log.useSource(prev);
                 chk.setLint(prevLint);
             }
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/AttrContext.java	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/AttrContext.java	Thu Oct 04 13:04:53 2012 +0100
@@ -56,7 +56,7 @@
 
     /** Are arguments to current function applications boxed into an array for varargs?
      */
-    boolean varArgs = false;
+    Resolve.MethodResolutionPhase pendingResolutionPhase = null;
 
     /** A record of the lint/SuppressWarnings currently in effect
      */
@@ -67,6 +67,11 @@
      */
     Symbol enclVar = null;
 
+    /** ResultInfo to be used for attributing 'return' statement expressions
+     * (set by Attr.visitMethod and Attr.visitLambda)
+     */
+    Attr.ResultInfo returnResult = null;
+
     /** Duplicate this context, replacing scope field and copying all others.
      */
     AttrContext dup(Scope scope) {
@@ -75,9 +80,10 @@
         info.staticLevel = staticLevel;
         info.isSelfCall = isSelfCall;
         info.selectSuper = selectSuper;
-        info.varArgs = varArgs;
+        info.pendingResolutionPhase = pendingResolutionPhase;
         info.lint = lint;
         info.enclVar = enclVar;
+        info.returnResult = returnResult;
         return info;
     }
 
@@ -93,6 +99,11 @@
         return scope.getElements();
     }
 
+    boolean lastResolveVarargs() {
+        return pendingResolutionPhase != null &&
+                pendingResolutionPhase.isVarargsRequired();
+    }
+
     public String toString() {
         return "AttrContext[" + scope.toString() + "]";
     }
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Thu Oct 04 13:04:53 2012 +0100
@@ -40,6 +40,7 @@
 import com.sun.tools.javac.code.Lint.LintCategory;
 import com.sun.tools.javac.code.Type.*;
 import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext;
 import com.sun.tools.javac.comp.Infer.InferenceContext;
 import com.sun.tools.javac.comp.Infer.InferenceContext.FreeTypeListener;
 
@@ -68,6 +69,7 @@
     private final Resolve rs;
     private final Symtab syms;
     private final Enter enter;
+    private final DeferredAttr deferredAttr;
     private final Infer infer;
     private final Types types;
     private final JCDiagnostic.Factory diags;
@@ -100,6 +102,7 @@
         rs = Resolve.instance(context);
         syms = Symtab.instance(context);
         enter = Enter.instance(context);
+        deferredAttr = DeferredAttr.instance(context);
         infer = Infer.instance(context);
         this.types = Types.instance(context);
         diags = JCDiagnostic.Factory.instance(context);
@@ -433,6 +436,8 @@
         public Warner checkWarner(DiagnosticPosition pos, Type found, Type req);
 
         public Infer.InferenceContext inferenceContext();
+
+        public DeferredAttr.DeferredAttrContext deferredAttrContext();
     }
 
     /**
@@ -463,6 +468,10 @@
         public Infer.InferenceContext inferenceContext() {
             return enclosingContext.inferenceContext();
         }
+
+        public DeferredAttrContext deferredAttrContext() {
+            return enclosingContext.deferredAttrContext();
+        }
     }
 
     /**
@@ -483,6 +492,10 @@
         public InferenceContext inferenceContext() {
             return infer.emptyContext;
         }
+
+        public DeferredAttrContext deferredAttrContext() {
+            return deferredAttr.emptyDeferredAttrContext;
+        }
     };
 
     /** Check that a given type is assignable to a given proto-type.
@@ -817,6 +830,8 @@
                 sym.owner == syms.enumSym)
                 formals = formals.tail.tail;
         List<JCExpression> args = argtrees;
+        DeferredAttr.DeferredTypeMap checkDeferredMap =
+                deferredAttr.new DeferredTypeMap(DeferredAttr.AttrMode.CHECK, sym, env.info.pendingResolutionPhase);
         while (formals.head != last) {
             JCTree arg = args.head;
             Warner warn = convertWarner(arg.pos(), arg.type, formals.head);
@@ -835,7 +850,7 @@
         } else if ((sym.flags() & VARARGS) != 0 && allowVarargs) {
             // non-varargs call to varargs method
             Type varParam = owntype.getParameterTypes().last();
-            Type lastArg = argtypes.last();
+            Type lastArg = checkDeferredMap.apply(argtypes.last());
             if (types.isSubtypeUnchecked(lastArg, types.elemtype(varParam)) &&
                     !types.isSameType(types.erasure(varParam), types.erasure(lastArg)))
                 log.warning(argtrees.last().pos(), "inexact.non-varargs.call",
@@ -847,7 +862,7 @@
                     kindName(sym),
                     sym.name,
                     rs.methodArguments(sym.type.getParameterTypes()),
-                    rs.methodArguments(argtypes),
+                    rs.methodArguments(Type.map(argtypes, checkDeferredMap)),
                     kindName(sym.location()),
                     sym.location());
            owntype = new MethodType(owntype.getParameterTypes(),
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Thu Oct 04 13:04:53 2012 +0100
@@ -0,0 +1,553 @@
+/*
+ * Copyright (c) 2012, 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.tools.javac.code.*;
+import com.sun.tools.javac.tree.*;
+import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.code.Type.*;
+import com.sun.tools.javac.comp.Attr.ResultInfo;
+import com.sun.tools.javac.comp.Infer.InferenceContext;
+import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
+import com.sun.tools.javac.tree.JCTree.*;
+
+import javax.tools.JavaFileObject;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import static com.sun.tools.javac.code.TypeTags.*;
+import static com.sun.tools.javac.tree.JCTree.Tag.*;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+
+/**
+ * This is an helper class that is used to perform deferred type-analysis.
+ * Each time a poly expression occurs in argument position, javac attributes it
+ * with a temporary 'deferred type' that is checked (possibly multiple times)
+ * against an expected formal type.
+ *
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public class DeferredAttr extends JCTree.Visitor {
+    protected static final Context.Key<DeferredAttr> deferredAttrKey =
+        new Context.Key<DeferredAttr>();
+
+    final Attr attr;
+    final Check chk;
+    final Enter enter;
+    final Infer infer;
+    final Log log;
+    final Symtab syms;
+    final TreeMaker make;
+    final Types types;
+
+    public static DeferredAttr instance(Context context) {
+        DeferredAttr instance = context.get(deferredAttrKey);
+        if (instance == null)
+            instance = new DeferredAttr(context);
+        return instance;
+    }
+
+    protected DeferredAttr(Context context) {
+        context.put(deferredAttrKey, this);
+        attr = Attr.instance(context);
+        chk = Check.instance(context);
+        enter = Enter.instance(context);
+        infer = Infer.instance(context);
+        log = Log.instance(context);
+        syms = Symtab.instance(context);
+        make = TreeMaker.instance(context);
+        types = Types.instance(context);
+    }
+
+    /**
+     * This type represents a deferred type. A deferred type starts off with
+     * no information on the underlying expression type. Such info needs to be
+     * discovered through type-checking the deferred type against a target-type.
+     * Every deferred type keeps a pointer to the AST node from which it originated.
+     */
+    public class DeferredType extends Type {
+
+        public JCExpression tree;
+        Env<AttrContext> env;
+        AttrMode mode;
+        SpeculativeCache speculativeCache;
+
+        DeferredType(JCExpression tree, Env<AttrContext> env) {
+            super(DEFERRED, null);
+            this.tree = tree;
+            this.env = env.dup(tree, env.info.dup());
+            this.speculativeCache = new SpeculativeCache();
+        }
+
+        /**
+         * A speculative cache is used to keep track of all overload resolution rounds
+         * that triggered speculative attribution on a given deferred type. Each entry
+         * stores a pointer to the speculative tree and the resolution phase in which the entry
+         * has been added.
+         */
+        class SpeculativeCache {
+
+            private Map<Symbol, List<Entry>> cache =
+                    new WeakHashMap<Symbol, List<Entry>>();
+
+            class Entry {
+                JCTree speculativeTree;
+                Resolve.MethodResolutionPhase phase;
+
+                public Entry(JCTree speculativeTree, MethodResolutionPhase phase) {
+                    this.speculativeTree = speculativeTree;
+                    this.phase = phase;
+                }
+
+                boolean matches(Resolve.MethodResolutionPhase phase) {
+                    return this.phase == phase;
+                }
+            }
+
+            /**
+             * Clone a speculative cache entry as a fresh entry associated
+             * with a new method (this maybe required to fixup speculative cache
+             * misses after Resolve.access())
+             */
+            void dupAllTo(Symbol from, Symbol to) {
+                Assert.check(cache.get(to) == null);
+                List<Entry> entries = cache.get(from);
+                if (entries != null) {
+                    cache.put(to, entries);
+                }
+            }
+
+            /**
+             * Retrieve a speculative cache entry corresponding to given symbol
+             * and resolution phase
+             */
+            Entry get(Symbol msym, MethodResolutionPhase phase) {
+                List<Entry> entries = cache.get(msym);
+                if (entries == null) return null;
+                for (Entry e : entries) {
+                    if (e.matches(phase)) return e;
+                }
+                return null;
+            }
+
+            /**
+             * Stores a speculative cache entry corresponding to given symbol
+             * and resolution phase
+             */
+            void put(Symbol msym, JCTree speculativeTree, MethodResolutionPhase phase) {
+                List<Entry> entries = cache.get(msym);
+                if (entries == null) {
+                    entries = List.nil();
+                }
+                cache.put(msym, entries.prepend(new Entry(speculativeTree, phase)));
+            }
+        }
+
+        /**
+         * Get the type that has been computed during a speculative attribution round
+         */
+        Type speculativeType(Symbol msym, MethodResolutionPhase phase) {
+            SpeculativeCache.Entry e = speculativeCache.get(msym, phase);
+            return e != null ? e.speculativeTree.type : Type.noType;
+        }
+
+        /**
+         * Check a deferred type against a potential target-type. Depending on
+         * the current attribution mode, a normal vs. speculative attribution
+         * round is performed on the underlying AST node. There can be only one
+         * speculative round for a given target method symbol; moreover, a normal
+         * attribution round must follow one or more speculative rounds.
+         */
+        Type check(ResultInfo resultInfo) {
+            DeferredAttrContext deferredAttrContext =
+                    resultInfo.checkContext.deferredAttrContext();
+            Assert.check(deferredAttrContext != emptyDeferredAttrContext);
+            List<Type> stuckVars = stuckVars(tree, resultInfo);
+            if (stuckVars.nonEmpty()) {
+                deferredAttrContext.addDeferredAttrNode(this, resultInfo, stuckVars);
+                return Type.noType;
+            } else {
+                try {
+                    switch (deferredAttrContext.mode) {
+                        case SPECULATIVE:
+                            Assert.check(mode == null ||
+                                    (mode == AttrMode.SPECULATIVE &&
+                                    speculativeType(deferredAttrContext.msym, deferredAttrContext.phase).tag == NONE));
+                            JCTree speculativeTree = attribSpeculative(tree, env, resultInfo);
+                            speculativeCache.put(deferredAttrContext.msym, speculativeTree, deferredAttrContext.phase);
+                            return speculativeTree.type;
+                        case CHECK:
+                            Assert.check(mode == AttrMode.SPECULATIVE);
+                            return attr.attribTree(tree, env, resultInfo);
+                    }
+                    Assert.error();
+                    return null;
+                } finally {
+                    mode = deferredAttrContext.mode;
+                }
+            }
+        }
+    }
+
+    /**
+     * The 'mode' in which the deferred type is to be type-checked
+     */
+    public enum AttrMode {
+        /**
+         * A speculative type-checking round is used during overload resolution
+         * mainly to generate constraints on inference variables. Side-effects
+         * arising from type-checking the expression associated with the deferred
+         * type are reversed after the speculative round finishes. This means the
+         * expression tree will be left in a blank state.
+         */
+        SPECULATIVE,
+        /**
+         * This is the plain type-checking mode. Produces side-effects on the underlying AST node
+         */
+        CHECK;
+    }
+
+    /**
+     * Routine that performs speculative type-checking; the input AST node is
+     * cloned (to avoid side-effects cause by Attr) and compiler state is
+     * restored after type-checking. All diagnostics (but critical ones) are
+     * disabled during speculative type-checking.
+     */
+    JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
+        JCTree newTree = new TreeCopier<Object>(make).copy(tree);
+        Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared()));
+        speculativeEnv.info.scope.owner = env.info.scope.owner;
+        Filter<JCDiagnostic> prevDeferDiagsFilter = log.deferredDiagFilter;
+        Queue<JCDiagnostic> prevDeferredDiags = log.deferredDiagnostics;
+        final JavaFileObject currentSource = log.currentSourceFile();
+        try {
+            log.deferredDiagnostics = new ListBuffer<JCDiagnostic>();
+            log.deferredDiagFilter = new Filter<JCDiagnostic>() {
+                public boolean accepts(JCDiagnostic t) {
+                    return t.getDiagnosticSource().getFile().equals(currentSource);
+                }
+            };
+            attr.attribTree(newTree, speculativeEnv, resultInfo);
+            unenterScanner.scan(newTree);
+            return newTree;
+        } catch (Abort ex) {
+            //if some very bad condition occurred during deferred attribution
+            //we should dump all errors before killing javac
+            log.reportDeferredDiagnostics();
+            throw ex;
+        } finally {
+            unenterScanner.scan(newTree);
+            log.deferredDiagFilter = prevDeferDiagsFilter;
+            log.deferredDiagnostics = prevDeferredDiags;
+        }
+    }
+    //where
+        protected TreeScanner unenterScanner = new TreeScanner() {
+            @Override
+            public void visitClassDef(JCClassDecl tree) {
+                ClassSymbol csym = tree.sym;
+                enter.typeEnvs.remove(csym);
+                chk.compiled.remove(csym.flatname);
+                syms.classes.remove(csym.flatname);
+                super.visitClassDef(tree);
+            }
+        };
+
+    /**
+     * 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
+     * the symbol of the method being checked, the overload resolution phase,
+     * the kind of attribution mode to be applied to deferred types and so forth.
+     * As deferred types are processed (by the method check routine) stuck AST nodes
+     * are added (as new deferred attribution nodes) to this context. The complete()
+     * routine makes sure that all pending nodes are properly processed, by
+     * progressively instantiating all inference variables on which one or more
+     * deferred attribution node is stuck.
+     */
+    class DeferredAttrContext {
+
+        /** attribution mode */
+        final AttrMode mode;
+
+        /** symbol of the method being checked */
+        final Symbol msym;
+
+        /** method resolution step */
+        final Resolve.MethodResolutionPhase phase;
+
+        /** inference context */
+        final InferenceContext inferenceContext;
+
+        /** list of deferred attribution nodes to be processed */
+        ArrayList<DeferredAttrNode> deferredAttrNodes = new ArrayList<DeferredAttrNode>();
+
+        DeferredAttrContext(AttrMode mode, Symbol msym, MethodResolutionPhase phase, InferenceContext inferenceContext) {
+            this.mode = mode;
+            this.msym = msym;
+            this.phase = phase;
+            this.inferenceContext = inferenceContext;
+        }
+
+        /**
+         * Adds a node to the list of deferred attribution nodes - used by Resolve.rawCheckArgumentsApplicable
+         * Nodes added this way act as 'roots' for the out-of-order method checking process.
+         */
+        void addDeferredAttrNode(final DeferredType dt, ResultInfo resultInfo, List<Type> stuckVars) {
+            deferredAttrNodes.add(new DeferredAttrNode(dt, resultInfo, stuckVars));
+        }
+
+        /**
+         * Incrementally process all nodes, by skipping 'stuck' nodes and attributing
+         * 'unstuck' ones. If at any point no progress can be made (no 'unstuck' nodes)
+         * some inference variable might get eagerly instantiated so that all nodes
+         * can be type-checked.
+         */
+        void complete() {
+            while (!deferredAttrNodes.isEmpty()) {
+                Set<Type> stuckVars = new HashSet<Type>();
+                boolean progress = false;
+                //scan a defensive copy of the node list - this is because a deferred
+                //attribution round can add new nodes to the list
+                for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) {
+                    if (!deferredAttrNode.isStuck()) {
+                        deferredAttrNode.process();
+                        deferredAttrNodes.remove(deferredAttrNode);
+                        progress = true;
+                    } else {
+                        stuckVars.addAll(deferredAttrNode.stuckVars);
+                    }
+                }
+                if (!progress) {
+                    //remove all variables that have already been instantiated
+                    //from the list of stuck variables
+                    inferenceContext.solveAny(inferenceContext.freeVarsIn(List.from(stuckVars)), types, infer);
+                    inferenceContext.notifyChange(types);
+                }
+            }
+        }
+
+        /**
+         * Class representing a deferred attribution node. It keeps track of
+         * a deferred type, along with the expected target type information.
+         */
+        class DeferredAttrNode implements Infer.InferenceContext.FreeTypeListener {
+
+            /** underlying deferred type */
+            DeferredType dt;
+
+            /** underlying target type information */
+            ResultInfo resultInfo;
+
+            /** list of uninferred inference variables causing this node to be stuck */
+            List<Type> stuckVars;
+
+            DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, List<Type> stuckVars) {
+                this.dt = dt;
+                this.resultInfo = resultInfo;
+                this.stuckVars = stuckVars;
+                if (!stuckVars.isEmpty()) {
+                    resultInfo.checkContext.inferenceContext().addFreeTypeListener(stuckVars, this);
+                }
+            }
+
+            @Override
+            public void typesInferred(InferenceContext inferenceContext) {
+                stuckVars = List.nil();
+                resultInfo = resultInfo.dup(inferenceContext.asInstType(resultInfo.pt, types));
+            }
+
+            /**
+             * is this node stuck?
+             */
+            boolean isStuck() {
+                return stuckVars.nonEmpty();
+            }
+
+            /**
+             * Process a deferred attribution node.
+             * Invariant: a stuck node cannot be processed.
+             */
+            void process() {
+                if (isStuck()) {
+                    throw new IllegalStateException("Cannot process a stuck deferred node");
+                }
+                dt.check(resultInfo);
+            }
+        }
+    }
+
+    /** an empty deferred attribution context - all methods throw exceptions */
+    final DeferredAttrContext emptyDeferredAttrContext =
+            new DeferredAttrContext(null, null, null, null) {
+                @Override
+                void addDeferredAttrNode(DeferredType dt, ResultInfo ri, List<Type> stuckVars) {
+                    Assert.error("Empty deferred context!");
+                }
+                @Override
+                void complete() {
+                    Assert.error("Empty deferred context!");
+                }
+            };
+
+    /**
+     * Map a list of types possibly containing one or more deferred types
+     * into a list of ordinary types. Each deferred type D is mapped into a type T,
+     * where T is computed by retrieving the type that has already been
+     * computed for D during a previous deferred attribution round of the given kind.
+     */
+    class DeferredTypeMap extends Type.Mapping {
+
+        DeferredAttrContext deferredAttrContext;
+
+        protected DeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
+            super(String.format("deferredTypeMap[%s]", mode));
+            this.deferredAttrContext = new DeferredAttrContext(mode, msym, phase, infer.emptyContext);
+        }
+
+        protected boolean validState(DeferredType dt) {
+            return dt.mode != null &&
+                    deferredAttrContext.mode.ordinal() <= dt.mode.ordinal();
+        }
+
+        @Override
+        public Type apply(Type t) {
+            if (t.tag != DEFERRED) {
+                return t.map(this);
+            } else {
+                DeferredType dt = (DeferredType)t;
+                Assert.check(validState(dt));
+                return typeOf(dt);
+            }
+        }
+
+        protected Type typeOf(DeferredType dt) {
+            switch (deferredAttrContext.mode) {
+                case CHECK:
+                    return dt.tree.type == null ? Type.noType : dt.tree.type;
+                case SPECULATIVE:
+                    return dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase);
+            }
+            Assert.error();
+            return null;
+        }
+    }
+
+    /**
+     * Specialized recovery deferred mapping.
+     * Each deferred type D is mapped into a type T, where T is computed either by
+     * (i) retrieving the type that has already been computed for D during a previous
+     * attribution round (as before), or (ii) by synthesizing a new type R for D
+     * (the latter step is useful in a recovery scenario).
+     */
+    public class RecoveryDeferredTypeMap extends DeferredTypeMap {
+
+        public RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
+            super(mode, msym, phase);
+        }
+
+        @Override
+        protected Type typeOf(DeferredType dt) {
+            Type owntype = super.typeOf(dt);
+            return owntype.tag == NONE ?
+                        recover(dt) : owntype;
+        }
+
+        @Override
+        protected boolean validState(DeferredType dt) {
+            return true;
+        }
+
+        /**
+         * Synthesize a type for a deferred type that hasn't been previously
+         * reduced to an ordinary type. Functional deferred types and conditionals
+         * are mapped to themselves, in order to have a richer diagnostic
+         * representation. Remaining deferred types are attributed using
+         * a default expected type (j.l.Object).
+         */
+        private Type recover(DeferredType dt) {
+            dt.check(new RecoveryInfo());
+            switch (TreeInfo.skipParens(dt.tree).getTag()) {
+                case LAMBDA:
+                case REFERENCE:
+                case CONDEXPR:
+                    //propagate those deferred types to the
+                    //diagnostic formatter
+                    return dt;
+                default:
+                    return super.apply(dt);
+            }
+        }
+
+        class RecoveryInfo extends ResultInfo {
+
+            public RecoveryInfo() {
+                attr.super(Kinds.VAL, Type.recoveryType, new Check.NestedCheckContext(chk.basicHandler) {
+                    @Override
+                    public DeferredAttrContext deferredAttrContext() {
+                        return deferredAttrContext;
+                    }
+                    @Override
+                    public boolean compatible(Type found, Type req, Warner warn) {
+                        return true;
+                    }
+                    @Override
+                    public void report(DiagnosticPosition pos, JCDiagnostic details) {
+                        //do nothing
+                    }
+                });
+            }
+
+            @Override
+            protected Type check(DiagnosticPosition pos, Type found) {
+                return chk.checkNonVoid(pos, super.check(pos, found));
+            }
+        }
+    }
+
+    /**
+     * Retrieves the list of inference variables that need to be inferred before
+     * an AST node can be type-checked
+     */
+    @SuppressWarnings("fallthrough")
+    List<Type> stuckVars(JCExpression tree, ResultInfo resultInfo) {
+        switch (tree.getTag()) {
+            case LAMBDA:
+            case REFERENCE:
+                Assert.error("not supported yet");
+            default:
+                return List.nil();
+        }
+    }
+}
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java	Thu Oct 04 13:04:53 2012 +0100
@@ -29,6 +29,7 @@
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.Type.*;
 import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
+import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
 import com.sun.tools.javac.comp.Resolve.InapplicableMethodException;
 import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode;
 import com.sun.tools.javac.tree.JCTree;
@@ -62,6 +63,7 @@
     Types types;
     Check chk;
     Resolve rs;
+    DeferredAttr deferredAttr;
     Log log;
     JCDiagnostic.Factory diags;
 
@@ -77,6 +79,7 @@
         syms = Symtab.instance(context);
         types = Types.instance(context);
         rs = Resolve.instance(context);
+        deferredAttr = DeferredAttr.instance(context);
         log = Log.instance(context);
         chk = Check.instance(context);
         diags = JCDiagnostic.Factory.instance(context);
@@ -187,7 +190,7 @@
             Attr.ResultInfo resultInfo,
             Warner warn) throws InferenceException {
         Type to = resultInfo.pt;
-        if (to.tag == NONE) {
+        if (to.tag == NONE || resultInfo.checkContext.inferenceContext().free(resultInfo.pt)) {
             to = mtype.getReturnType().tag <= VOID ?
                     mtype.getReturnType() : syms.objectType;
         }
@@ -268,14 +271,16 @@
                                   List<Type> argtypes,
                                   boolean allowBoxing,
                                   boolean useVarargs,
+                                  Resolve.MethodResolutionContext resolveContext,
                                   Warner warn) throws InferenceException {
         //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
         final InferenceContext inferenceContext = new InferenceContext(tvars, this);
         inferenceException.clear();
 
         try {
-            rs.checkRawArgumentsAcceptable(env, inferenceContext, argtypes, mt.getParameterTypes(),
-                    allowBoxing, useVarargs, warn, new InferenceCheckHandler(inferenceContext));
+            rs.checkRawArgumentsAcceptable(env, msym, resolveContext.attrMode(), inferenceContext,
+                    argtypes, mt.getParameterTypes(), allowBoxing, useVarargs, warn,
+                    new InferenceCheckHandler(inferenceContext));
 
             // minimize as yet undetermined type variables
             for (Type t : inferenceContext.undetvars) {
@@ -469,6 +474,7 @@
      */
     Type instantiatePolymorphicSignatureInstance(Env<AttrContext> env,
                                             MethodSymbol spMethod,  // sig. poly. method or null if none
+                                            Resolve.MethodResolutionContext resolveContext,
                                             List<Type> argtypes) {
         final Type restype;
 
@@ -498,7 +504,7 @@
                 restype = syms.objectType;
         }
 
-        List<Type> paramtypes = Type.map(argtypes, implicitArgType);
+        List<Type> paramtypes = Type.map(argtypes, new ImplicitArgType(spMethod, resolveContext.step));
         List<Type> exType = spMethod != null ?
             spMethod.getThrownTypes() :
             List.of(syms.throwableType); // make it throw all exceptions
@@ -510,16 +516,21 @@
         return mtype;
     }
     //where
-        Mapping implicitArgType = new Mapping ("implicitArgType") {
-                public Type apply(Type t) {
-                    t = types.erasure(t);
-                    if (t.tag == BOT)
-                        // nulls type as the marker type Null (which has no instances)
-                        // infer as java.lang.Void for now
-                        t = types.boxedClass(syms.voidType).type;
-                    return t;
-                }
-        };
+        class ImplicitArgType extends DeferredAttr.DeferredTypeMap {
+
+            public ImplicitArgType(Symbol msym, Resolve.MethodResolutionPhase phase) {
+                deferredAttr.super(AttrMode.SPECULATIVE, msym, phase);
+            }
+
+            public Type apply(Type t) {
+                t = types.erasure(super.apply(t));
+                if (t.tag == BOT)
+                    // nulls type as the marker type Null (which has no instances)
+                    // infer as java.lang.Void for now
+                    t = types.boxedClass(syms.voidType).type;
+                return t;
+            }
+        }
 
     /**
      * Mapping that turns inference variables into undet vars
@@ -708,6 +719,22 @@
                 throw thrownEx;
             }
         }
+
+        void solveAny(List<Type> varsToSolve, Types types, Infer infer) {
+            boolean progress = false;
+            for (Type t : varsToSolve) {
+                UndetVar uv = (UndetVar)asFree(t, types);
+                if (uv.inst == null) {
+                    infer.minimizeInst(uv, Warner.noWarnings);
+                    if (uv.inst != null) {
+                        progress = true;
+                    }
+                }
+            }
+            if (!progress) {
+                throw infer.inferenceException.setMessage("cyclic.inference", varsToSolve);
+            }
+        }
     }
 
     final InferenceContext emptyContext = new InferenceContext(List.<Type>nil(), this);
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java	Thu Oct 04 13:04:53 2012 +0100
@@ -1998,7 +1998,7 @@
             // replace with <BoxedClass>.TYPE
             ClassSymbol c = types.boxedClass(type);
             Symbol typeSym =
-                rs.access(
+                rs.accessBase(
                     rs.findIdentInType(attrEnv, c.type, names.TYPE, VAR),
                     pos, c.type, names.TYPE, true);
             if (typeSym.kind == VAR)
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Thu Oct 04 13:04:53 2012 +0100
@@ -604,6 +604,10 @@
             env.dup(tree, env.info.dup(env.info.scope.dupUnshared()));
         localEnv.enclMethod = tree;
         localEnv.info.scope.owner = tree.sym;
+        if (tree.sym.type != null) {
+            //when this is called in the enter stage, there's no type to be set
+            localEnv.info.returnResult = attr.new ResultInfo(VAL, tree.sym.type.getReturnType());
+        }
         if ((tree.mods.flags & STATIC) != 0) localEnv.info.staticLevel++;
         return localEnv;
     }
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Thu Oct 04 13:04:53 2012 +0100
@@ -31,6 +31,9 @@
 import com.sun.tools.javac.code.Type.*;
 import com.sun.tools.javac.comp.Attr.ResultInfo;
 import com.sun.tools.javac.comp.Check.CheckContext;
+import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
+import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext;
+import com.sun.tools.javac.comp.DeferredAttr.DeferredType;
 import com.sun.tools.javac.comp.Infer.InferenceContext;
 import com.sun.tools.javac.comp.Infer.InferenceContext.FreeTypeListener;
 import com.sun.tools.javac.comp.Resolve.MethodResolutionContext.Candidate;
@@ -42,15 +45,12 @@
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.EnumMap;
 import java.util.EnumSet;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.Set;
 
 import javax.lang.model.element.ElementVisitor;
 
@@ -77,6 +77,7 @@
     Log log;
     Symtab syms;
     Attr attr;
+    DeferredAttr deferredAttr;
     Check chk;
     Infer infer;
     ClassReader reader;
@@ -109,6 +110,7 @@
         names = Names.instance(context);
         log = Log.instance(context);
         attr = Attr.instance(context);
+        deferredAttr = DeferredAttr.instance(context);
         chk = Check.instance(context);
         infer = Infer.instance(context);
         reader = ClassReader.instance(context);
@@ -219,9 +221,12 @@
             }
         }
         String key = success ? "verbose.resolve.multi" : "verbose.resolve.multi.1";
+        List<Type> argtypes2 = Type.map(argtypes,
+                    deferredAttr.new RecoveryDeferredTypeMap(AttrMode.SPECULATIVE, bestSoFar, currentResolutionContext.step));
         JCDiagnostic main = diags.note(log.currentSource(), dpos, key, name,
                 site.tsym, mostSpecificPos, currentResolutionContext.step,
-                methodArguments(argtypes), methodArguments(typeargtypes));
+                methodArguments(argtypes2),
+                methodArguments(typeargtypes));
         JCDiagnostic d = new JCDiagnostic.MultilineDiagnostic(main, subDiags.toList());
         log.report(d);
     }
@@ -501,13 +506,34 @@
                                     argtypes,
                                     allowBoxing,
                                     useVarargs,
+                                    currentResolutionContext,
                                     warn);
 
-        checkRawArgumentsAcceptable(env, argtypes, mt.getParameterTypes(),
+        checkRawArgumentsAcceptable(env, m, argtypes, mt.getParameterTypes(),
                                 allowBoxing, useVarargs, warn);
         return mt;
     }
 
+    Type checkMethod(Env<AttrContext> env,
+                     Type site,
+                     Symbol m,
+                     ResultInfo resultInfo,
+                     List<Type> argtypes,
+                     List<Type> typeargtypes,
+                     Warner warn) {
+        MethodResolutionContext prevContext = currentResolutionContext;
+        try {
+            currentResolutionContext = new MethodResolutionContext();
+            currentResolutionContext.attrMode = DeferredAttr.AttrMode.CHECK;
+            MethodResolutionPhase step = currentResolutionContext.step = env.info.pendingResolutionPhase;
+            return rawInstantiate(env, site, m, resultInfo, argtypes, typeargtypes,
+                    step.isBoxingRequired(), step.isVarargsRequired(), warn);
+        }
+        finally {
+            currentResolutionContext = prevContext;
+        }
+    }
+
     /** Same but returns null instead throwing a NoInstanceException
      */
     Type instantiate(Env<AttrContext> env,
@@ -530,13 +556,14 @@
     /** Check if a parameter list accepts a list of args.
      */
     boolean argumentsAcceptable(Env<AttrContext> env,
+                                Symbol msym,
                                 List<Type> argtypes,
                                 List<Type> formals,
                                 boolean allowBoxing,
                                 boolean useVarargs,
                                 Warner warn) {
         try {
-            checkRawArgumentsAcceptable(env, argtypes, formals, allowBoxing, useVarargs, warn);
+            checkRawArgumentsAcceptable(env, msym, argtypes, formals, allowBoxing, useVarargs, warn);
             return true;
         } catch (InapplicableMethodException ex) {
             return false;
@@ -583,12 +610,13 @@
     };
 
     void checkRawArgumentsAcceptable(Env<AttrContext> env,
+                                Symbol msym,
                                 List<Type> argtypes,
                                 List<Type> formals,
                                 boolean allowBoxing,
                                 boolean useVarargs,
                                 Warner warn) {
-        checkRawArgumentsAcceptable(env, infer.emptyContext, argtypes, formals,
+        checkRawArgumentsAcceptable(env, msym, currentResolutionContext.attrMode(), infer.emptyContext, argtypes, formals,
                 allowBoxing, useVarargs, warn, resolveHandler);
     }
 
@@ -598,35 +626,41 @@
      * compatible (by method invocation conversion) with the types in F.
      *
      * Since this routine is shared between overload resolution and method
-     * type-inference, it is crucial that actual types are converted to the
-     * corresponding 'undet' form (i.e. where inference variables are replaced
-     * with undetvars) so that constraints can be propagated and collected.
+     * type-inference, a (possibly empty) inference context is used to convert
+     * formal types to the corresponding 'undet' form ahead of a compatibility
+     * check so that constraints can be propagated and collected.
      *
-     * Moreover, if one or more types in A is a poly type, this routine calls
-     * Infer.instantiateArg in order to complete the poly type (this might involve
-     * deferred attribution).
+     * Moreover, if one or more types in A is a deferred type, this routine uses
+     * DeferredAttr in order to perform deferred attribution. If one or more actual
+     * deferred types are stuck, they are placed in a queue and revisited later
+     * after the remainder of the arguments have been seen. If this is not sufficient
+     * to 'unstuck' the argument, a cyclic inference error is called out.
      *
      * A method check handler (see above) is used in order to report errors.
      */
     void checkRawArgumentsAcceptable(final Env<AttrContext> env,
+                                Symbol msym,
+                                DeferredAttr.AttrMode mode,
                                 final Infer.InferenceContext inferenceContext,
                                 List<Type> argtypes,
                                 List<Type> formals,
                                 boolean allowBoxing,
                                 boolean useVarargs,
                                 Warner warn,
-                                MethodCheckHandler handler) {
+                                final MethodCheckHandler handler) {
         Type varargsFormal = useVarargs ? formals.last() : null;
-        ListBuffer<Type> checkedArgs = ListBuffer.lb();
 
         if (varargsFormal == null &&
                 argtypes.size() != formals.size()) {
             throw handler.arityMismatch(); // not enough args
         }
 
+        DeferredAttr.DeferredAttrContext deferredAttrContext =
+                deferredAttr.new DeferredAttrContext(mode, msym, currentResolutionContext.step, inferenceContext);
+
         while (argtypes.nonEmpty() && formals.head != varargsFormal) {
-            ResultInfo resultInfo = methodCheckResult(formals.head, allowBoxing, false, inferenceContext, handler, warn);
-            checkedArgs.append(resultInfo.check(env.tree.pos(), argtypes.head));
+            ResultInfo mresult = methodCheckResult(formals.head, allowBoxing, false, inferenceContext, deferredAttrContext, handler, warn);
+            mresult.check(null, argtypes.head);
             argtypes = argtypes.tail;
             formals = formals.tail;
         }
@@ -638,15 +672,17 @@
         if (useVarargs) {
             //note: if applicability check is triggered by most specific test,
             //the last argument of a varargs is _not_ an array type (see JLS 15.12.2.5)
-            Type elt = types.elemtype(varargsFormal);
+            final Type elt = types.elemtype(varargsFormal);
+            ResultInfo mresult = methodCheckResult(elt, allowBoxing, true, inferenceContext, deferredAttrContext, handler, warn);
             while (argtypes.nonEmpty()) {
-                ResultInfo resultInfo = methodCheckResult(elt, allowBoxing, true, inferenceContext, handler, warn);
-                checkedArgs.append(resultInfo.check(env.tree.pos(), argtypes.head));
+                mresult.check(null, argtypes.head);
                 argtypes = argtypes.tail;
             }
             //check varargs element type accessibility
             varargsAccessible(env, elt, handler, inferenceContext);
         }
+
+        deferredAttrContext.complete();
     }
 
     void varargsAccessible(final Env<AttrContext> env, final Type t, final Resolve.MethodCheckHandler handler, final InferenceContext inferenceContext) {
@@ -674,12 +710,15 @@
         MethodCheckHandler handler;
         boolean useVarargs;
         Infer.InferenceContext inferenceContext;
+        DeferredAttrContext deferredAttrContext;
         Warner rsWarner;
 
-        public MethodCheckContext(MethodCheckHandler handler, boolean useVarargs, Infer.InferenceContext inferenceContext, Warner rsWarner) {
+        public MethodCheckContext(MethodCheckHandler handler, boolean useVarargs,
+                Infer.InferenceContext inferenceContext, DeferredAttrContext deferredAttrContext, Warner rsWarner) {
             this.handler = handler;
             this.useVarargs = useVarargs;
             this.inferenceContext = inferenceContext;
+            this.deferredAttrContext = deferredAttrContext;
             this.rsWarner = rsWarner;
         }
 
@@ -694,6 +733,10 @@
         public InferenceContext inferenceContext() {
             return inferenceContext;
         }
+
+        public DeferredAttrContext deferredAttrContext() {
+            return deferredAttrContext;
+        }
     }
 
     /**
@@ -702,8 +745,9 @@
      */
     class StrictMethodContext extends MethodCheckContext {
 
-        public StrictMethodContext(MethodCheckHandler handler, boolean useVarargs, Infer.InferenceContext inferenceContext, Warner rsWarner) {
-            super(handler, useVarargs, inferenceContext, rsWarner);
+        public StrictMethodContext(MethodCheckHandler handler, boolean useVarargs,
+                Infer.InferenceContext inferenceContext, DeferredAttrContext deferredAttrContext, Warner rsWarner) {
+            super(handler, useVarargs, inferenceContext, deferredAttrContext, rsWarner);
         }
 
         public boolean compatible(Type found, Type req, Warner warn) {
@@ -717,8 +761,9 @@
      */
     class LooseMethodContext extends MethodCheckContext {
 
-        public LooseMethodContext(MethodCheckHandler handler, boolean useVarargs, Infer.InferenceContext inferenceContext, Warner rsWarner) {
-            super(handler, useVarargs, inferenceContext, rsWarner);
+        public LooseMethodContext(MethodCheckHandler handler, boolean useVarargs,
+                Infer.InferenceContext inferenceContext, DeferredAttrContext deferredAttrContext, Warner rsWarner) {
+            super(handler, useVarargs, inferenceContext, deferredAttrContext, rsWarner);
         }
 
         public boolean compatible(Type found, Type req, Warner warn) {
@@ -730,16 +775,37 @@
      * Create a method check context to be used during method applicability check
      */
     ResultInfo methodCheckResult(Type to, boolean allowBoxing, boolean useVarargs,
-            Infer.InferenceContext inferenceContext, MethodCheckHandler methodHandler, Warner rsWarner) {
+            Infer.InferenceContext inferenceContext, DeferredAttr.DeferredAttrContext deferredAttrContext,
+            MethodCheckHandler methodHandler, Warner rsWarner) {
         MethodCheckContext checkContext = allowBoxing ?
-                new LooseMethodContext(methodHandler, useVarargs, inferenceContext, rsWarner) :
-                new StrictMethodContext(methodHandler, useVarargs, inferenceContext, rsWarner);
-        return attr.new ResultInfo(VAL, to, checkContext) {
-            @Override
-            protected Type check(DiagnosticPosition pos, Type found) {
+                new LooseMethodContext(methodHandler, useVarargs, inferenceContext, deferredAttrContext, rsWarner) :
+                new StrictMethodContext(methodHandler, useVarargs, inferenceContext, deferredAttrContext, rsWarner);
+        return new MethodResultInfo(to, checkContext, deferredAttrContext);
+    }
+
+    class MethodResultInfo extends ResultInfo {
+
+        DeferredAttr.DeferredAttrContext deferredAttrContext;
+
+        public MethodResultInfo(Type pt, MethodCheckContext checkContext, DeferredAttr.DeferredAttrContext deferredAttrContext) {
+            attr.super(VAL, pt, checkContext);
+            this.deferredAttrContext = deferredAttrContext;
+        }
+
+        @Override
+        protected Type check(DiagnosticPosition pos, Type found) {
+            if (found.tag == DEFERRED) {
+                DeferredType dt = (DeferredType)found;
+                return dt.check(this);
+            } else {
                 return super.check(pos, chk.checkNonVoid(pos, types.capture(types.upperBound(found.baseType()))));
             }
-        };
+        }
+
+        @Override
+        protected MethodResultInfo dup(Type newPt) {
+            return new MethodResultInfo(newPt, (MethodCheckContext)checkContext, deferredAttrContext);
+        }
     }
 
     public static class InapplicableMethodException extends RuntimeException {
@@ -1614,14 +1680,41 @@
      *
      *  @param sym       The symbol that was found, or a ResolveError.
      *  @param pos       The position to use for error reporting.
+     *  @param location  The symbol the served as a context for this lookup
      *  @param site      The original type from where the selection took place.
      *  @param name      The symbol's name.
+     *  @param qualified Did we get here through a qualified expression resolution?
      *  @param argtypes  The invocation's value arguments,
      *                   if we looked for a method.
      *  @param typeargtypes  The invocation's type arguments,
      *                   if we looked for a method.
+     *  @param logResolveHelper helper class used to log resolve errors
      */
-    Symbol access(Symbol sym,
+    Symbol accessInternal(Symbol sym,
+                  DiagnosticPosition pos,
+                  Symbol location,
+                  Type site,
+                  Name name,
+                  boolean qualified,
+                  List<Type> argtypes,
+                  List<Type> typeargtypes,
+                  LogResolveHelper logResolveHelper) {
+        if (sym.kind >= AMBIGUOUS) {
+            ResolveError errSym = (ResolveError)sym;
+            sym = errSym.access(name, qualified ? site.tsym : syms.noSymbol);
+            argtypes = logResolveHelper.getArgumentTypes(errSym, sym, name, argtypes);
+            if (logResolveHelper.resolveDiagnosticNeeded(site, argtypes, typeargtypes)) {
+                logResolveError(errSym, pos, location, site, name, argtypes, typeargtypes);
+            }
+        }
+        return sym;
+    }
+
+    /**
+     * Variant of the generalized access routine, to be used for generating method
+     * resolution diagnostics
+     */
+    Symbol accessMethod(Symbol sym,
                   DiagnosticPosition pos,
                   Symbol location,
                   Type site,
@@ -1629,53 +1722,91 @@
                   boolean qualified,
                   List<Type> argtypes,
                   List<Type> typeargtypes) {
-        if (sym.kind >= AMBIGUOUS) {
-            ResolveError errSym = (ResolveError)sym;
-            if (!site.isErroneous() &&
-                !Type.isErroneous(argtypes) &&
-                (typeargtypes==null || !Type.isErroneous(typeargtypes)))
-                logResolveError(errSym, pos, location, site, name, argtypes, typeargtypes);
-            sym = errSym.access(name, qualified ? site.tsym : syms.noSymbol);
-        }
-        return sym;
+        return accessInternal(sym, pos, location, site, name, qualified, argtypes, typeargtypes, methodLogResolveHelper);
     }
 
-    /** Same as original access(), but without location.
+    /** Same as original accessMethod(), but without location.
      */
-    Symbol access(Symbol sym,
+    Symbol accessMethod(Symbol sym,
                   DiagnosticPosition pos,
                   Type site,
                   Name name,
                   boolean qualified,
                   List<Type> argtypes,
                   List<Type> typeargtypes) {
-        return access(sym, pos, site.tsym, site, name, qualified, argtypes, typeargtypes);
+        return accessMethod(sym, pos, site.tsym, site, name, qualified, argtypes, typeargtypes);
     }
 
-    /** Same as original access(), but without type arguments and arguments.
+    /**
+     * Variant of the generalized access routine, to be used for generating variable,
+     * type resolution diagnostics
      */
-    Symbol access(Symbol sym,
+    Symbol accessBase(Symbol sym,
                   DiagnosticPosition pos,
                   Symbol location,
                   Type site,
                   Name name,
                   boolean qualified) {
-        if (sym.kind >= AMBIGUOUS)
-            return access(sym, pos, location, site, name, qualified, List.<Type>nil(), null);
-        else
-            return sym;
+        return accessInternal(sym, pos, location, site, name, qualified, List.<Type>nil(), null, basicLogResolveHelper);
     }
 
-    /** Same as original access(), but without location, type arguments and arguments.
+    /** Same as original accessBase(), but without location.
      */
-    Symbol access(Symbol sym,
+    Symbol accessBase(Symbol sym,
                   DiagnosticPosition pos,
                   Type site,
                   Name name,
                   boolean qualified) {
-        return access(sym, pos, site.tsym, site, name, qualified);
+        return accessBase(sym, pos, site.tsym, site, name, qualified);
+    }
+
+    interface LogResolveHelper {
+        boolean resolveDiagnosticNeeded(Type site, List<Type> argtypes, List<Type> typeargtypes);
+        List<Type> getArgumentTypes(ResolveError errSym, Symbol accessedSym, Name name, List<Type> argtypes);
     }
 
+    LogResolveHelper basicLogResolveHelper = new LogResolveHelper() {
+        public boolean resolveDiagnosticNeeded(Type site, List<Type> argtypes, List<Type> typeargtypes) {
+            return !site.isErroneous();
+        }
+        public List<Type> getArgumentTypes(ResolveError errSym, Symbol accessedSym, Name name, List<Type> argtypes) {
+            return argtypes;
+        }
+    };
+
+    LogResolveHelper methodLogResolveHelper = new LogResolveHelper() {
+        public boolean resolveDiagnosticNeeded(Type site, List<Type> argtypes, List<Type> typeargtypes) {
+            return !site.isErroneous() &&
+                        !Type.isErroneous(argtypes) &&
+                        (typeargtypes == null || !Type.isErroneous(typeargtypes));
+        }
+        public List<Type> getArgumentTypes(ResolveError errSym, Symbol accessedSym, Name name, List<Type> argtypes) {
+            if (syms.operatorNames.contains(name)) {
+                return argtypes;
+            } else {
+                Symbol msym = errSym.kind == WRONG_MTH ?
+                        ((InapplicableSymbolError)errSym).errCandidate().sym : accessedSym;
+
+                List<Type> argtypes2 = Type.map(argtypes,
+                        deferredAttr.new RecoveryDeferredTypeMap(AttrMode.SPECULATIVE, msym, currentResolutionContext.firstErroneousResolutionPhase()));
+
+                if (msym != accessedSym) {
+                    //fixup deferred type caches - this 'hack' is required because the symbol
+                    //returned by InapplicableSymbolError.access() will hide the candidate
+                    //method symbol that can be used for lookups in the speculative cache,
+                    //causing problems in Attr.checkId()
+                    for (Type t : argtypes) {
+                        if (t.tag == DEFERRED) {
+                            DeferredType dt = (DeferredType)t;
+                            dt.speculativeCache.dupAllTo(msym, accessedSym);
+                        }
+                    }
+                }
+                return argtypes2;
+            }
+        }
+    };
+
     /** Check that sym is not an abstract method.
      */
     void checkNonAbstract(DiagnosticPosition pos, Symbol sym) {
@@ -1734,7 +1865,7 @@
      */
     Symbol resolveIdent(DiagnosticPosition pos, Env<AttrContext> env,
                         Name name, int kind) {
-        return access(
+        return accessBase(
             findIdent(env, name, kind),
             pos, env.enclClass.sym.type, name, false);
     }
@@ -1759,19 +1890,19 @@
             while (steps.nonEmpty() &&
                    steps.head.isApplicable(boxingEnabled, varargsEnabled) &&
                    sym.kind >= ERRONEOUS) {
-                currentResolutionContext.step = steps.head;
+                currentResolutionContext.step = env.info.pendingResolutionPhase = steps.head;
                 sym = findFun(env, name, argtypes, typeargtypes,
                         steps.head.isBoxingRequired,
-                        env.info.varArgs = steps.head.isVarargsRequired);
+                        steps.head.isVarargsRequired);
                 currentResolutionContext.resolutionCache.put(steps.head, sym);
                 steps = steps.tail;
             }
             if (sym.kind >= AMBIGUOUS) {//if nothing is found return the 'first' error
                 MethodResolutionPhase errPhase =
                         currentResolutionContext.firstErroneousResolutionPhase();
-                sym = access(currentResolutionContext.resolutionCache.get(errPhase),
+                sym = accessMethod(currentResolutionContext.resolutionCache.get(errPhase),
                         pos, env.enclClass.sym.type, name, false, argtypes, typeargtypes);
-                env.info.varArgs = errPhase.isVarargsRequired;
+                env.info.pendingResolutionPhase = errPhase;
             }
             return sym;
         }
@@ -1811,10 +1942,10 @@
             while (steps.nonEmpty() &&
                    steps.head.isApplicable(boxingEnabled, varargsEnabled) &&
                    sym.kind >= ERRONEOUS) {
-                currentResolutionContext.step = steps.head;
+                currentResolutionContext.step = env.info.pendingResolutionPhase = steps.head;
                 sym = findMethod(env, site, name, argtypes, typeargtypes,
                         steps.head.isBoxingRequired(),
-                        env.info.varArgs = steps.head.isVarargsRequired(), false);
+                        steps.head.isVarargsRequired(), false);
                 currentResolutionContext.resolutionCache.put(steps.head, sym);
                 steps = steps.tail;
             }
@@ -1822,13 +1953,13 @@
                 //if nothing is found return the 'first' error
                 MethodResolutionPhase errPhase =
                         currentResolutionContext.firstErroneousResolutionPhase();
-                sym = access(currentResolutionContext.resolutionCache.get(errPhase),
+                sym = accessMethod(currentResolutionContext.resolutionCache.get(errPhase),
                         pos, location, site, name, true, argtypes, typeargtypes);
-                env.info.varArgs = errPhase.isVarargsRequired;
+                env.info.pendingResolutionPhase = errPhase;
             } else if (allowMethodHandles) {
                 MethodSymbol msym = (MethodSymbol)sym;
                 if (msym.isSignaturePolymorphic(types)) {
-                    env.info.varArgs = false;
+                    env.info.pendingResolutionPhase = BASIC;
                     return findPolymorphicSignatureInstance(env, sym, argtypes);
                 }
             }
@@ -1850,7 +1981,7 @@
                                             Symbol spMethod,
                                             List<Type> argtypes) {
         Type mtype = infer.instantiatePolymorphicSignatureInstance(env,
-                (MethodSymbol)spMethod, argtypes);
+                (MethodSymbol)spMethod, currentResolutionContext, argtypes);
         for (Symbol sym : polymorphicSignatureScope.getElementsByName(spMethod.name)) {
             if (types.isSameType(mtype, sym.type)) {
                return sym;
@@ -1918,18 +2049,18 @@
             while (steps.nonEmpty() &&
                    steps.head.isApplicable(boxingEnabled, varargsEnabled) &&
                    sym.kind >= ERRONEOUS) {
-                currentResolutionContext.step = steps.head;
+                currentResolutionContext.step = env.info.pendingResolutionPhase = steps.head;
                 sym = findConstructor(pos, env, site, argtypes, typeargtypes,
                         steps.head.isBoxingRequired(),
-                        env.info.varArgs = steps.head.isVarargsRequired());
+                        steps.head.isVarargsRequired());
                 currentResolutionContext.resolutionCache.put(steps.head, sym);
                 steps = steps.tail;
             }
             if (sym.kind >= AMBIGUOUS) {//if nothing is found return the 'first' error
                 MethodResolutionPhase errPhase = currentResolutionContext.firstErroneousResolutionPhase();
-                sym = access(currentResolutionContext.resolutionCache.get(errPhase),
+                sym = accessMethod(currentResolutionContext.resolutionCache.get(errPhase),
                         pos, site, names.init, true, argtypes, typeargtypes);
-                env.info.varArgs = errPhase.isVarargsRequired();
+                env.info.pendingResolutionPhase = errPhase;
             }
             return sym;
         }
@@ -1961,10 +2092,10 @@
             while (steps.nonEmpty() &&
                    steps.head.isApplicable(boxingEnabled, varargsEnabled) &&
                    sym.kind >= ERRONEOUS) {
-                currentResolutionContext.step = steps.head;
+                currentResolutionContext.step = env.info.pendingResolutionPhase = steps.head;
                 sym = findDiamond(env, site, argtypes, typeargtypes,
                         steps.head.isBoxingRequired(),
-                        env.info.varArgs = steps.head.isVarargsRequired());
+                        steps.head.isVarargsRequired());
                 currentResolutionContext.resolutionCache.put(steps.head, sym);
                 steps = steps.tail;
             }
@@ -1986,8 +2117,8 @@
                     }
                 };
                 MethodResolutionPhase errPhase = currentResolutionContext.firstErroneousResolutionPhase();
-                sym = access(errSym, pos, site, names.init, true, argtypes, typeargtypes);
-                env.info.varArgs = errPhase.isVarargsRequired();
+                sym = accessMethod(errSym, pos, site, names.init, true, argtypes, typeargtypes);
+                env.info.pendingResolutionPhase = errPhase;
             }
             return sym;
         }
@@ -2115,7 +2246,7 @@
             if (boxingEnabled && sym.kind >= WRONG_MTHS)
                 sym = findMethod(env, syms.predefClass.type, name, argtypes,
                                  null, true, false, true);
-            return access(sym, pos, env.enclClass.sym.type, name,
+            return accessMethod(sym, pos, env.enclClass.sym.type, name,
                           false, argtypes, null);
         }
         finally {
@@ -2167,7 +2298,7 @@
                 Symbol sym = env1.info.scope.lookup(name).sym;
                 if (sym != null) {
                     if (staticOnly) sym = new StaticError(sym);
-                    return access(sym, pos, env.enclClass.sym.type,
+                    return accessBase(sym, pos, env.enclClass.sym.type,
                                   name, true);
                 }
             }
@@ -2199,7 +2330,7 @@
                     Symbol sym = env1.info.scope.lookup(name).sym;
                     if (sym != null) {
                         if (staticOnly) sym = new StaticError(sym);
-                        return access(sym, pos, env.enclClass.sym.type,
+                        return accessBase(sym, pos, env.enclClass.sym.type,
                                       name, true);
                     }
                 }
@@ -2322,17 +2453,6 @@
                 Name name,
                 List<Type> argtypes,
                 List<Type> typeargtypes);
-
-        /**
-         * A name designates an operator if it consists
-         * of a non-empty sequence of operator symbols {@literal +-~!/*%&|^<>= }
-         */
-        boolean isOperator(Name name) {
-            int i = 0;
-            while (i < name.getByteLength() &&
-                   "+-~!*/%&|^<>=".indexOf(name.getByteAt(i)) >= 0) i++;
-            return i > 0 && i == name.getByteLength();
-        }
     }
 
     /**
@@ -2393,7 +2513,7 @@
             if (name == names.error)
                 return null;
 
-            if (isOperator(name)) {
+            if (syms.operatorNames.contains(name)) {
                 boolean isUnaryOp = argtypes.size() == 1;
                 String key = argtypes.size() == 1 ?
                     "operator.cant.be.applied" :
@@ -2415,8 +2535,7 @@
                 hasLocation = !location.name.equals(names._this) &&
                         !location.name.equals(names._super);
             }
-            boolean isConstructor = kind == ABSENT_MTH &&
-                    name == names.table.names.init;
+            boolean isConstructor = kind == ABSENT_MTH && name == names.init;
             KindName kindname = isConstructor ? KindName.CONSTRUCTOR : absentKind(kind);
             Name idname = isConstructor ? site.tsym.name : name;
             String errKey = getErrorKey(kindname, typeargtypes.nonEmpty(), hasLocation);
@@ -2496,7 +2615,7 @@
             if (name == names.error)
                 return null;
 
-            if (isOperator(name)) {
+            if (syms.operatorNames.contains(name)) {
                 boolean isUnaryOp = argtypes.size() == 1;
                 String key = argtypes.size() == 1 ?
                     "operator.cant.be.applied" :
@@ -2774,9 +2893,10 @@
         private Map<MethodResolutionPhase, Symbol> resolutionCache =
             new EnumMap<MethodResolutionPhase, Symbol>(MethodResolutionPhase.class);
 
-        private MethodResolutionPhase step = null;
+        MethodResolutionPhase step = null;
 
         private boolean internalResolution = false;
+        private DeferredAttr.AttrMode attrMode = DeferredAttr.AttrMode.SPECULATIVE;
 
         private MethodResolutionPhase firstErroneousResolutionPhase() {
             MethodResolutionPhase bestSoFar = BASIC;
@@ -2842,6 +2962,14 @@
                 return mtype != null;
             }
         }
+
+        DeferredAttr.AttrMode attrMode() {
+            return attrMode;
+        }
+
+        boolean internal() {
+            return internalResolution;
+        }
     }
 
     MethodResolutionContext currentResolutionContext = null;
--- a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Thu Oct 04 13:04:53 2012 +0100
@@ -1041,7 +1041,7 @@
                 genEndPos = true;
                 if (!taskListener.isEmpty())
                     taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));
-                log.deferDiagnostics = true;
+                log.deferAll();
             } else { // free resources
                 procEnvImpl.close();
             }
@@ -1151,7 +1151,7 @@
                 if (c != this)
                     annotationProcessingOccurred = c.annotationProcessingOccurred = true;
                 // doProcessing will have handled deferred diagnostics
-                Assert.check(c.log.deferDiagnostics == false
+                Assert.check(c.log.deferredDiagFilter == null
                         && c.log.deferredDiagnostics.size() == 0);
                 return c;
             } finally {
--- a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java	Thu Oct 04 13:04:53 2012 +0100
@@ -806,7 +806,7 @@
             log = Log.instance(context);
             log.nerrors = priorErrors;
             log.nwarnings += priorWarnings;
-            log.deferDiagnostics = true;
+            log.deferAll();
 
             // the following is for the benefit of JavacProcessingEnvironment.getContext()
             JavacProcessingEnvironment.this.context = context;
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Thu Oct 04 13:04:53 2012 +0100
@@ -635,6 +635,10 @@
     second operand: {0}\n\
     third operand : {1}
 
+# 0: message segment
+compiler.misc.incompatible.type.in.conditional=\
+    bad type in conditional expression; {0}
+
 compiler.err.new.not.allowed.in.annotation=\
     ''new'' not allowed in an annotation
 
@@ -1701,6 +1705,10 @@
     inferred: {0}\n\
     equality constraints(s): {1}
 
+# 0: list of type
+compiler.misc.cyclic.inference=\
+    Cannot instantiate inference variables {0} because of an inference loop
+
 # 0: symbol
 compiler.misc.diamond=\
     {0}<>
@@ -2086,6 +2094,9 @@
 compiler.misc.type.null=\
     <null>
 
+compiler.misc.type.conditional=\
+    conditional expression
+
 # X#n (where n is an int id) is disambiguated tvar name
 # 0: name, 1: number
 compiler.misc.type.var=\
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java	Thu Oct 04 13:04:53 2012 +0100
@@ -81,6 +81,12 @@
      */
     DocCommentTable docComments = null;
 
+    /**
+     * A string sequence to be used when Pretty output should be constrained
+     * to fit into a given size
+     */
+    private final static String trimSequence = "[...]";
+
     /** Align code to be indented to left margin.
      */
     void align() throws IOException {
@@ -129,6 +135,27 @@
         out.write(lineSep);
     }
 
+    public static String toSimpleString(JCTree tree, int maxLength) {
+        StringWriter s = new StringWriter();
+        try {
+            new Pretty(s, false).printExpr(tree);
+        }
+        catch (IOException e) {
+            // should never happen, because StringWriter is defined
+            // never to throw any IOExceptions
+            throw new AssertionError(e);
+        }
+        //we need to (i) replace all line terminators with a space and (ii) remove
+        //occurrences of 'missing' in the Pretty output (generated when types are missing)
+        String res = s.toString().replaceAll("\\s+", " ").replaceAll("/\\*missing\\*/", "");
+        if (res.length() < maxLength) {
+            return res;
+        } else {
+            int split = (maxLength - trimSequence.length()) * 2 / 3;
+            return res.substring(0, split) + trimSequence + res.substring(split);
+        }
+    }
+
     String lineSep = System.getProperty("line.separator");
 
     /**************************************************************************
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Thu Oct 04 13:04:53 2012 +0100
@@ -245,6 +245,23 @@
         }
     }
 
+    /** Return true if a a tree corresponds to a poly expression. */
+    public static boolean isPoly(JCTree tree, JCTree origin) {
+        switch (tree.getTag()) {
+            case APPLY:
+            case NEWCLASS:
+            case CONDEXPR:
+                return !origin.hasTag(TYPECAST);
+            case LAMBDA:
+            case REFERENCE:
+                return true;
+            case PARENS:
+                return isPoly(((JCParens)tree).expr, origin);
+            default:
+                return false;
+        }
+    }
+
     /**
      * Return true if the AST corresponds to a static select of the kind A.B
      */
--- a/langtools/src/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java	Thu Oct 04 13:04:53 2012 +0100
@@ -489,7 +489,8 @@
      * type referred by a given captured type C contains C itself) which might
      * lead to infinite loops.
      */
-    protected Printer printer = new Printer() {
+    protected Printer printer = new Printer(isRaw()) {
+
         @Override
         protected String localize(Locale locale, String key, Object... args) {
             return AbstractDiagnosticFormatter.this.localize(locale, key, args);
--- a/langtools/src/share/classes/com/sun/tools/javac/util/List.java	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/List.java	Thu Oct 04 13:04:53 2012 +0100
@@ -83,6 +83,19 @@
         }
     };
 
+    /** Returns the list obtained from 'l' after removing all elements 'elem'
+     */
+    public static <A> List<A> filter(List<A> l, A elem) {
+        Assert.checkNonNull(elem);
+        List<A> res = List.nil();
+        for (A a : l) {
+            if (a != null && !a.equals(elem)) {
+                res = res.prepend(a);
+            }
+        }
+        return res.reverse();
+    }
+
     /** Construct a list consisting of given element.
      */
     public static <A> List<A> of(A x1) {
@@ -120,6 +133,14 @@
         return xs;
     }
 
+    public static <A> List<A> from(Iterable<? extends A> coll) {
+        List<A> xs = nil();
+        for (A a : coll) {
+            xs = new List<A>(a, xs);
+        }
+        return xs;
+    }
+
     /** Construct a list consisting of a given number of identical elements.
      *  @param len    The number of elements in the list.
      *  @param init   The value of each element.
--- a/langtools/src/share/classes/com/sun/tools/javac/util/Log.java	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/Log.java	Thu Oct 04 13:04:53 2012 +0100
@@ -130,7 +130,7 @@
     /**
      * Deferred diagnostics
      */
-    public boolean deferDiagnostics;
+    public Filter<JCDiagnostic> deferredDiagFilter;
     public Queue<JCDiagnostic> deferredDiagnostics = new ListBuffer<JCDiagnostic>();
 
     /** Construct a log with given I/O redirections.
@@ -450,7 +450,7 @@
 
     /** Report selected deferred diagnostics, and clear the deferDiagnostics flag. */
     public void reportDeferredDiagnostics(Set<JCDiagnostic.Kind> kinds) {
-        deferDiagnostics = false;
+        deferredDiagFilter = null;
         JCDiagnostic d;
         while ((d = deferredDiagnostics.poll()) != null) {
             if (kinds.contains(d.getKind()))
@@ -464,7 +464,7 @@
      * reported so far, the diagnostic may be handed off to writeDiagnostic.
      */
     public void report(JCDiagnostic diagnostic) {
-        if (deferDiagnostics) {
+        if (deferredDiagFilter != null && deferredDiagFilter.accepts(diagnostic)) {
             deferredDiagnostics.add(diagnostic);
             return;
         }
@@ -551,6 +551,18 @@
         }
     }
 
+    public void deferAll() {
+        deferredDiagFilter = new Filter<JCDiagnostic>() {
+            public boolean accepts(JCDiagnostic t) {
+                return true;
+            }
+        };
+    }
+
+    public void deferNone() {
+        deferredDiagFilter = null;
+    }
+
     /** Find a localized string in the resource bundle.
      *  Because this method is static, it ignores the locale.
      *  Use localize(key, args) when possible.
--- a/langtools/src/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java	Thu Oct 04 13:04:53 2012 +0100
@@ -325,6 +325,10 @@
      */
     protected class RichPrinter extends Printer {
 
+        public RichPrinter() {
+            super(formatter.isRaw());
+        }
+
         @Override
         public String localize(Locale locale, String key, Object... args) {
             return formatter.localize(locale, key, args);
@@ -393,11 +397,6 @@
         }
 
         @Override
-        protected String printMethodArgs(List<Type> args, boolean varArgs, Locale locale) {
-            return super.printMethodArgs(args, varArgs, locale);
-        }
-
-        @Override
         public String visitClassSymbol(ClassSymbol s, Locale locale) {
             String name = nameSimplifier.simplify(s);
             if (name.length() == 0 ||
--- a/langtools/test/tools/javac/conditional/Conditional.java	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/test/tools/javac/conditional/Conditional.java	Thu Oct 04 13:04:53 2012 +0100
@@ -27,6 +27,7 @@
  * @summary Conditional operator applies assignment conversion
  * @author Tim Hanson, BEA
  *
+ * @compile -XDallowPoly Conditional.java
  * @compile/fail Conditional.java
  */
 
--- a/langtools/test/tools/javac/diags/examples.not-yet.txt	Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/test/tools/javac/diags/examples.not-yet.txt	Thu Oct 04 13:04:53 2012 +0100
@@ -58,6 +58,7 @@
 compiler.misc.fatal.err.cant.close	                # JavaCompiler
 compiler.misc.file.does.not.contain.package
 compiler.misc.illegal.start.of.class.file
+compiler.misc.cyclic.inference                          # Cannot happen w/o lambdas
 compiler.misc.kindname.annotation
 compiler.misc.kindname.enum
 compiler.misc.kindname.package
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/IncompatibleTypesInConditional.java	Thu Oct 04 13:04:53 2012 +0100
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012, 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.prob.found.req
+// key: compiler.misc.incompatible.type.in.conditional
+// key: compiler.misc.inconvertible.types
+// options: -XDallowPoly
+
+class IncompatibleTypesInConditional {
+
+    interface A { }
+    interface B { }
+
+    B b = true ? (A)null : (B)null;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/TypeConditional.java	Thu Oct 04 13:04:53 2012 +0100
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012, 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.apply.symbol.1
+// key: compiler.misc.type.conditional
+// key: compiler.misc.no.args
+// key: compiler.misc.arg.length.mismatch
+// options: -XDallowPoly
+// run: simple
+
+class TypeConditional {
+
+    void m() { }
+
+    void test() {
+        m(true ? 1 : 2);
+    }
+}