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<Type, Set<Type>> depVarsMap = new LinkedHashMap<>();
- List<Type> 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<Type> 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<Type> 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<StuckNode> 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<? extends StuckNode> csn = GraphUtils.tarjan(nodes).get(0);
+ return csn.length() == 1 ? csn.get(0).data : deferredAttrNodes.get(0);
+ }
+
+ class StuckNode extends GraphUtils.TarjanNode<DeferredAttrNode, StuckNode> {
+
+ Set<StuckNode> deps = new HashSet<>();
+
+ StuckNode(DeferredAttrNode data) {
+ super(data);
+ }
+
+ @Override
+ public DependencyKind[] getSupportedDependencyKinds() {
+ return new DependencyKind[] { Infer.DependencyKind.STUCK };
+ }
+
+ @Override
+ public Collection<? extends StuckNode> getDependenciesByKind(DependencyKind dk) {
+ if (dk == Infer.DependencyKind.STUCK) {
+ return deps;
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ @Override
+ public Iterable<? extends StuckNode> getAllDependencies() {
+ return deps;
+ }
+ }
}
/**