resolving several ivars to the same capture?

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Thu Oct 23 10:45:20 UTC 2025


On 23/10/2025 11:25, Stephan Herrmann wrote:

> Hi Maurizio
>
> thanks for taking the time.
>
> Am 22.10.25 um 12:05 schrieb Maurizio Cimadamore:
>> first, I'll note that this issue seems dangerously close to this open 
>> spec issue:
>>
>> https://bugs.openjdk.org/browse/JDK-8016196 
>
> In this particular issue I'm puzzled by this statement:
>
> "The correct behavior is unspecified: what is the parameterization of 
> List that is a supertype of ArrayList<?>? How do we derive it?"
>
> Doesn't 4.10.2 clearly state that type arguments should be captured here?

Yes, but that means that we will generate “spurious” capture variables 
during inference which will end up in the result. Depending on the case, 
this might result in failures.

Dan (CC’ed) might add more details.

>> We have other examples where applying capture conversion during 
>> incorporation this way leads to issues:
>>
>> https://bugs.openjdk.org/browse/JDK-8206142 
>
> The issue states that rejecting the example is a regression (in 9). 
> FWIW, ecj accepts the example ever since Java 1.8. Seeing that a fix 
> for javac exists for many years, why is that fix not applied? Is this 
> an indication that perhaps JLS is to be changed rather than javac?
IIRC, we realized that this is a case where we’re doomed no matter what 
we do. When running that fix through our tests we got some compatibility 
issues, so in general we were skeptical of applying it w/o having some 
kind of spec coverage.
>
> What do you recommend for the current issue? Is it OK for ecj to 
> accept the program, and if people complain about the difference to 
> javac, explain that this is a bug in javac? Or are there any fine 
> points in the spec which we are missing, that justify rejecting?

If this is indeed connected to the spec issue I mentioned above, then 
I’d say that it’s sad but also sort of ok for the compilers to diverge, 
given that a “real” fix will in reality be a lot more convoluted than 
just applying capture.

>
>> (That said, I would have expected javac to perform a capture there -- 
>> @Vicente, when you have time, can you please take a look and see why 
>> javac is not capturing?)
>
> OK, I might just wait for Vicente's answer here :)

Ok.

Thanks
Maurizio

>
> thanks,
> Stephan
>> Thanks
>> Maurizio
>>
>> On 21/10/2025 20:26, Stephan Herrmann wrote:
>>> Once more, I have a bunch of tests on my desk where javac and ecj 
>>> disagree.
>>>
>>> The pending fix for one case, makes ecj accept the following 
>>> program, which is rejected by javac:
>>>
>>> //---
>>> import java.util.function.Function;
>>> public class Test {
>>>     public static void main(String[] args) {
>>>         C<B<?>> c = null;
>>>         m(
>>>                 _ -> new A<>(c),
>>>                 b -> b.intValue());
>>>     }
>>>     static <T, R> void m(Function<B<Number>, A<T>> f1, Function<T, 
>>> R> f2) {}
>>>     static class A<U> {
>>>         public A(C<? extends C<U>> t) {}
>>>     }
>>>     private record B<V extends Number>(V t) implements C<V> {
>>>
>>>     }
>>>     private interface C<W> {
>>>         W t();
>>>     }
>>> }
>>> //---
>>>
>>> javac reports:
>>> Test.java:5: error: cannot infer type arguments for A<>
>>>                 _ -> new A<>((C<B<?>>) null),
>>>                      ^
>>>   reason: cannot infer type-variable(s) U
>>>     (argument mismatch; C<B<?>> cannot be converted to C<? extends 
>>> C<U>>)
>>>   where U is a type-variable:
>>>     U extends Object declared in class A
>>> Test.java:6: error: cannot find symbol
>>>                 b -> b.intValue());
>>>                       ^
>>>   symbol:   method intValue()
>>>   location: variable b of type Object
>>> 2 errors
>>>
>>>
>>> With my pending fix ecj would accept, with these details:
>>>
>>> Outer inference of m() yields:
>>>     T#0    :    capture#1-of ?
>>>     R#1    :    java.lang.Integer
>>>     U#3    :    capture#1-of ?
>>> so m() resolves as:
>>> void m(Function<B<Number>,A<capture#1-of ?>>, Function<capture#1-of 
>>> ?,Integer>)
>>>
>>> With target types Function<B<Number>,A<capture#1-of ?>> and 
>>> Function<capture#1-of ?,Integer> the two lambdas complete resolution 
>>> just fine.
>>>
>>>
>>> Am I missing any detail, why this inference solution is not valid?
>>>
>>>
>>> FYI, the pending fix relates to capturing while computing super 
>>> types of A<?>. While normally we ensure uniqueness of captures per 
>>> source location, when type inference requests a capture for 
>>> supertype computation we use the current invocation as the point of 
>>> reference, i.e., repeatedly capturing the same wildcard during one 
>>> invocation of type inference will share one unified capture. Is this 
>>> OK? Or what are the rules for uniqueness vs. unification in this case?
>>>
>>>
>>>
>>> thanks,
>>> Stephan
>
>
>
​
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/compiler-dev/attachments/20251023/d5b0c4ed/attachment-0001.htm>


More information about the compiler-dev mailing list