Skip to content

Commit 2875481

Browse files
ECJ vs Javac: Regression in Generic Type Inference (eclipse-jdt#4814)
Pragmatically handle equivalent exception ivars: + if one resolves to RuntimeException by special rule immediately incorporate to be able to propagate to equivalent ivars Fixes eclipse-jdt#4810
1 parent bb9d9eb commit 2875481

File tree

2 files changed

+48
-0
lines changed

2 files changed

+48
-0
lines changed

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,12 +1174,24 @@ public boolean reduceAndIncorporate(ConstraintFormula constraint) throws Inferen
11741174
final int numVars = variableSet.size();
11751175
if (numVars > 0) {
11761176
final InferenceVariable[] variables = variableSet.toArray(new InferenceVariable[numVars]);
1177+
// NON-JLS: prioritize ivars in 'inThrows' as those may pull in new information by extra rule below (=RuntimeException)
1178+
BoundSet tSet = tmpBoundSet;
1179+
Arrays.sort(variables, (v1, v2) -> {
1180+
int r1 = tSet.inThrows.contains(v1) ? -1 : 0;
1181+
int r2 = tSet.inThrows.contains(v2) ? -1 : 0;
1182+
return r1 - r2;
1183+
});
1184+
//
11771185
variables: if (!isRecordPatternTypeInference && !tmpBoundSet.hasCaptureBound(variableSet)) {
11781186
// try to instantiate this set of variables in a fresh copy of the bound set:
11791187
BoundSet prevBoundSet = tmpBoundSet;
11801188
tmpBoundSet = tmpBoundSet.copy();
11811189
for (int j = 0; j < variables.length; j++) {
11821190
InferenceVariable variable = variables[j];
1191+
if (tmpBoundSet.isInstantiated(variable)) { // NON-JLS: may happen when exception bound has been incorporated
1192+
toResolveSet.remove(variable);
1193+
continue;
1194+
}
11831195
// try lower bounds:
11841196
TypeBinding[] lowerBounds = tmpBoundSet.lowerBounds(variable, true/*onlyProper*/);
11851197
if (lowerBounds != Binding.NO_TYPES) {
@@ -1193,6 +1205,11 @@ public boolean reduceAndIncorporate(ConstraintFormula constraint) throws Inferen
11931205
if (tmpBoundSet.inThrows.contains(variable.prototype()) && tmpBoundSet.hasOnlyTrivialExceptionBounds(variable, upperBounds)) {
11941206
TypeBinding runtimeException = this.scope.getType(TypeConstants.JAVA_LANG_RUNTIMEEXCEPTION, 3);
11951207
tmpBoundSet.addBound(new TypeBound(variable, runtimeException, ReductionResult.SAME), this.environment);
1208+
// NON-JLS: propagate RuntimeException to equivalent ivars:
1209+
if (!tmpBoundSet.incorporate(this)) {
1210+
tmpBoundSet = prevBoundSet;// clean-up for second attempt
1211+
break variables;
1212+
}
11961213
} else {
11971214
// try upper bounds:
11981215
TypeBinding glb = this.object;

org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_9.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2003,6 +2003,37 @@ public interface SomeObject<T extends SomeType<?, L>, L extends SomeLocation, P
20032003
});
20042004
}
20052005

2006+
public void testGH4810() {
2007+
runConformTest(new String[] {
2008+
"Repro.java",
2009+
"""
2010+
import java.util.concurrent.Callable;
2011+
public class Repro {
2012+
Object test() {
2013+
try {
2014+
return myMethod(new MyCallable<>() {
2015+
@Override
2016+
public Object call() {
2017+
return new Object();
2018+
}
2019+
});
2020+
} catch (Exception e) {
2021+
e.printStackTrace();
2022+
return null;
2023+
}
2024+
}
2025+
<T, E extends Exception> T myMethod(MyCallable<T, E> callable) throws E {
2026+
return callable.call();
2027+
}
2028+
}
2029+
interface MyCallable<U, F extends Exception> extends Callable<U> {
2030+
@Override
2031+
U call() throws F;
2032+
}
2033+
"""
2034+
});
2035+
}
2036+
20062037
public static Class<GenericsRegressionTest_9> testClass() {
20072038
return GenericsRegressionTest_9.class;
20082039
}

0 commit comments

Comments
 (0)