Unchecked conversion and super raw type

Alex Buckley alex.buckley at oracle.com
Fri Aug 23 15:46:25 PDT 2013


On second thoughts, this is a complicated mess.

foo(B) is applicable by subtyping and foo(A<String>) isn't. Since at 
least one method is applicable by subtyping, overload resolution should 
stop and foo(B) should be selected.

If overload resolution was to proceed to applicability by method 
invocation conversion, it would find that foo(A<String>) is applicable 
(as described earlier) and also that foo(B) is applicable (identity 
conversion) - but it's not meant to proceed!

So, javac is wrong to give an ambiguity. Or is it? In the pre-generics 
world - static class A {} ... void foo(A a) ... - JLS2 would have said 
that "foo(b)" was ambiguous because foo(A) and foo(B) were both 
applicable by method invocation conversion. Generifying the declaration 
of class A and parameterizing the formal parameter type A should not 
change that. And so, JLS3's two-stage applicability testing is 
inaccurate when it chooses foo(B) as The Answer.

Perhaps if I had a complete description of javac's overload resolution 
rules, I could make 15.12.2 reflect what really happens. Or maybe this 
whole idea of "migration compatibility" is just too hard.

Alex

On 8/23/2013 3:18 PM, Alex Buckley wrote:
> I am happy to report that JLS7 makes foo(A<String>) applicable by method
> invocation conversion (15.12.2.3), so javac is right to report an
> ambiguity.
>
> Method invocation conversion allows B to undergo a widening reference
> conversion to A, because B's direct supertype is A; and then, because A
> is a raw type, an unchecked conversion may be applied from A to A<String>.
>
> Alex
>
> On 4/12/2013 3:25 AM, Maurizio Cimadamore wrote:
>> The spec is saying:
>>
>> "The method m is applicable by subtyping if and only if both of the
>> following conditions hold:
>>
>> For 1 ≤ i ≤ n, either:
>>
>> Ai <: Si (§4.10), or
>>
>> Ai is convertible to some type Ci by unchecked conversion (§5.1.9), and
>> Ci <: Si."
>>
>>
>> And I agree this seems to be a spec problem - there's no unchecked
>> conversion for going from B to A<String>, as unchecked conversion
>> requires that source bases type and target nbae type are the same - in
>> this case we have that B != A so no unchecked conversion applies.
>>
>> However, javac (and Eclipse) implement a relaxed check; for example,
>> javac is happy whenever it can find a supertype of the LHS type that
>> matches the base type of the RHS. Which in this case is satisfied.
>>
>> Maurizio
>>
>>
>> On 11/04/13 23:40, Zhong Yu wrote:
>>>
>>>
>>>
>>> On Thu, Apr 11, 2013 at 5:10 PM, Zhong Yu <zhong.j.yu at gmail.com
>>> <mailto:zhong.j.yu at gmail.com>> wrote:
>>>
>>>     Consider this example:
>>>
>>>     public class Test
>>>     {
>>>         static class A<T> {}
>>>
>>>         static class B extends A {}
>>>
>>>         void foo(A<String> a) {}
>>>
>>>         void foo(B b) {}
>>>
>>>         void test()
>>>         {
>>>             B b = new B();
>>>             foo(b); // error: reference to foo is ambiguous
>>>         }
>>>     }
>>>
>>>     For the method invocation expression `foo(b)`, method `foo(B)` is
>>>     applicable by subtyping. However is that also true for
>>>     `foo(A<String>)`? By the letter of the spec, we cannot find a Ci
>>>     such that "B" is convertible to Ci by unchecked conversion and Ci
>>>     <: A<String>. So my understanding is that `foo(A<String>)` is not
>>>     applicable to `foo(b)` by subtyping, and the code should compile
>>>     since only one applicable method is found during "15.12.2.2.
>>> Phase 1"
>>>
>>>
>>>
>>> Or, is this a bug of the spec? Maybe the spec intends to say
>>>
>>> For 1 ≤ /i/ ≤ /n/, either:
>>>
>>>  *
>>>
>>>     A_i |<:| S_i (§4.10
>>>
>>> <http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.10>),
>>>     or
>>>
>>>  *
>>>
>>>     A_i |<:| |S_i |
>>>
>>> The second clause is for the legacy code that saw a non-generic method
>>> parameter type.
>>>
>>> Zhong Yu
>>>
>>


More information about the compiler-dev mailing list