@@ -1408,19 +1408,15 @@ private void addDependencies(BoundSet boundSet, Set<InferenceVariable> variableS
14081408 }
14091409
14101410 private ConstraintFormula pickFromCycle (Set <ConstraintFormula > c ) {
1411- // Detail from 18.5.2 bullet 6.1
1412-
14131411 // Note on performance: this implementation could quite possibly be optimized a lot.
14141412 // However, we only *very rarely* reach here,
14151413 // so nobody should really be affected by the performance penalty paid here.
14161414
1417- // Note on spec conformance: the spec seems to require _all_ criteria (i)-(iv) to be fulfilled
1418- // with the sole exception of (iii), which should only be used, if _any_ constraints matching (i) & (ii)
1419- // also fulfill this condition.
1420- // Experiments, however, show that strict application of the above is prone to failing to pick any constraint,
1421- // causing non-termination of the algorithm.
1422- // Since that is not acceptable, I'm *interpreting* the spec to request a search for a constraint
1423- // that "best matches" the given conditions.
1415+ // from JLS 18.5.2.2 bullet 3.1 para 2:
1416+ //
1417+ // If this subset is empty, then there is a cycle (or cycles) in the graph of dependencies between constraints.
1418+ // In this case, the constraints in C that participate in a dependency cycle (or cycles) and
1419+ // do not depend on any constraints outside of the cycle (or cycles) are considered.
14241420
14251421 // collect all constraints participating in a cycle
14261422 HashMap <ConstraintFormula ,Set <ConstraintFormula >> dependencies = new HashMap <>();
@@ -1448,10 +1444,10 @@ private ConstraintFormula pickFromCycle(Set<ConstraintFormula> c) {
14481444 outside .removeAll (cycles );
14491445
14501446 Set <ConstraintFormula > candidatesII = new LinkedHashSet <>();
1451- // (i): participates in a cycle:
1447+ // participates in a cycle:
14521448 candidates : for (ConstraintFormula candidate : cycles ) {
14531449 Collection <InferenceVariable > infVars = candidate .inputVariables (this );
1454- // (ii) does not depend on any constraints outside the cycle
1450+ // does not depend on any constraints outside the cycle
14551451 for (ConstraintFormula out : outside ) {
14561452 if (dependsOn (infVars , out .outputVariables (this )))
14571453 continue candidates ;
@@ -1461,62 +1457,39 @@ private ConstraintFormula pickFromCycle(Set<ConstraintFormula> c) {
14611457 if (candidatesII .isEmpty ())
14621458 candidatesII = c ; // not spec'ed but needed to avoid returning null below, witness: java.util.stream.Collectors
14631459
1464- // tentatively: (iii) has the form ⟨Expression → T⟩
1465- Set <ConstraintFormula > candidatesIII = new LinkedHashSet <>();
1460+ // JLS cntd:
1461+ // A single constraint is selected from these considered constraints, as follows:
1462+ // * If any of the considered constraints have the form ‹Expression → T›, then
1463+ // the selected constraint is the considered constraint of this form that contains the expression
1464+ // to the left (§3.5) of the expression of every other considered constraint of this form.
1465+ int minStart = Integer .MAX_VALUE ;
1466+ ConstraintFormula leftMost = null ;
14661467 for (ConstraintFormula candidate : candidatesII ) {
1467- if (candidate instanceof ConstraintExpressionFormula )
1468- candidatesIII .add (candidate );
1469- }
1470- if (candidatesIII .isEmpty ()) {
1471- candidatesIII = candidatesII ; // no constraint fulfills (iii) -> ignore this condition
1472- } else { // candidatesIII contains all relevant constraints ⟨Expression → T⟩
1473- // (iv) contains an expression that appears to the left of the expression
1474- // of every other constraint satisfying the previous three requirements
1475-
1476- // collect containment info regarding all expressions in candidate constraints:
1477- // (a) find minimal enclosing expressions:
1478- Map <ConstraintExpressionFormula ,ConstraintExpressionFormula > expressionContainedBy = new LinkedHashMap <>();
1479- for (ConstraintFormula one : candidatesIII ) {
1480- ConstraintExpressionFormula oneCEF = (ConstraintExpressionFormula ) one ;
1481- Expression exprOne = oneCEF .left ;
1482- for (ConstraintFormula two : candidatesIII ) {
1483- if (one == two ) continue ;
1484- ConstraintExpressionFormula twoCEF = (ConstraintExpressionFormula ) two ;
1485- Expression exprTwo = twoCEF .left ;
1486- if (doesExpressionContain (exprOne , exprTwo )) {
1487- ConstraintExpressionFormula previous = expressionContainedBy .get (two );
1488- if (previous == null || doesExpressionContain (previous .left , exprOne )) // only if improving
1489- expressionContainedBy .put (twoCEF , oneCEF );
1490- }
1491- }
1492- }
1493- // (b) build the tree from the above
1494- Map <ConstraintExpressionFormula ,Set <ConstraintExpressionFormula >> containmentForest = new LinkedHashMap <>();
1495- for (Map .Entry <ConstraintExpressionFormula , ConstraintExpressionFormula > parentRelation : expressionContainedBy .entrySet ()) {
1496- ConstraintExpressionFormula parent = parentRelation .getValue ();
1497- Set <ConstraintExpressionFormula > children = containmentForest .get (parent );
1498- if (children == null )
1499- containmentForest .put (parent , children = new LinkedHashSet <>());
1500- children .add (parentRelation .getKey ());
1468+ if (candidate instanceof ConstraintExpressionFormula cef && cef .left .sourceStart < minStart ) {
1469+ minStart = cef .left .sourceStart ;
1470+ leftMost = cef ;
15011471 }
1472+ }
1473+ if (leftMost != null )
1474+ return leftMost ;
15021475
1503- // approximate the spec by searching the largest containment tree:
1504- int bestRank = -1 ;
1505- ConstraintExpressionFormula candidate = null ;
1506- for (ConstraintExpressionFormula parent : containmentForest .keySet ()) {
1507- int rank = rankNode (parent , expressionContainedBy , containmentForest );
1508- if (rank > bestRank ) {
1509- bestRank = rank ;
1510- candidate = parent ;
1511- }
1476+ // JLS cntd:
1477+ // * If no considered constraint has the form ‹Expression → T›, then the selected constraint is the considered
1478+ // constraint that contains the expression to the left of the expression of every other considered constraint.
1479+ for (ConstraintFormula candidate : candidatesII ) {
1480+ // note: ConstraintExpressionFormula is the only shape left, which contains an expression
1481+ if (candidate instanceof ConstraintExceptionFormula cef && cef .left .sourceStart < minStart ) {
1482+ minStart = cef .left .sourceStart ;
1483+ leftMost = cef ;
15121484 }
1513- if (candidate != null )
1514- return candidate ;
15151485 }
1486+ if (leftMost != null )
1487+ return leftMost ;
15161488
1517- if (candidatesIII .isEmpty ())
1489+ // not spec'ed: random pick
1490+ if (candidatesII .isEmpty ())
15181491 throw new IllegalStateException ("cannot pick constraint from cyclic set" ); //$NON-NLS-1$
1519- return candidatesIII .iterator ().next ();
1492+ return candidatesII .iterator ().next ();
15201493 }
15211494
15221495 /**
@@ -1554,35 +1527,6 @@ private boolean isReachable(Map<ConstraintFormula,Set<ConstraintFormula>> deps,
15541527 return false ;
15551528 }
15561529
1557- /** Does exprOne lexically contain exprTwo? */
1558- private boolean doesExpressionContain (Expression exprOne , Expression exprTwo ) {
1559- if (exprTwo .sourceStart > exprOne .sourceStart ) {
1560- return exprTwo .sourceEnd <= exprOne .sourceEnd ;
1561- } else if (exprTwo .sourceStart == exprOne .sourceStart ) {
1562- return exprTwo .sourceEnd < exprOne .sourceEnd ;
1563- }
1564- return false ;
1565- }
1566-
1567- /** non-roots answer -1, roots answer the size of the spanned tree */
1568- private int rankNode (ConstraintExpressionFormula parent ,
1569- Map <ConstraintExpressionFormula ,ConstraintExpressionFormula > expressionContainedBy ,
1570- Map <ConstraintExpressionFormula , Set <ConstraintExpressionFormula >> containmentForest )
1571- {
1572- if (expressionContainedBy .get (parent ) != null )
1573- return -1 ; // not a root
1574- Set <ConstraintExpressionFormula > children = containmentForest .get (parent );
1575- if (children == null )
1576- return 1 ; // unconnected node or leaf
1577- int sum = 1 ;
1578- for (ConstraintExpressionFormula child : children ) {
1579- int cRank = rankNode (child , expressionContainedBy , containmentForest );
1580- if (cRank > 0 )
1581- sum += cRank ;
1582- }
1583- return sum ;
1584- }
1585-
15861530 private Set <ConstraintFormula > findBottomSet (Set <ConstraintFormula > constraints ,
15871531 Set <InferenceVariable > allOutputVariables , List <Set <InferenceVariable >> components )
15881532 {
0 commit comments