Quantcast

spec clarification: wildcard array element signature

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

spec clarification: wildcard array element signature

Liam Miller-Cushon
When javac compiles the following program, it writes field i's signature as "LA<[*>.I;".

I don't think the grammar in JVMS 4.7.9.1 allows for the element type of an array to be a wildcard. Is that a spec bug?

class A<X> { class I {} }
class Test {
  class B<Y> extends A<Y[]> {}
  B<?>.I i;
}
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: spec clarification: wildcard array element signature

Alex Buckley-3
First, I don't know why javac is denoting the type of i using A rather
than B, both in the field descriptor and in the Signature attribute. The
field descriptor is specified in JLS8 13.1 as containing "a symbolic
reference to the erasure of the type of the field". Plainly this is
LB$I, and Signature would follow suit.

Second, there is nothing in JLS8 8.1.2 to deny B<?>'s supertype being
A<?[]>, so to speak. But it was never envisaged in JVMS8 4.7.9.1 that
there would be a type parameterized by "array of wildcards". This may be
due to the trickiness of Signature having multiple roles: it reifies
generic type information like B<Y> (where array types are not permitted
as type parameters) in addition to parameterized type information like
A<Y[]> (where array types are permitted as type arguments).

Third, on JDK 9b140, javac crashes if the declaration of i uses a
bounded wildcard for B's type argument -- say B<? extends Number>.I

java.lang.ClassCastException:
com.sun.tools.javac.code.Type$TypeMapping$3 (in module: jdk.compiler)
cannot be cast to
com.sun.tools.javac.code.Type$WildcardType (in module: jdk.compiler)
at
com.sun.tools.javac.comp.Attr$TypeAnnotationsValidator.validateAnnotatedType(jdk.compiler@9-ea/Attr.java:4804)

Looking for others to comment.

Alex

On 10/22/2016 8:15 PM, Liam Miller-Cushon wrote:

> When javac compiles the following program, it writes field i's signature
> as "LA<[*>.I;".
>
> I don't think the grammar in JVMS 4.7.9.1 allows for the element type of
> an array to be a wildcard. Is that a spec bug?
>
> class A<X> { class I {} }
> class Test {
>    class B<Y> extends A<Y[]> {}
>    B<?>.I i;
> }
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: spec clarification: wildcard array element signature

Maurizio Cimadamore


On 24/10/16 19:28, Alex Buckley wrote:
> First, I don't know why javac is denoting the type of i using A rather
> than B, both in the field descriptor and in the Signature attribute.
> The field descriptor is specified in JLS8 13.1 as containing "a
> symbolic reference to the erasure of the type of the field". Plainly
> this is LB$I, and Signature would follow suit.
I think this is coming from this rule (13.1):

"The binary name of a member type (§8.5, §9.5) consists of the binary
name of its immediately enclosing type, followed by $, followed by the
simple name of the member."

The rule speaks about 'enclosing type' hence A being used instead of B I
believe. But that counts for the descriptor.

As for the contents of the signature attributes, my feeling is that the
signature attribute attempts to 'augment' the information that's
available in the descriptor, not completely replace it. I think having,
say, Field.getType return A, but Field.getGenericType return
B<something> would be a little weird, I believe. Other compilers such as
ecj seem to be doing the exact same thing in this respect.

>
> Second, there is nothing in JLS8 8.1.2 to deny B<?>'s supertype being
> A<?[]>, so to speak. But it was never envisaged in JVMS8 4.7.9.1 that
> there would be a type parameterized by "array of wildcards". This may
> be due to the trickiness of Signature having multiple roles: it
> reifies generic type information like B<Y> (where array types are not
> permitted as type parameters) in addition to parameterized type
> information like A<Y[]> (where array types are permitted as type
> arguments).
Right - this is not explicitly disallowed - but it seems in contrast to
the rules for computing the supertype of a generic class: the supertype
of B<?> is not A<?[]> but A<#CAP[]>, where #CAP <: Object. I believe
keeping wildcards open in the bytecode (which is something ecj does too)
might result in unsoundness? Presence of arrays here is largely
irrelevant - if the supertype was just A<Y> wouldn't still be
problematic to use A<?> as the field type?

