eclipse-jdt / eclipse-jdt/eclipse.jdt.core

Reconsider interning of capture bindings

Open
#2,419 16 comments 0 reactions 0 assignees View on GitHub
javac
Dominant language
Java
Stars
237
Forks
195
Avg merge
1d 12h
Merged PRs (30d)
47

Description

From #2321:

Consider this example:
```
class Test {
public void test() {
B b1 = new B<>();
B b2 = new B<>();
A> a = this::error; // This makes both B parameters use the same capture variable
}
public void error(B a, B b) {}
interface A {
void run(T t1, T t2);
}
class B {}
}
```
ecj accepts the assignment while javac rejects, saying:
```
error: incompatible types: invalid method reference
A> a = this::error; // This makes both B parameters use the same capture variable
^
method error in class Test cannot be applied to given types
required: Test.B,Test.B
found: Test.B,Test.B
reason: inference variable T has incompatible equality constraints CAP#1,CAP#2
where T is a type-variable:
T extends Object declared in method error(Test.B,Test.B)
where CAP#1,CAP#2 are fresh type-variables:
CAP#1 extends Object from capture of ?
CAP#2 extends Object from capture of ?
```

Debugging inference for this assignment I can see that descriptorParametersAsArgumentExpressions() answers twice the same type `B` in the position where javac seems to create two distinct captures.

ecj unifies both types because TypeSystem.getCapturedWildcard() is invoked twice with the exact same ingredients (same wildcard and same source positions), and so the capture is shared. Given that both parameter types originate from the same type variable `` this unification seems justified by common sense, but frankly this is not spelled out in JLS. [5.1.10. Capture Conversion](https://docs.oracle.com/javase/specs/jls/se22/html/jls-5.html#jls-5.1.10) unconditionally speaks of "a fresh type variable".

This "interning" was introduced in commit 2156fedd. When I disable it, I see the same two errors as reported by javac, but also regressions in:
* NegativeLambdaExpressionsTest.test432759()
* LambdaExpressionTest: test577466, testBug577719, testBug577719_2, testIssue2065
* GenericTypeTest:
* test0394, test0459, test0684, test0685, test0946, test1363, test426836, test434118
* this might actually improve: test0884 (see comment in the test)
* GenericsRegressionTest_1_8: testBug424710, testBug425798, testBug426836, testBug432110

To check:
* are those regressions actual failures, or perhaps some would align us better with javac?
* perhaps interning isn't bad per se but the fake arguments of a reference expression should still get distinct captures (although we don't have distinct source positions).

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.