unchecked conversion with self-referencing type parameter
Dan Smith
daniel.smith at oracle.com
Fri Jan 31 13:39:18 PST 2014
See this javac bug:
https://bugs.openjdk.java.net/browse/JDK-8026527
Per JLS, the program should not compile.
On Jan 30, 2014, at 4:29 PM, Rafkind, Jon <jon.rafkind at hp.com> wrote:
> On 01/30/2014 12:20 PM, Rafkind, Jon wrote:
>> In the following code javac warns that unchecked conversion was needed,
>> but my own type inference engine doesn't find a case where unchecked
>> conversion is possible.
>>
>> public class C<X>{
>> public <T extends C<T>> void foo(Class<T> c){
>> }
>>
>> public void test(){
>> Class<C> c = null;
>> foo(c);
>> // foo(C.class); // originally my test case was this, but its
>> the same as using 'c'
>> }
>> }
>>
>> Substitute 'a1' for T.
>>
>> Bounds: a1 <: C<a1>
>> Constraints: c -> Class<a1>
>>
>> reduce 'c -> Class<a1>'
>> 1. c -> Class<a1>
>> 2. Class<C> -> Class<a1>
>> // at this point I think unchecked conversion is needed as loose
>> constraints are the only place in the reduction process that mention
>> unchecked conversion
>> // but case 1 doesn't apply (Class<a1> is not proper), and case 4
>> doesn't apply because G = Class<a1>, S is already a form of G = Class<C>.
>> 3. Class<C> <: Class<a1>
>> 4. C <= a1
>> 5. C = a1
>>
>> add bound C = a1, infer the constraint 'C <: C<a1>' during incorporation.
>>
>> reduce 'C <: C<a1>'
>> 1. C <: C<a1>
>> fail, because C<a1> is a parameterized type but there is no super type
>> of C that is a parameterized type of C
>>
>
> I think the mistake I made is during incorporation, the new bound should
> have been 'C <: C<C>' which succeeds with unchecked conversion for the
> subtype constraint. If the rule 'a = U and S <: T' matches before 'a = S
> and a <: T' this is possible. The rules for incorporation (18.3) need to
> be changed slightly to allow for this outcome, however.
Yes, I imagine javac is doing something like this in order to succeed in compilation. But bounds of the form "T extends Foo<Bar>" are not meant to allow unchecked conversion, and it is incorrect to treat them that way.
> 1. The process doesn't explicitly say only one rule should match, just
> that 'for any pair of bounds matching one of the rules'. I can see the
> meaning go either way, but I originally took this to mean match as many
> rules as possible.
Yes, it's a loop -- while some pair of bounds matches a rule, apply the rule; repeat until no pair of bounds can produce a new bound.
> 2. Supposing only one rule should match it is not clear that the 'a = U
> ...' rules should match before the 'a = S' rules. So the ordering of the
> rules should put 'a = U' at the top. Probably the process should be
> explicit about matching in the order they are given as well.
>
> Alternatively, S and T could be types that must contain inference
> variables while U must be a proper type. I understood 'S and T are
> inference variables or types' to mean they can be any kind of type.
Yes, they are meant to include any kind of type.
—Dan
More information about the lambda-spec-observers
mailing list