At the same time, there's no representation at the bytecode level for
captured variables, so there's not much that can be done in that space.

>
> Third, on JDK 9b140, javac crashes if the declaration of i uses a
> bounded wildcard for B's type argument -- say B<? extends Number>.I
>
> java.lang.ClassCastException:
> com.sun.tools.javac.code.Type$TypeMapping$3 (in module: jdk.compiler)
> cannot be cast to
> com.sun.tools.javac.code.Type$WildcardType (in module: jdk.compiler)
> at
> com.sun.tools.javac.comp.Attr$TypeAnnotationsValidator.validateAnnotatedType(jdk.compiler@9-ea/Attr.java:4804)
This is a bug - I've also been able to reproduce on JDK 8.

Regarding the other issue about wildcards being replaced in supertypes,
I think there are two options - none of which is particularly appealing:

* fix javac (and other compilers) so that the signature attribute only
speaks about types in the source code, w/o attempting to do any
membership computation - this should ensure that non-denotable types
should not crop up in the process - unfortunately, doing so will change
the signature attribute of real code out there - and the compatibility
impact potentially large (the difference will be visible in core
reflection).

* keep javac as is - live with 'weird' signatures and plug resulting
soundness issues (esp. around separate compilation) ?

Maurizio

>
> Looking for others to comment.
>
> Alex
>
> On 10/22/2016 8:15 PM, Liam Miller-Cushon wrote:
>> When javac compiles the following program, it writes field i's signature
>> as "LA<[*>.I;".
>>
>> I don't think the grammar in JVMS 4.7.9.1 allows for the element type of
>> an array to be a wildcard. Is that a spec bug?
>>
>> class A<X> { class I {} }
>> class Test {
>>    class B<Y> extends A<Y[]> {}
>>    B<?>.I i;
>> }

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: spec clarification: wildcard array element signature

Srikanth
In reply to this post by Liam Miller-Cushon
> Alex Buckley [hidden email]
> Mon Oct 24 18:28:28 UTC 2016

>Third, on JDK 9b140, javac crashes if the declaration of i uses a 
>bounded wildcard for B's type argument -- say B<? extends Number>.I

>java.lang.ClassCastException:
>com.sun.tools.javac.code.Type$TypeMapping$3 (in module: jdk.compiler)
>cannot be cast to
>com.sun.tools.javac.code.Type$WildcardType (in module: jdk.compiler) at 
>com.sun.tools.javac.comp.Attr$TypeAnnotationsValidator.validateAnnotatedType(jdk.compiler at 9-ea/Attr.java:4804)

I have raised https://bugs.openjdk.java.net/browse/JDK-8168760

Thanks!
Srikanth

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: spec clarification: wildcard array element signature

Alex Buckley-3
In reply to this post by Liam Miller-Cushon
On 10/22/2016 8:15 PM, Liam Miller-Cushon wrote:

> When javac compiles the following program, it writes field i's signature
> as "LA<[*>.I;".
>
> I don't think the grammar in JVMS 4.7.9.1 allows for the element type of
> an array to be a wildcard. Is that a spec bug?
>
> class A<X> { class I {} }
> class Test {
>    class B<Y> extends A<Y[]> {}
>    B<?>.I i;
> }

Liam, are you calling Field.getGenericType() on i and getting a
surprising result, perhaps a ParameterizedType whose
getActualTypeArguments() blows up?

Alex
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: spec clarification: wildcard array element signature

Liam Miller-Cushon
On Wed, Nov 2, 2016 at 2:28 PM, Alex Buckley <[hidden email]> wrote:
Liam, are you calling Field.getGenericType() on i and getting a surprising result, perhaps a ParameterizedType whose getActualTypeArguments() blows up?

I noticed this because it crashes ASM [1], not because of an issue with reflection. But accessing it reflectively as you describe does blow up:

((ParameterizedType) Test.class.getField("i").getGenericType()).getActualTypeArguments()
...
GenericSignatureFormatError: Signature Parse error: Expected Field Type Signature
Remaining input: *>.I;
at sun.reflect.generics.parser.SignatureParser.error(SignatureParser.java:124)
at sun.reflect.generics.parser.SignatureParser.parseFieldTypeSignature(SignatureParser.java:297)

