LVTI: as per spec upward projection couldn't have resulted in a '? extends' parameterization
Georgiy Rakov
georgiy.rakov at oracle.com
Thu Oct 12 17:53:56 UTC 2017
Thanks for quick response and clarifications. Now two more questions are
presented below.
1) Let's consider the code from the original letter.
class C0 {}
class C1 extends C0 {}
class C2 extends C1 {}
public class Shell<T extends C1> {
void set(T t) {}
T get() {return null;}
public static void main(String args[]) {
Shell<? extends C0> y = new Shell<C1>();
var z = y; //upward projection is applied here
z = new Shell<C1>(); //compilation succeeds
z = new Shell<C2>(); //compilation succeeds
z = new C0(); //obviously compilation error
...
javac output following error message on line "z = new C0();":
Shell.java:16: error: incompatible types: C0 cannot be converted to
Shell<? extends C1>
z = new C0(); //obviously compilation error
According to this error message javac assumes type of 'z' to be Shell<?
extends C1>. It seems that this is at least a cosmetic defect since type
of 'z' is Shell<?> as it's been clarified.
Should a JBS issue be filed on javac for this reason?
2) The next question relates to further applying rules for calculation
of upward projection of Shell<CAP> presented in the original letter.
As it's been clarified the assertion (1) from [1] presented below
doesn't apply so we proceed to the the next assertion (2) from [1]:
(1) If U is not Object, and if either the declared bound of the ith
parameter of G, Bi, mentions a type parameter of G, or Bi is not a
subtype of U, then Ai' is an upper-bounded wildcard, ? extends U.
(2) Otherwise, if the downward projection of Ai is L, then Ai' is a
lower-bounded wildcard, ? super L.
(3) Otherwise, the downward projection of Ai is undefined and Ai' is
an unbounded wildcard, ?.
Which leads us to downward projection rules from [1]:
The downward projection of a type T with respect to a set of
restricted type variables is a partial function, defined as follows:
(4) If T does not mention any restricted type variable, then the
result is T.
(5) If T is a restricted type variable, then if T has a lower
bound, and if the downward projection of that bound is L, the result
is L; if T has no lower bound, or if the downward projection of that
bound is undefined, then the result is undefined.
Here T is 'CAP extends C1 super NULL_TYPE' as per capture conversion and
restricted type variable include just the same CAP.
Rule (4) doesn't apply so according to rule (5):
downward_projection(CAP) = downward_projection(NULL_TYPE) = NULL_TYPE,
NULL_TYPE doesn't mention any restricted type variable so downward
projection of NULL_TYPE is NULL_TYPE according to rule (4).
Thus rule (2) results in ? super NULL_TYPE.
Is this understand correctly that '? super NULL_TYPE' is effectively
equal to '?' (simple wildcard) because both of these wildcrads define
the same set of types since NULL_TYPE's super types are all reference
types and any reference type extends Object directly or not? According
to this reasoning it's rule (2) which makes
upward_projection(Shell<CAP>) to result in 'Shell<?>'. Is this correct?
If it is should spec be clarified on this because the reduction of '?
super NULL_TYPE' to '?' is not explicitly specified by JLS and it might
be not obvious that it's applied?
Or should spec just specify that the downward projection of NULL_TYPE is
undefined? In this case it would be rule (3) which would make
upward_projection(Shell<CAP>) to result in Shell<?>.
[1] http://cr.openjdk.java.net/~dlsmith/local-var-inference.html
Thank you,
Georgiy.
On 12.10.2017 2:09, Dan Smith wrote:
> Hey, thanks for careful testing of these rules. I'm sure they can use
> some scrutiny!
>
>> On Oct 11, 2017, at 9:57 AM, Georgiy Rakov <georgiy.rakov at oracle.com
>> <mailto:georgiy.rakov at oracle.com>> wrote:
>>
>> 4. Afterwards following assertion from [1] is touched:
>>
>> *If /U/ is not |Object|, and if either the declared bound of the
>> ith parameter of /G/, /Bi/, mentions a type parameter of /G/, or
>> /Bi/ is not a subtype of /U/, then /Ai'/ is an upper-bounded
>> wildcard, /|? extends| U/.*
>> **
>>
>> Here we have just B1 which is C1, so:
>> **a. "*/U/ is not |Object|*" is _true_ since U is C1;
>> b. "*the declared bound of the ith parameter of /G/, /Bi/, mentions a
>> type parameter of /G/*" is _false_ since B1 is C1 - no type
>> parameters are mentioned;
>> c. "*/Bi/ is not a subtype of /U/*" is _false_ because both B1 and U
>> are C1 so B1 is a subtype of U since a class is always a subtype of
>> itself.
>>
>> For this reason A1' cannot be defined by this assertion as ? extends
>> C1 which would make upward projection to result in Shell<? extends
>> C1>, so none of other assertions can do either.
>
> You are right that this rule does not apply.
>
> What you are missing is that, per the subsequent rules, the type is
> Shell<?>
>
> Subsequently, all reads of 'z' have type
> capture(Shell<?>) = Shell<CAP> where CAP extends C1
>
> In other words, there is no need to mention C1 in the type, because it
> is implicit from the declaration-site bound of T in Shell.
>
>> It's not quite clear why "*/Bi/ is not a subtype of /U/*" was added
>> to the specification. Some examples clarifying this point would be
>> highly appreciated.
>
> Ideally, we'd like an upper bound and a lower bound:
> ? extends upward(Ai) super downward(Ai)
>
> However, wildcards aren't expressive enough to have both upper and
> lower bounds, so we have to pick one. The heuristic is: if the upper
> bound is "meaningful", use that. If the upper bound is not meaningful,
> use the lower bound instead (or nothing, if there is no lower bound).
> The definition of "meaningful" is, loosely, "something that may affect
> the upper bound of the capture of the result".
>
> If Bi is a subtype of of U, then U will not affect the upper bound of
> the capture of the result, because capture will just do a glb(Bi, U) = Bi.
>
> —Dan
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20171012/32a7ab26/attachment.html>
More information about the compiler-dev
mailing list