diff -r 0ea78d6e0b7b -r b4b0377b8dba langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java
--- /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.
+ *
+ *
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.
+ */
+public class DeferredAttr extends JCTree.Visitor {
+ protected static final Context.Key deferredAttrKey =
+ new Context.Key();
+
+ 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 env;
+ AttrMode mode;
+ SpeculativeCache speculativeCache;
+
+ DeferredType(JCExpression tree, Env 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> cache =
+ new WeakHashMap>();
+
+ 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 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 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 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 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 env, ResultInfo resultInfo) {
+ JCTree newTree = new TreeCopier