If you're interested in pursuing the first option Maurizio described, I'd be happy to help assess the compatibility impact on our code.

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: spec clarification: wildcard array element signature

Alex Buckley-3
In reply to this post by Maurizio Cimadamore
On 10/24/2016 2:35 PM, Maurizio Cimadamore wrote:

> On 24/10/16 19:28, Alex Buckley wrote:
> Regarding the other issue about wildcards being replaced in supertypes,
> I think there are two options - none of which is particularly appealing:
>
> 1. fix javac (and other compilers) so that the signature attribute only
> speaks about types in the source code, w/o attempting to do any
> membership computation - this should ensure that non-denotable types
> should not crop up in the process - unfortunately, doing so will change
> the signature attribute of real code out there - and the compatibility
> impact potentially large (the difference will be visible in core
> reflection).

The Signature attribute, in particular a class type signature (JVMS8
4.7.9.1), is defined in terms of binary names, as alluded to by your
comment about Field.getGenericType aligning with Field.getType.

Therefore, Signature must be able to encode  A<?[]>.I  (so to speak)
rather than the  B<?>.I  type literally found in source code.

That means rejecting option 1, and choosing option 2:

> 2. keep javac as is - live with 'weird' signatures and plug resulting
> soundness issues (esp. around separate compilation) ?

Which means a change to the JVMS TypeArgument production, and
corresponding enhancement to ParameterizedType.getActualTypeArguments()
[thanks Liam].

Dan, any objection to this?

Alex
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: spec clarification: wildcard array element signature

Alex Buckley-3
On 11/3/2016 4:24 PM, Alex Buckley wrote:

> Therefore, Signature must be able to encode  A<?[]>.I  (so to speak)
> rather than the  B<?>.I  type literally found in source code.
>
> That means rejecting option 1, and choosing option 2:
>
>> 2. keep javac as is - live with 'weird' signatures and plug resulting
>> soundness issues (esp. around separate compilation) ?
>
> Which means a change to the JVMS TypeArgument production, and
> corresponding enhancement to ParameterizedType.getActualTypeArguments()
> [thanks Liam].

Filed JDK-8172742 to track this issue post-9.

Alex
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: spec clarification: wildcard array element signature

Dan Smith-17
In reply to this post by Alex Buckley-3
> On Nov 3, 2016, at 5:24 PM, Alex Buckley <[hidden email]> wrote:
>
> On 10/24/2016 2:35 PM, Maurizio Cimadamore wrote:
>> On 24/10/16 19:28, Alex Buckley wrote:
>> Regarding the other issue about wildcards being replaced in supertypes,
>> I think there are two options - none of which is particularly appealing:
>>
>> 1. fix javac (and other compilers) so that the signature attribute only
>> speaks about types in the source code, w/o attempting to do any
>> membership computation - this should ensure that non-denotable types
>> should not crop up in the process - unfortunately, doing so will change
>> the signature attribute of real code out there - and the compatibility
>> impact potentially large (the difference will be visible in core
>> reflection).
>
> The Signature attribute, in particular a class type signature (JVMS8 4.7.9.1), is defined in terms of binary names, as alluded to by your comment about Field.getGenericType aligning with Field.getType.
>
> Therefore, Signature must be able to encode  A<?[]>.I  (so to speak) rather than the  B<?>.I  type literally found in source code.
>
> That means rejecting option 1, and choosing option 2:
>
>> 2. keep javac as is - live with 'weird' signatures and plug resulting
>> soundness issues (esp. around separate compilation) ?
>
> Which means a change to the JVMS TypeArgument production, and corresponding enhancement to ParameterizedType.getActualTypeArguments() [thanks Liam].
>
> Dan, any objection to this?

Sorry, didn't see this originally, thanks for pointing me to it.

Yes, I object! "?[]" is not a type. It's meaningless.

