Unchecked conversion and super raw type
Zhong Yu
zhong.j.yu at gmail.com
Fri Aug 23 23:12:07 PDT 2013
On Fri, Aug 23, 2013 at 5:46 PM, Alex Buckley <alex.buckley at oracle.com> wrote:
> 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 the conflict is that m2 is more specific than m1, yet m1 is "more
applicable" than m2, in the sense that m1 belongs to the 1st kind of
applicable methods. This is confusing to average programmers who
probably aren't aware that there are different kinds of applicable
methods. It might have been easier to consider all applicable methods
indiscriminately.
>
> 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