src/share/classes/com/sun/tools/javac/comp/Infer.java

changeset 2000
4a6acc42c3a1
parent 1919
3155e77d2676
child 2047
5f915a0c9615
equal deleted inserted replaced
1999:7993cfab8610 2000:4a6acc42c3a1
38 import com.sun.tools.javac.comp.DeferredAttr.AttrMode; 38 import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
39 import com.sun.tools.javac.comp.Infer.GraphSolver.InferenceGraph; 39 import com.sun.tools.javac.comp.Infer.GraphSolver.InferenceGraph;
40 import com.sun.tools.javac.comp.Infer.GraphSolver.InferenceGraph.Node; 40 import com.sun.tools.javac.comp.Infer.GraphSolver.InferenceGraph.Node;
41 import com.sun.tools.javac.comp.Resolve.InapplicableMethodException; 41 import com.sun.tools.javac.comp.Resolve.InapplicableMethodException;
42 import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode; 42 import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode;
43 43 import com.sun.tools.javac.util.GraphUtils.TarjanNode;
44 import java.util.Comparator; 44
45 import java.util.ArrayList;
46 import java.util.Collections;
47 import java.util.EnumMap;
48 import java.util.EnumSet;
45 import java.util.HashMap; 49 import java.util.HashMap;
50 import java.util.HashSet;
51 import java.util.LinkedHashSet;
46 import java.util.Map; 52 import java.util.Map;
47 import java.util.Set; 53 import java.util.Set;
48 import java.util.TreeSet;
49
50 import java.util.ArrayList;
51 import java.util.Collections;
52 import java.util.EnumSet;
53 import java.util.HashSet;
54 54
55 import static com.sun.tools.javac.code.TypeTag.*; 55 import static com.sun.tools.javac.code.TypeTag.*;
56 56
57 /** Helper class for type parameter inference, used by the attribution phase. 57 /** Helper class for type parameter inference, used by the attribution phase.
58 * 58 *
109 109
110 List<JCDiagnostic> messages = List.nil(); 110 List<JCDiagnostic> messages = List.nil();
111 111
112 InferenceException(JCDiagnostic.Factory diags) { 112 InferenceException(JCDiagnostic.Factory diags) {
113 super(diags); 113 super(diags);
114 }
115
116 @Override
117 InapplicableMethodException setMessage() {
118 //no message to set
119 return this;
114 } 120 }
115 121
116 @Override 122 @Override
117 InapplicableMethodException setMessage(JCDiagnostic diag) { 123 InapplicableMethodException setMessage(JCDiagnostic diag) {
118 messages = messages.append(diag); 124 messages = messages.append(diag);
1004 * Graph inference strategy - act as an input to the inference solver; a strategy is 1010 * Graph inference strategy - act as an input to the inference solver; a strategy is
1005 * composed of two ingredients: (i) find a node to solve in the inference graph, 1011 * composed of two ingredients: (i) find a node to solve in the inference graph,
1006 * and (ii) tell th engine when we are done fixing inference variables 1012 * and (ii) tell th engine when we are done fixing inference variables
1007 */ 1013 */
1008 interface GraphStrategy { 1014 interface GraphStrategy {
1015
1016 /**
1017 * A NodeNotFoundException is thrown whenever an inference strategy fails
1018 * to pick the next node to solve in the inference graph.
1019 */
1020 public static class NodeNotFoundException extends RuntimeException {
1021 private static final long serialVersionUID = 0;
1022
1023 InferenceGraph graph;
1024
1025 public NodeNotFoundException(InferenceGraph graph) {
1026 this.graph = graph;
1027 }
1028 }
1009 /** 1029 /**
1010 * Pick the next node (leaf) to solve in the graph 1030 * Pick the next node (leaf) to solve in the graph
1011 */ 1031 */
1012 Node pickNode(InferenceGraph g); 1032 Node pickNode(InferenceGraph g) throws NodeNotFoundException;
1013 /** 1033 /**
1014 * Is this the last step? 1034 * Is this the last step?
1015 */ 1035 */
1016 boolean done(); 1036 boolean done();
1017 } 1037 }
1020 * Simple solver strategy class that locates all leaves inside a graph 1040 * Simple solver strategy class that locates all leaves inside a graph
1021 * and picks the first leaf as the next node to solve 1041 * and picks the first leaf as the next node to solve
1022 */ 1042 */
1023 abstract class LeafSolver implements GraphStrategy { 1043 abstract class LeafSolver implements GraphStrategy {
1024 public Node pickNode(InferenceGraph g) { 1044 public Node pickNode(InferenceGraph g) {
1025 Assert.check(!g.nodes.isEmpty(), "No nodes to solve!"); 1045 if (g.nodes.isEmpty()) {
1046 //should not happen
1047 throw new NodeNotFoundException(g);
1048 };
1026 return g.nodes.get(0); 1049 return g.nodes.get(0);
1027 } 1050 }
1028 1051
1029 boolean isSubtype(Type s, Type t, Warner warn, Infer infer) { 1052 boolean isSubtype(Type s, Type t, Warner warn, Infer infer) {
1030 return doIncorporationOp(IncorporationBinaryOpKind.IS_SUBTYPE, s, t, warn, infer); 1053 return doIncorporationOp(IncorporationBinaryOpKind.IS_SUBTYPE, s, t, warn, infer);
1067 * tries to select the node that has maximal probability to contain one 1090 * tries to select the node that has maximal probability to contain one
1068 * or more inference variables in a given list 1091 * or more inference variables in a given list
1069 */ 1092 */
1070 abstract class BestLeafSolver extends LeafSolver { 1093 abstract class BestLeafSolver extends LeafSolver {
1071 1094
1095 /** list of ivars of which at least one must be solved */
1072 List<Type> varsToSolve; 1096 List<Type> varsToSolve;
1073 1097
1074 BestLeafSolver(List<Type> varsToSolve) { 1098 BestLeafSolver(List<Type> varsToSolve) {
1075 this.varsToSolve = varsToSolve; 1099 this.varsToSolve = varsToSolve;
1076 } 1100 }
1077 1101
1078 /** 1102 /**
1079 * Computes the minimum path that goes from a given node to any of the nodes 1103 * Computes a path that goes from a given node to the leafs in the graph.
1080 * containing a variable in {@code varsToSolve}. For any given path, the cost 1104 * Typically this will start from a node containing a variable in
1081 * is computed as the total number of type-variables that should be eagerly 1105 * {@code varsToSolve}. For any given path, the cost is computed as the total
1082 * instantiated across that path. 1106 * number of type-variables that should be eagerly instantiated across that path.
1083 */ 1107 */
1084 int computeMinPath(InferenceGraph g, Node n) { 1108 Pair<List<Node>, Integer> computeTreeToLeafs(Node n) {
1085 return computeMinPath(g, n, List.<Node>nil(), 0); 1109 Pair<List<Node>, Integer> cachedPath = treeCache.get(n);
1086 } 1110 if (cachedPath == null) {
1087 1111 //cache miss
1088 int computeMinPath(InferenceGraph g, Node n, List<Node> path, int cost) { 1112 if (n.isLeaf()) {
1089 if (path.contains(n)) return Integer.MAX_VALUE; 1113 //if leaf, stop
1090 List<Node> path2 = path.prepend(n); 1114 cachedPath = new Pair<List<Node>, Integer>(List.of(n), n.data.length());
1091 int cost2 = cost + n.data.size(); 1115 } else {
1092 if (!Collections.disjoint(n.data, varsToSolve)) { 1116 //if non-leaf, proceed recursively
1093 return cost2; 1117 Pair<List<Node>, Integer> path = new Pair<List<Node>, Integer>(List.of(n), n.data.length());
1094 } else { 1118 for (Node n2 : n.getAllDependencies()) {
1095 int bestPath = Integer.MAX_VALUE; 1119 if (n2 == n) continue;
1096 for (Node n2 : g.nodes) { 1120 Pair<List<Node>, Integer> subpath = computeTreeToLeafs(n2);
1097 if (n2.deps.contains(n)) { 1121 path = new Pair<List<Node>, Integer>(
1098 int res = computeMinPath(g, n2, path2, cost2); 1122 path.fst.prependList(subpath.fst),
1099 if (res < bestPath) { 1123 path.snd + subpath.snd);
1100 bestPath = res; 1124 }
1101 } 1125 cachedPath = path;
1102 } 1126 }
1103 } 1127 //save results in cache
1104 return bestPath; 1128 treeCache.put(n, cachedPath);
1105 } 1129 }
1106 } 1130 return cachedPath;
1131 }
1132
1133 /** cache used to avoid redundant computation of tree costs */
1134 final Map<Node, Pair<List<Node>, Integer>> treeCache =
1135 new HashMap<Node, Pair<List<Node>, Integer>>();
1136
1137 /** constant value used to mark non-existent paths */
1138 final Pair<List<Node>, Integer> noPath =
1139 new Pair<List<Node>, Integer>(null, Integer.MAX_VALUE);
1107 1140
1108 /** 1141 /**
1109 * Pick the leaf that minimize cost 1142 * Pick the leaf that minimize cost
1110 */ 1143 */
1111 @Override 1144 @Override
1112 public Node pickNode(final InferenceGraph g) { 1145 public Node pickNode(final InferenceGraph g) {
1113 final Map<Node, Integer> leavesMap = new HashMap<Node, Integer>(); 1146 treeCache.clear(); //graph changes at every step - cache must be cleared
1147 Pair<List<Node>, Integer> bestPath = noPath;
1114 for (Node n : g.nodes) { 1148 for (Node n : g.nodes) {
1115 if (n.isLeaf(n)) { 1149 if (!Collections.disjoint(n.data, varsToSolve)) {
1116 leavesMap.put(n, computeMinPath(g, n)); 1150 Pair<List<Node>, Integer> path = computeTreeToLeafs(n);
1117 } 1151 //discard all paths containing at least a node in the
1118 } 1152 //closure computed above
1119 Assert.check(!leavesMap.isEmpty(), "No nodes to solve!"); 1153 if (path.snd < bestPath.snd) {
1120 TreeSet<Node> orderedLeaves = new TreeSet<Node>(new Comparator<Node>() { 1154 bestPath = path;
1121 public int compare(Node n1, Node n2) { 1155 }
1122 return leavesMap.get(n1) - leavesMap.get(n2); 1156 }
1123 } 1157 }
1124 }); 1158 if (bestPath == noPath) {
1125 orderedLeaves.addAll(leavesMap.keySet()); 1159 //no path leads there
1126 return orderedLeaves.first(); 1160 throw new NodeNotFoundException(g);
1161 }
1162 return bestPath.fst.head;
1127 } 1163 }
1128 } 1164 }
1129 1165
1130 /** 1166 /**
1131 * The inference process can be thought of as a sequence of steps. Each step 1167 * The inference process can be thought of as a sequence of steps. Each step
1319 this.steps = steps; 1355 this.steps = steps;
1320 } 1356 }
1321 } 1357 }
1322 1358
1323 /** 1359 /**
1360 * There are two kinds of dependencies between inference variables. The basic
1361 * kind of dependency (or bound dependency) arises when a variable mention
1362 * another variable in one of its bounds. There's also a more subtle kind
1363 * of dependency that arises when a variable 'might' lead to better constraints
1364 * on another variable (this is typically the case with variables holding up
1365 * stuck expressions).
1366 */
1367 enum DependencyKind implements GraphUtils.DependencyKind {
1368
1369 /** bound dependency */
1370 BOUND("dotted"),
1371 /** stuck dependency */
1372 STUCK("dashed");
1373
1374 final String dotSyle;
1375
1376 private DependencyKind(String dotSyle) {
1377 this.dotSyle = dotSyle;
1378 }
1379
1380 @Override
1381 public String getDotStyle() {
1382 return dotSyle;
1383 }
1384 }
1385
1386 /**
1324 * This is the graph inference solver - the solver organizes all inference variables in 1387 * This is the graph inference solver - the solver organizes all inference variables in
1325 * a given inference context by bound dependencies - in the general case, such dependencies 1388 * a given inference context by bound dependencies - in the general case, such dependencies
1326 * would lead to a cyclic directed graph (hence the name); the dependency info is used to build 1389 * would lead to a cyclic directed graph (hence the name); the dependency info is used to build
1327 * an acyclic graph, where all cyclic variables are bundled together. An inference 1390 * an acyclic graph, where all cyclic variables are bundled together. An inference
1328 * step corresponds to solving a node in the acyclic graph - this is done by 1391 * step corresponds to solving a node in the acyclic graph - this is done by
1329 * relying on a given strategy (see GraphStrategy). 1392 * relying on a given strategy (see GraphStrategy).
1330 */ 1393 */
1331 class GraphSolver { 1394 class GraphSolver {
1332 1395
1333 InferenceContext inferenceContext; 1396 InferenceContext inferenceContext;
1397 Map<Type, Set<Type>> stuckDeps;
1334 Warner warn; 1398 Warner warn;
1335 1399
1336 GraphSolver(InferenceContext inferenceContext, Warner warn) { 1400 GraphSolver(InferenceContext inferenceContext, Map<Type, Set<Type>> stuckDeps, Warner warn) {
1337 this.inferenceContext = inferenceContext; 1401 this.inferenceContext = inferenceContext;
1402 this.stuckDeps = stuckDeps;
1338 this.warn = warn; 1403 this.warn = warn;
1339 } 1404 }
1340 1405
1341 /** 1406 /**
1342 * Solve variables in a given inference context. The amount of variables 1407 * Solve variables in a given inference context. The amount of variables
1343 * to be solved, and the way in which the underlying acyclic graph is explored 1408 * to be solved, and the way in which the underlying acyclic graph is explored
1344 * depends on the selected solver strategy. 1409 * depends on the selected solver strategy.
1345 */ 1410 */
1346 void solve(GraphStrategy sstrategy) { 1411 void solve(GraphStrategy sstrategy) {
1347 checkWithinBounds(inferenceContext, warn); //initial propagation of bounds 1412 checkWithinBounds(inferenceContext, warn); //initial propagation of bounds
1348 InferenceGraph inferenceGraph = new InferenceGraph(); 1413 InferenceGraph inferenceGraph = new InferenceGraph(stuckDeps);
1349 while (!sstrategy.done()) { 1414 while (!sstrategy.done()) {
1350 InferenceGraph.Node nodeToSolve = sstrategy.pickNode(inferenceGraph); 1415 InferenceGraph.Node nodeToSolve = sstrategy.pickNode(inferenceGraph);
1351 List<Type> varsToSolve = List.from(nodeToSolve.data); 1416 List<Type> varsToSolve = List.from(nodeToSolve.data);
1352 List<Type> saved_undet = inferenceContext.save(); 1417 List<Type> saved_undet = inferenceContext.save();
1353 try { 1418 try {
1388 * updates on the structure of the graph this node belongs to (used to 1453 * updates on the structure of the graph this node belongs to (used to
1389 * keep dependencies in sync). 1454 * keep dependencies in sync).
1390 */ 1455 */
1391 class Node extends GraphUtils.TarjanNode<ListBuffer<Type>> { 1456 class Node extends GraphUtils.TarjanNode<ListBuffer<Type>> {
1392 1457
1393 Set<Node> deps; 1458 /** map listing all dependencies (grouped by kind) */
1459 EnumMap<DependencyKind, Set<Node>> deps;
1394 1460
1395 Node(Type ivar) { 1461 Node(Type ivar) {
1396 super(ListBuffer.of(ivar)); 1462 super(ListBuffer.of(ivar));
1397 this.deps = new HashSet<Node>(); 1463 this.deps = new EnumMap<DependencyKind, Set<Node>>(DependencyKind.class);
1398 } 1464 }
1399 1465
1400 @Override 1466 @Override
1401 public Iterable<? extends Node> getDependencies() { 1467 public GraphUtils.DependencyKind[] getSupportedDependencyKinds() {
1402 return deps; 1468 return DependencyKind.values();
1403 } 1469 }
1404 1470
1405 @Override 1471 @Override
1406 public String printDependency(GraphUtils.Node<ListBuffer<Type>> to) { 1472 public String getDependencyName(GraphUtils.Node<ListBuffer<Type>> to, GraphUtils.DependencyKind dk) {
1407 StringBuilder buf = new StringBuilder(); 1473 if (dk == DependencyKind.STUCK) return "";
1408 String sep = ""; 1474 else {
1409 for (Type from : data) { 1475 StringBuilder buf = new StringBuilder();
1410 UndetVar uv = (UndetVar)inferenceContext.asFree(from); 1476 String sep = "";
1411 for (Type bound : uv.getBounds(InferenceBound.values())) { 1477 for (Type from : data) {
1412 if (bound.containsAny(List.from(to.data))) { 1478 UndetVar uv = (UndetVar)inferenceContext.asFree(from);
1413 buf.append(sep); 1479 for (Type bound : uv.getBounds(InferenceBound.values())) {
1414 buf.append(bound); 1480 if (bound.containsAny(List.from(to.data))) {
1415 sep = ","; 1481 buf.append(sep);
1482 buf.append(bound);
1483 sep = ",";
1484 }
1416 } 1485 }
1417 } 1486 }
1418 } 1487 return buf.toString();
1419 return buf.toString(); 1488 }
1420 } 1489 }
1421 1490
1422 boolean isLeaf(Node n) { 1491 @Override
1492 public Iterable<? extends Node> getAllDependencies() {
1493 return getDependencies(DependencyKind.values());
1494 }
1495
1496 @Override
1497 public Iterable<? extends TarjanNode<ListBuffer<Type>>> getDependenciesByKind(GraphUtils.DependencyKind dk) {
1498 return getDependencies((DependencyKind)dk);
1499 }
1500
1501 /**
1502 * Retrieves all dependencies with given kind(s).
1503 */
1504 protected Set<Node> getDependencies(DependencyKind... depKinds) {
1505 Set<Node> buf = new LinkedHashSet<Node>();
1506 for (DependencyKind dk : depKinds) {
1507 Set<Node> depsByKind = deps.get(dk);
1508 if (depsByKind != null) {
1509 buf.addAll(depsByKind);
1510 }
1511 }
1512 return buf;
1513 }
1514
1515 /**
1516 * Adds dependency with given kind.
1517 */
1518 protected void addDependency(DependencyKind dk, Node depToAdd) {
1519 Set<Node> depsByKind = deps.get(dk);
1520 if (depsByKind == null) {
1521 depsByKind = new LinkedHashSet<Node>();
1522 deps.put(dk, depsByKind);
1523 }
1524 depsByKind.add(depToAdd);
1525 }
1526
1527 /**
1528 * Add multiple dependencies of same given kind.
1529 */
1530 protected void addDependencies(DependencyKind dk, Set<Node> depsToAdd) {
1531 for (Node n : depsToAdd) {
1532 addDependency(dk, n);
1533 }
1534 }
1535
1536 /**
1537 * Remove a dependency, regardless of its kind.
1538 */
1539 protected Set<DependencyKind> removeDependency(Node n) {
1540 Set<DependencyKind> removedKinds = new HashSet<>();
1541 for (DependencyKind dk : DependencyKind.values()) {
1542 Set<Node> depsByKind = deps.get(dk);
1543 if (depsByKind == null) continue;
1544 if (depsByKind.remove(n)) {
1545 removedKinds.add(dk);
1546 }
1547 }
1548 return removedKinds;
1549 }
1550
1551 /**
1552 * Compute closure of a give node, by recursively walking
1553 * through all its dependencies (of given kinds)
1554 */
1555 protected Set<Node> closure(DependencyKind... depKinds) {
1556 boolean progress = true;
1557 Set<Node> closure = new HashSet<Node>();
1558 closure.add(this);
1559 while (progress) {
1560 progress = false;
1561 for (Node n1 : new HashSet<Node>(closure)) {
1562 progress = closure.addAll(n1.getDependencies(depKinds));
1563 }
1564 }
1565 return closure;
1566 }
1567
1568 /**
1569 * Is this node a leaf? This means either the node has no dependencies,
1570 * or it just has self-dependencies.
1571 */
1572 protected boolean isLeaf() {
1423 //no deps, or only one self dep 1573 //no deps, or only one self dep
1424 return (n.deps.isEmpty() || 1574 Set<Node> allDeps = getDependencies(DependencyKind.BOUND, DependencyKind.STUCK);
1425 n.deps.size() == 1 && n.deps.contains(n)); 1575 if (allDeps.isEmpty()) return true;
1426 } 1576 for (Node n : allDeps) {
1427 1577 if (n != this) {
1428 void mergeWith(List<? extends Node> nodes) { 1578 return false;
1579 }
1580 }
1581 return true;
1582 }
1583
1584 /**
1585 * Merge this node with another node, acquiring its dependencies.
1586 * This routine is used to merge all cyclic node together and
1587 * form an acyclic graph.
1588 */
1589 protected void mergeWith(List<? extends Node> nodes) {
1429 for (Node n : nodes) { 1590 for (Node n : nodes) {
1430 Assert.check(n.data.length() == 1, "Attempt to merge a compound node!"); 1591 Assert.check(n.data.length() == 1, "Attempt to merge a compound node!");
1431 data.appendList(n.data); 1592 data.appendList(n.data);
1432 deps.addAll(n.deps); 1593 for (DependencyKind dk : DependencyKind.values()) {
1594 addDependencies(dk, n.getDependencies(dk));
1595 }
1433 } 1596 }
1434 //update deps 1597 //update deps
1435 Set<Node> deps2 = new HashSet<Node>(); 1598 EnumMap<DependencyKind, Set<Node>> deps2 = new EnumMap<DependencyKind, Set<Node>>(DependencyKind.class);
1436 for (Node d : deps) { 1599 for (DependencyKind dk : DependencyKind.values()) {
1437 if (data.contains(d.data.first())) { 1600 for (Node d : getDependencies(dk)) {
1438 deps2.add(this); 1601 Set<Node> depsByKind = deps2.get(dk);
1439 } else { 1602 if (depsByKind == null) {
1440 deps2.add(d); 1603 depsByKind = new LinkedHashSet<Node>();
1604 deps2.put(dk, depsByKind);
1605 }
1606 if (data.contains(d.data.first())) {
1607 depsByKind.add(this);
1608 } else {
1609 depsByKind.add(d);
1610 }
1441 } 1611 }
1442 } 1612 }
1443 deps = deps2; 1613 deps = deps2;
1444 } 1614 }
1445 1615
1446 void graphChanged(Node from, Node to) { 1616 /**
1447 if (deps.contains(from)) { 1617 * Notify all nodes that something has changed in the graph
1448 deps.remove(from); 1618 * topology.
1619 */
1620 private void graphChanged(Node from, Node to) {
1621 for (DependencyKind dk : removeDependency(from)) {
1449 if (to != null) { 1622 if (to != null) {
1450 deps.add(to); 1623 addDependency(dk, to);
1451 } 1624 }
1452 } 1625 }
1453 } 1626 }
1454 } 1627 }
1455 1628
1456 /** the nodes in the inference graph */ 1629 /** the nodes in the inference graph */
1457 ArrayList<Node> nodes; 1630 ArrayList<Node> nodes;
1458 1631
1459 InferenceGraph() { 1632 InferenceGraph(Map<Type, Set<Type>> optDeps) {
1460 initNodes(); 1633 initNodes(optDeps);
1634 }
1635
1636 /**
1637 * Basic lookup helper for retrieving a graph node given an inference
1638 * variable type.
1639 */
1640 public Node findNode(Type t) {
1641 for (Node n : nodes) {
1642 if (n.data.contains(t)) {
1643 return n;
1644 }
1645 }
1646 return null;
1461 } 1647 }
1462 1648
1463 /** 1649 /**
1464 * Delete a node from the graph. This update the underlying structure 1650 * Delete a node from the graph. This update the underlying structure
1465 * of the graph (including dependencies) via listeners updates. 1651 * of the graph (including dependencies) via listeners updates.
1482 1668
1483 /** 1669 /**
1484 * Create the graph nodes. First a simple node is created for every inference 1670 * Create the graph nodes. First a simple node is created for every inference
1485 * variables to be solved. Then Tarjan is used to found all connected components 1671 * variables to be solved. Then Tarjan is used to found all connected components
1486 * in the graph. For each component containing more than one node, a super node is 1672 * in the graph. For each component containing more than one node, a super node is
1487 * created, effectively replacing the original cyclic nodes. 1673 * created, effectively replacing the original cyclic nodes.
1488 */ 1674 */
1489 void initNodes() { 1675 void initNodes(Map<Type, Set<Type>> stuckDeps) {
1676 //add nodes
1490 nodes = new ArrayList<Node>(); 1677 nodes = new ArrayList<Node>();
1491 for (Type t : inferenceContext.restvars()) { 1678 for (Type t : inferenceContext.restvars()) {
1492 nodes.add(new Node(t)); 1679 nodes.add(new Node(t));
1493 } 1680 }
1681 //add dependencies
1494 for (Node n_i : nodes) { 1682 for (Node n_i : nodes) {
1495 Type i = n_i.data.first(); 1683 Type i = n_i.data.first();
1684 Set<Type> optDepsByNode = stuckDeps.get(i);
1496 for (Node n_j : nodes) { 1685 for (Node n_j : nodes) {
1497 Type j = n_j.data.first(); 1686 Type j = n_j.data.first();
1498 UndetVar uv_i = (UndetVar)inferenceContext.asFree(i); 1687 UndetVar uv_i = (UndetVar)inferenceContext.asFree(i);
1499 if (Type.containsAny(uv_i.getBounds(InferenceBound.values()), List.of(j))) { 1688 if (Type.containsAny(uv_i.getBounds(InferenceBound.values()), List.of(j))) {
1500 //update i's deps 1689 //update i's bound dependencies
1501 n_i.deps.add(n_j); 1690 n_i.addDependency(DependencyKind.BOUND, n_j);
1502 } 1691 }
1503 } 1692 if (optDepsByNode != null && optDepsByNode.contains(j)) {
1504 } 1693 //update i's stuck dependencies
1694 n_i.addDependency(DependencyKind.STUCK, n_j);
1695 }
1696 }
1697 }
1698 //merge cyclic nodes
1505 ArrayList<Node> acyclicNodes = new ArrayList<Node>(); 1699 ArrayList<Node> acyclicNodes = new ArrayList<Node>();
1506 for (List<? extends Node> conSubGraph : GraphUtils.tarjan(nodes)) { 1700 for (List<? extends Node> conSubGraph : GraphUtils.tarjan(nodes)) {
1507 if (conSubGraph.length() > 1) { 1701 if (conSubGraph.length() > 1) {
1508 Node root = conSubGraph.head; 1702 Node root = conSubGraph.head;
1509 root.mergeWith(conSubGraph.tail); 1703 root.mergeWith(conSubGraph.tail);
1629 */ 1823 */
1630 final List<Type> boundedVars() { 1824 final List<Type> boundedVars() {
1631 return filterVars(new Filter<UndetVar>() { 1825 return filterVars(new Filter<UndetVar>() {
1632 public boolean accepts(UndetVar uv) { 1826 public boolean accepts(UndetVar uv) {
1633 return uv.getBounds(InferenceBound.UPPER) 1827 return uv.getBounds(InferenceBound.UPPER)
1634 .diff(uv.getDeclaredBounds()) 1828 .diff(uv.getDeclaredBounds())
1635 .appendList(uv.getBounds(InferenceBound.EQ, InferenceBound.LOWER)).nonEmpty(); 1829 .appendList(uv.getBounds(InferenceBound.EQ, InferenceBound.LOWER)).nonEmpty();
1636 } 1830 }
1637 }); 1831 });
1638 } 1832 }
1639 1833
1640 private List<Type> filterVars(Filter<UndetVar> fu) { 1834 private List<Type> filterVars(Filter<UndetVar> fu) {
1820 } 2014 }
1821 }, List.of(t)); 2015 }, List.of(t));
1822 } 2016 }
1823 } 2017 }
1824 2018
2019 private void solve(GraphStrategy ss, Warner warn) {
2020 solve(ss, new HashMap<Type, Set<Type>>(), warn);
2021 }
2022
1825 /** 2023 /**
1826 * Solve with given graph strategy. 2024 * Solve with given graph strategy.
1827 */ 2025 */
1828 private void solve(GraphStrategy ss, Warner warn) { 2026 private void solve(GraphStrategy ss, Map<Type, Set<Type>> stuckDeps, Warner warn) {
1829 GraphSolver s = new GraphSolver(this, warn); 2027 GraphSolver s = new GraphSolver(this, stuckDeps, warn);
1830 s.solve(ss); 2028 s.solve(ss);
1831 } 2029 }
1832 2030
1833 /** 2031 /**
1834 * Solve all variables in this context. 2032 * Solve all variables in this context.
1853 } 2051 }
1854 2052
1855 /** 2053 /**
1856 * Solve at least one variable in given list. 2054 * Solve at least one variable in given list.
1857 */ 2055 */
1858 public void solveAny(List<Type> varsToSolve, Warner warn) { 2056 public void solveAny(List<Type> varsToSolve, Map<Type, Set<Type>> optDeps, Warner warn) {
1859 checkWithinBounds(this, warn); //propagate bounds 2057 solve(new BestLeafSolver(varsToSolve.intersect(restvars())) {
1860 List<Type> boundedVars = boundedVars().intersect(restvars()).intersect(varsToSolve);
1861 if (boundedVars.isEmpty()) {
1862 throw inferenceException.setMessage("cyclic.inference",
1863 freeVarsIn(varsToSolve));
1864 }
1865 solve(new BestLeafSolver(boundedVars) {
1866 public boolean done() { 2058 public boolean done() {
1867 return instvars().intersect(varsToSolve).nonEmpty(); 2059 return instvars().intersect(varsToSolve).nonEmpty();
1868 } 2060 }
1869 }, warn); 2061 }, optDeps, warn);
1870 } 2062 }
1871 2063
1872 /** 2064 /**
1873 * Apply a set of inference steps 2065 * Apply a set of inference steps
1874 */ 2066 */

mercurial