Skip to content

Commit 6894bfa

Browse files
Combined inference improvements (#5129)
Align inference resolution with javac by applying hints from Maurizio See https://mail.openjdk.org/archives/list/compiler-dev@openjdk.org/message/GN6RTCGMME6I5JVLSFZRIR32XY6QKOI2/ + rank ivars for processing in smaller batches + remove our own tweak from commit ad3653e Make most ivar-ivar dependencies bidirectional (see also next) Opportunistically fine tune usage of same bounds: + only during regular inference: + record inverse of same-bounds for use by rankIVar() + only during record pattern inference: + workaround for inverse same-bounds in rankIVar() Reacting to failure: + propagate failures during resolution of capture bounds + let unsuccessful glb proceed to 2nd attempt rather than failing Improve "softness" of type bounds: + opportunistically mark constraints from capture bounds "soft" to refix - GenericsRegressionTest.test434118 - GenericsRegressionTest_9.testIssue4864 + more propagation of isSoft flag (for consistency) + Revert part of commit dd34c06 from #4635: ARGUMENT_CONSTRAINTS_ARE_SOFT is back to false as recommended Minor fixes here and there run.javac improvements: + more documentation for JavacHasABug.JavacBug6573446 + new constant JavacHasABug.JavacBugIvarInterning + new constant JavacHasABug.JavacBug8297428 At this point GenericsRegressionTest_9 is ready to opt in to this mode Fixed and new tests: + #4937 + #3351 For individual commits see #5129
1 parent 8908c4c commit 6894bfa

4 files changed

Lines changed: 213 additions & 89 deletions

File tree

org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ else if (type.hasNullTypeAnnotations())
315315
* <dl>
316316
* <dt>captures<dd>IC18.resumeSuspendedInference() will reset these to avoid captures from nested
317317
* inference spilling blindly into the current inference.<br>
318-
* {@link InferenceContext18#collectDependencies(BoundSet, boolean, boolean[])} considers only "local" {@link #captures}.
318+
* {@link InferenceContext18#collectDependencies(BoundSet)} considers only "local" {@link #captures}.
319319
* <dt>allCaptures<dd>Still {@link #hasCaptureBound(Set)} and {@link #incorporate(InferenceContext18)} will
320320
* operate on {@link #allCaptures}.
321321
*/
@@ -327,6 +327,7 @@ else if (type.hasNullTypeAnnotations())
327327
private TypeBound[] unincorporatedBounds = new TypeBound[8];
328328
private int unincorporatedBoundsCount = 0;
329329
private final TypeBound[] mostRecentBounds = new TypeBound[4]; // for quick & dirty duplicate elimination
330+
public boolean isRecordPatternInference;
330331

331332
public BoundSet() {}
332333

@@ -427,12 +428,17 @@ else if (boundNullBits != 0) // combine bits from both sources, even if this cre
427428
three.setInstantiation(typeBinding, variable, environment);
428429
if (bound.right instanceof InferenceVariable) {
429430
// for a dependency between two IVs make a note about the inverse bound.
430-
// this should be needed to determine IV dependencies independent of direction.
431-
// TODO: so far no test could be identified which actually needs it ...
432-
InferenceVariable rightIV = (InferenceVariable) bound.right.prototype();
433-
three = this.boundsPerVariable.get(rightIV);
434-
if (three == null)
435-
this.boundsPerVariable.put(rightIV, (three = new ThreeSets()));
431+
int relation = switch (bound.relation) {
432+
case ReductionResult.SUBTYPE -> ReductionResult.SUPERTYPE;
433+
case ReductionResult.SUPERTYPE -> ReductionResult.SUBTYPE;
434+
case ReductionResult.SAME -> this.isRecordPatternInference ? -1 : ReductionResult.SAME;
435+
default -> -1;
436+
};
437+
if (relation != -1) {
438+
InferenceVariable rightIV = (InferenceVariable) bound.right.prototype();
439+
three = this.boundsPerVariable.computeIfAbsent(rightIV, k -> new ThreeSets());
440+
three.addBound(new TypeBound(rightIV, bound.left, relation, bound.isSoft));
441+
}
436442
}
437443
}
438444
}
@@ -696,7 +702,10 @@ protected TypeBinding getP(int i) {
696702
System.arraycopy(otherBounds, 0, allBounds, 1, n-1);
697703
bi = context.environment.createIntersectionType18(allBounds);
698704
}
699-
if (addTypeBoundsFromWildcardBound(context, theta, wildcardBinding.boundKind, t, r, bi))
705+
ReductionResult result = addTypeBoundsFromWildcardBound(context, theta, wildcardBinding.boundKind, t, r, bi);
706+
if (result == ReductionResult.FALSE)
707+
return false;
708+
else if (result == ReductionResult.TRUE)
700709
capturesToRemove.add(gAlpha);
701710
}
702711
}
@@ -709,7 +718,8 @@ protected TypeBinding getP(int i) {
709718
TypeBound bound = it.next();
710719
if (!(bound.right instanceof InferenceVariable)) {
711720
if (wildcardBinding.boundKind == Wildcard.SUPER) {
712-
reduceOneConstraint(context, ConstraintTypeFormula.create(bound.right, t, ReductionResult.SUBTYPE));
721+
if (!reduceOneConstraint(context, ConstraintTypeFormula.create(bound.right, t, ReductionResult.SUBTYPE)))
722+
return false;
713723
capturesToRemove.add(gAlpha);
714724
} else {
715725
return false;
@@ -739,23 +749,24 @@ protected TypeBinding getP(int i) {
739749
}
740750

741751
// try to infer and reduce a new constraint based on details of a given capture bound
742-
// return true iff a new constraint has been added indeed
743-
boolean addTypeBoundsFromWildcardBound(InferenceContext18 context, InferenceSubstitution theta, int boundKind, TypeBinding t,
752+
// return TRUE or FALSE iff a new constraint has been added indeed
753+
ReductionResult addTypeBoundsFromWildcardBound(InferenceContext18 context, InferenceSubstitution theta, int boundKind, TypeBinding t,
744754
TypeBinding r, TypeBinding bi) throws InferenceFailureException {
745755
ConstraintFormula formula = null;
746756
if (boundKind == Wildcard.EXTENDS) {
747757
if (bi.id == TypeIds.T_JavaLangObject)
748-
formula = ConstraintTypeFormula.create(t, r, ReductionResult.SUBTYPE);
758+
formula = ConstraintTypeFormula.create(t, r, ReductionResult.SUBTYPE, true);
749759
if (t.id == TypeIds.T_JavaLangObject)
750-
formula = ConstraintTypeFormula.create(theta.substitute(theta, bi), r, ReductionResult.SUBTYPE);
760+
formula = ConstraintTypeFormula.create(theta.substitute(theta, bi), r, ReductionResult.SUBTYPE, true);
751761
} else {
752-
formula = ConstraintTypeFormula.create(theta.substitute(theta, bi), r, ReductionResult.SUBTYPE);
762+
formula = ConstraintTypeFormula.create(theta.substitute(theta, bi), r, ReductionResult.SUBTYPE, true);
753763
}
754764
if (formula != null) {
755-
reduceOneConstraint(context, formula);
756-
return true;
765+
if (!reduceOneConstraint(context, formula))
766+
return ReductionResult.FALSE;
767+
return ReductionResult.TRUE;
757768
}
758-
return false;
769+
return null;
759770
}
760771

761772
private ConstraintTypeFormula combineSameSame(TypeBound boundS, TypeBound boundT, Map<InferenceVariable,TypeBound> properTypesByInferenceVariable) {
@@ -881,7 +892,7 @@ private ConstraintTypeFormula combineEqualSupers(TypeBound boundS, TypeBound bou
881892
innerSame = true; // came in as: S REL α and α REL T imply ⟨S REL T⟩
882893
if (outerSame) {
883894
if (innerSame) // NON-JLS bidirectional subtyping implies equality:
884-
return ConstraintTypeFormula.create(boundS.left, boundS.right, ReductionResult.SAME, false);
895+
return ConstraintTypeFormula.create(boundS.left, boundS.right, ReductionResult.SAME, boundT.isSoft||boundS.isSoft);
885896
return ConstraintTypeFormula.create(boundT.left, boundS.right, boundS.relation, boundT.isSoft||boundS.isSoft);
886897
} else if (innerSame) {
887898
return ConstraintTypeFormula.create(boundS.left, boundT.right, boundS.relation, boundT.isSoft||boundS.isSoft);
@@ -1082,6 +1093,32 @@ public boolean hasOnlyTrivialExceptionBounds(InferenceVariable variable, TypeBin
10821093
return true;
10831094
}
10841095

1096+
public int rankIVar(InferenceVariable ivar) {
1097+
// implements the ranking of ivars according to their bounds as explained in
1098+
// https://mail.openjdk.org/archives/list/compiler-dev@openjdk.org/message/GN6RTCGMME6I5JVLSFZRIR32XY6QKOI2/
1099+
ThreeSets three = this.boundsPerVariable.get(ivar.prototype());
1100+
if (three != null) {
1101+
if (three.sameBounds != null)
1102+
if (!three.sameBounds.isEmpty())
1103+
return 1;
1104+
if (this.isRecordPatternInference) {
1105+
// workaround for not having inverse bounds of type SAME (see addBound(TypeBound, LookupEnvironment)):
1106+
for (ThreeSets dep3 : this.boundsPerVariable.values()) {
1107+
if (dep3 != null && dep3.sameBounds != null) {
1108+
for (TypeBound depBound : dep3.sameBounds) {
1109+
if (depBound.right.equals(ivar))
1110+
return 1;
1111+
}
1112+
}
1113+
}
1114+
}
1115+
if (three.superBounds != null)
1116+
if (!three.superBounds.isEmpty())
1117+
return 2;
1118+
}
1119+
return 3;
1120+
}
1121+
10851122
/**
10861123
* JLS 18.1.3:
10871124
* Answer all upper bounds for the given inference variable as defined by any bounds in this set.

0 commit comments

Comments
 (0)