It is always wrong to perform substitutions that replace type variables with wildcards. javac has a history of doing so, and those cases need to be fixed. The compiler's internal representation of wildcards should not even allow such an attempt at substitution to compile (e.g., a class Wildcard should not extend a class Type), but alas, we have a lot of legacy violating this rule.

Liam's program raises issues related to two existing spec bugs:
JDK-8030746: 4.10: Define subtyping for inner classes of parameterized types
JDK-8016196: Inference: define supertype parameterization for wildcard-parameterized types

These are part of our type system cleanup effort; when addressed, we'll have a clear answer for how to interpret "B<?>.I" and, thus, how to record it in bytecode. (Preview: the answer is probably "A<? extends Object[]>.I".)

Suggest closing JDK-8172742 as "Not an Issue"—the JVMS grammar is fine.

—Dan
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: spec clarification: wildcard array element signature

Alex Buckley-3
On 2/7/2017 10:54 AM, Dan Smith wrote:
> Yes, I object! "?[]" is not a type. It's meaningless.
>
> It is always wrong to perform substitutions that replace type
> variables with wildcards. javac has a history of doing so, and those
> cases need to be fixed. The compiler's internal representation of
> wildcards should not even allow such an attempt at substitution to
> compile (e.g., a class Wildcard should not extend a class Type), but
> alas, we have a lot of legacy violating this rule.

Am I right to say that this is what javac is doing in the recent snipper
from Stephan Herrmann? :-

---
public class Bug494198<T> { class Inner<U> {...} }

Bug494198<?> outer = ...
... outer.new Inner<String>() {...}

final class Bug494198$1
   extends ***Bug494198<<captured wildcard>>***.Inner<java.lang.String>
---

> Liam's program raises issues related to two existing spec bugs:
> JDK-8030746: 4.10: Define subtyping for inner classes of
> parameterized types JDK-8016196: Inference: define supertype
> parameterization for wildcard-parameterized types
>
> These are part of our type system cleanup effort; when addressed,
> we'll have a clear answer for how to interpret "B<?>.I" and, thus,
> how to record it in bytecode. (Preview: the answer is probably "A<?
> extends Object[]>.I".)
>
> Suggest closing JDK-8172742 as "Not an Issue"—the JVMS grammar is
> fine.

OK -- please close it with an explanation for Liam and Stephan's benefit.

Alex
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: spec clarification: wildcard array element signature

Dan Smith-17

> On Feb 7, 2017, at 12:38 PM, Alex Buckley <[hidden email]> wrote:
>
> On 2/7/2017 10:54 AM, Dan Smith wrote:
>> Yes, I object! "?[]" is not a type. It's meaningless.
>>
>> It is always wrong to perform substitutions that replace type
>> variables with wildcards. javac has a history of doing so, and those
>> cases need to be fixed. The compiler's internal representation of
>> wildcards should not even allow such an attempt at substitution to
>> compile (e.g., a class Wildcard should not extend a class Type), but
>> alas, we have a lot of legacy violating this rule.
>
> Am I right to say that this is what javac is doing in the recent snipper from Stephan Herrmann? :-
>
> ---
> public class Bug494198<T> { class Inner<U> {...} }
>
> Bug494198<?> outer = ...
> ... outer.new Inner<String>() {...}
>
> final class Bug494198$1
>  extends ***Bug494198<<captured wildcard>>***.Inner<java.lang.String>
> ---

Yep, same issue. Odd that javac uses capture in this case while using a wildcard in the other case, but it comes down to the same lack of a spec.

>> Liam's program raises issues related to two existing spec bugs:
>> JDK-8030746: 4.10: Define subtyping for inner classes of
>> parameterized types JDK-8016196: Inference: define supertype
>> parameterization for wildcard-parameterized types
>>
>> These are part of our type system cleanup effort; when addressed,
>> we'll have a clear answer for how to interpret "B<?>.I" and, thus,
>> how to record it in bytecode. (Preview: the answer is probably "A<?
>> extends Object[]>.I".)
>>
>> Suggest closing JDK-8172742 as "Not an Issue"—the JVMS grammar is
>> fine.
>
> OK -- please close it with an explanation for Liam and Stephan's benefit.

Done.

—Dan

Loading...