diff -r 6ae7f7d9b44c -r b643c42e9d25 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Tue May 17 01:35:36 2016 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Tue May 17 17:53:18 2016 +0100 @@ -35,6 +35,7 @@ import com.sun.tools.javac.tree.*; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.DefinedBy.Api; +import com.sun.tools.javac.util.GraphUtils.DependencyKind; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.comp.Attr.ResultInfo; @@ -44,9 +45,10 @@ import com.sun.tools.javac.util.Log.DeferredDiagnosticHandler; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.EnumSet; -import java.util.LinkedHashMap; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; @@ -576,28 +578,11 @@ */ void complete() { while (!deferredAttrNodes.isEmpty()) { - Map> depVarsMap = new LinkedHashMap<>(); - List stuckVars = List.nil(); 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.process(this)) { - List restStuckVars = - List.from(deferredAttrNode.deferredStuckPolicy.stuckVars()) - .intersect(inferenceContext.restvars()); - stuckVars = stuckVars.prependList(restStuckVars); - //update dependency map - for (Type t : List.from(deferredAttrNode.deferredStuckPolicy.depVars()) - .intersect(inferenceContext.restvars())) { - Set prevDeps = depVarsMap.get(t); - if (prevDeps == null) { - prevDeps = new LinkedHashSet<>(); - depVarsMap.put(t, prevDeps); - } - prevDeps.addAll(restStuckVars); - } - } else { + if (deferredAttrNode.process(this)) { deferredAttrNodes.remove(deferredAttrNode); progress = true; } @@ -612,7 +597,9 @@ //remove all variables that have already been instantiated //from the list of stuck variables try { - inferenceContext.solveAny(stuckVars, depVarsMap, warn); + //find stuck expression to unstuck + DeferredAttrNode toUnstuck = pickDeferredNode(); + inferenceContext.solveAny(List.from(toUnstuck.deferredStuckPolicy.stuckVars()), warn); inferenceContext.notifyChange(); } catch (Infer.GraphStrategy.NodeNotFoundException ex) { //this means that we are in speculative mode and the @@ -634,6 +621,59 @@ } return dac.parent.insideOverloadPhase(); } + + /** + * Pick the deferred node to be unstuck. The chosen node is the first strongly connected + * component containing exactly one node found in the dependency graph induced by deferred nodes. + * If no such component is found, the first deferred node is returned. + */ + DeferredAttrNode pickDeferredNode() { + List nodes = deferredAttrNodes.stream() + .map(StuckNode::new) + .collect(List.collector()); + //init stuck expression graph; a deferred node A depends on a deferred node B iff + //the intersection between A's input variable and B's output variable is non-empty. + for (StuckNode sn1 : nodes) { + for (Type t : sn1.data.deferredStuckPolicy.stuckVars()) { + for (StuckNode sn2 : nodes) { + if (sn1 != sn2 && sn2.data.deferredStuckPolicy.depVars().contains(t)) { + sn1.deps.add(sn2); + } + } + } + } + //compute tarjan on the stuck graph + List csn = GraphUtils.tarjan(nodes).get(0); + return csn.length() == 1 ? csn.get(0).data : deferredAttrNodes.get(0); + } + + class StuckNode extends GraphUtils.TarjanNode { + + Set deps = new HashSet<>(); + + StuckNode(DeferredAttrNode data) { + super(data); + } + + @Override + public DependencyKind[] getSupportedDependencyKinds() { + return new DependencyKind[] { Infer.DependencyKind.STUCK }; + } + + @Override + public Collection getDependenciesByKind(DependencyKind dk) { + if (dk == Infer.DependencyKind.STUCK) { + return deps; + } else { + throw new IllegalStateException(); + } + } + + @Override + public Iterable getAllDependencies() { + return deps; + } + } } /**