type_path of constructors for inner classes

Werner Dietl wdietl at gmail.com
Fri Oct 11 17:13:52 PDT 2013


Are you saying the correct annotations for the constructor of Inner would be:

    RuntimeVisibleTypeAnnotations:
      0: #16(#17=I#19): METHOD_RETURN
      1: #16(#17=I#18): METHOD_RETURN, location=[INNER_TYPE]
      2: #16(#17=I#19): METHOD_RECEIVER

That is, the @Annot(1) from the receiver appears again on the return
and the @Annot(0) appears on the return, with a location.
Or should we avoid this duplication and only keep 1 and 2, that is the
two explicit annotations?


> I'm not talking about 'new' at all. I say "type of the newly constructed
> object" to indicate the type to which a TYPE_USE annotation in front of a
> ctor declaration applies. I got the phrase from page 3 of
> java-annotation-design.pdf:

I find this wording in the design document rather unclear. Will this
appear in the JLS like this?


> You're saying that the "true" type of the newly constructed object at line 5
> is:
>
>   @Annot(1) Test . @Annot(0) Inner
>
> and I agree. So why aren't there two annotations for the METHOD_RETURN
> target of the ctor, one with a location clause? You'd expect _at least_ the
> @Annot(0) to be emitted with a location clause.

Expectations seem to be different and the JLS should be written in a
way to clarify this situation, imo.

cu, WMD.


On Fri, Oct 11, 2013 at 7:56 PM, Alex Buckley <alex.buckley at oracle.com> wrote:
> On 10/11/2013 4:22 PM, Werner Dietl wrote:
>>
>> when reading "type of the newly constructed object" it seems to me
>> like you're talking about an object creation - a "new" expression.
>> There is a "new Inner();", but there is no type annotation there. Are
>> you talking about line 7 or 5 in Joel's example?
>
>
> I'm not talking about 'new' at all. I say "type of the newly constructed
> object" to indicate the type to which a TYPE_USE annotation in front of a
> ctor declaration applies. I got the phrase from page 3 of
> java-annotation-design.pdf:
>
> "A type annotation is permitted in front of a constructor declaration, where
> declaration annotations are already permitted. In that location, a type
> annotation is treated as applying to the constructed object (which is
> different than the receiver, if any, of the constructor)."
>
>
>> If I change line 7 to
>>
>>      public @Annot(5) Inner foo(@Annot(55) Test.Inner Test.Inner.this)
>> { return new @Annot(555) Inner(); }
>>
>> And look at the generated bytecode, I see:
>>
>>        RuntimeVisibleTypeAnnotations:
>>          0: #16(#17=I#23): NEW, offset=0, location=[INNER_TYPE]
>>      RuntimeVisibleTypeAnnotations:
>>        0: #16(#17=I#24): METHOD_RETURN, location=[INNER_TYPE]
>>        1: #16(#17=I#25): METHOD_RECEIVER
>>
>> That behavior seems correct to me.
>
>
> Yes. Note that @Annot(5) on the return type is really "Test.Inner
> @Annot(5)", hence there's a location clause, whereas @Annot(55) on the
> receiver parameter's type is truly on the Test of "Test.Inner", so there's
> no location clause.
>
>
>> However, I think we were talking about the constructor result
>> annotations, that is, about line 5.
>> Do you consider the constructor name a simple type name?
>
>
> Yes. As a matter of interest, the only place that SimpleTypeName appears in
> the language grammar is ConstructorDeclarator.
>
>
>> In line 5:
>>
>> @Annot(0) Inner(@Annot(1) Test Test.this) {}
>>
>> It is not possible to make the outer type of the result explicit, that
>> is, one cannot write:
>>
>> @Annot(666) Test. at Annot(0) Inner(@Annot(1) Test Test.this) {}
>>
>> Therefore, @Annot(1) is the only possible annotation for outer type of
>> the constructor result.
>
>
> You're saying that the "true" type of the newly constructed object at line 5
> is:
>
>   @Annot(1) Test . @Annot(0) Inner
>
> and I agree. So why aren't there two annotations for the METHOD_RETURN
> target of the ctor, one with a location clause? You'd expect _at least_ the
> @Annot(0) to be emitted with a location clause.
>
>
>> In your last paragraph, you have:
>>
>>> Our thinking is that a ctor does not have a return type, so
>>> getReturnType()
>>> for a ctor's Executable really must give a NoType. Annotations on the
>>> ctor
>>> with target_type=0x14 ("return type of method, or type of newly
>>> constructed
>>> object") will be exposed on the NoType. It's not worth complicating with
>>> receiver annotations.
>>
>>
>> If the constructor result type is a NoType, wouldn't it be confusing
>> if it had a location in bytecode? To me the location INNER_TYPE would
>> only make sense if the result type were "@Anno(1) Test. @Anno(0)
>> Inner".
>> If we use NoType as the result type, I feel like the current behavior
>> of javac is correct.
>
>
> I see what you mean, but we're really talking about different things:
>
> - A compiler can emit a "true" nested type (@Annot(1) Test . @Annot(0)
> Inner) as the type of a newly constructed object, and Core Reflection should
> be able to deal with it - j.l.r.Constructor inherits
> getAnnotatedReturnType() from j.l.r.Executable, so we made that method
> understand that a ctor may be annotated with the type of the constructed
> object.
>
> - In the Language Model API, we give a NoType for a ctor's "return type"
> because in the JLS, a constructor does not have a return type. All you can
> do with the NoType is get its TYPE_USE annotations, which I would hope is
> @Annot(0). You can't distinguish between Test and Inner, but that's not a
> big deal because you're getting the annotation which was written at the
> appropriate location in the source code. An alternative would be to give a
> DeclaredType, since it would expose the "enclosing type" Test as distinct
> from Inner, but that would not be consistent with the JLS.
>
> Alex
>
>
>> Thoughts?
>> cu, WMD.
>>
>>
>>
>> On Fri, Oct 11, 2013 at 6:40 PM, Alex Buckley <alex.buckley at oracle.com>
>> wrote:
>>>
>>> On 10/11/2013 12:30 PM, Werner Dietl wrote:
>>>>
>>>>
>>>> The JSR 308 spec unfortunately doesn't make it clear what behavior is
>>>> required, so maybe it's best to raise the issue to the EG.
>>>
>>>
>>>
>>> When javac finds an annotation on the simple name of a nested type, it
>>> appears to first expand the simple name to a qualified name, and then
>>> describe the annotation with a target_path item. So, the @Annot(99)
>>> annotation in:
>>>
>>> class Test {
>>>    class Inner {}
>>>    void m(@Annot(99) Inner i) {}
>>> }
>>>
>>> is deemed to really be "Test. at Annot(99) Inner". A one-entry type_path
>>> structure is emitted as the target_path item, and javap renders it as
>>> "location=[INNER_TYPE]".
>>>
>>> That's all fine. The draft JLS/JVMS text for 308 - which I now regard as
>>> "the spec" - doesn't say that simple names must be expanded because
>>> that's
>>> the kind of thing compilers usually do automatically.
>>>
>>> In any case, I would have expected javac to treat the type of the newly
>>> constructed object as Test.Inner too, and place @Annot(0) in the same
>>> nested
>>> location. The type of the newly constructed object is just as much
>>> Test.Inner as with the i parameter in my m method above.
>>>
>>>
>>>> A constructor doesn't have a return type in the same sense as a method.
>>>> One cannot have annotations on type arguments or outer types on a
>>>> constructor result.
>>>> The spec says:
>>>>
>>>> "Outer class annotations for a constructor result must be identical to
>>>> those on the receiver, so they can be inferred from the annotations on
>>>> the receiver."
>>>>
>>>> So not having the location seems OK, because there is no possible
>>>> ambiguity.
>>>
>>>
>>>
>>> I have not transferred this "must be identical" clause to the spec
>>> because I
>>> don't know what it means. First, in a nested class declaration, you can't
>>> write the type of the constructor result, so you can't write outer class
>>> annotations. Second, when I see "must" in normative text, I look for the
>>> error to be given if the clause is violated, but no error is mandated
>>> here.
>>>
>>> Please supply two declarations, one which you think should give an error
>>> and
>>> one which should not.
>>>
>>>
>>>> The JavaDoc for javax.lang.model.type.ExecutableType.getReturnType()
>>>> currently says:
>>>>
>>>>        * Returns the return type of this executable.
>>>>        * Returns a {@link NoType} with kind {@link TypeKind#VOID VOID}
>>>>        * if this executable is not a method, or is a method that does
>>>> not
>>>>        * return a value."
>>>>
>>>> So I would assume that the result for an annotated constructor would be
>>>> an annotated NoType, containing only the annotations on the result,
>>>> without any locations.
>>>>
>>>> A better alternative might be that the result type of the constructor
>>>> uses the actual return type instead of NoType and performs the inference
>>>> of the annotations from the receiver type.
>>>> It would then probably be easier and more consistent if the result
>>>> annotations contained the location information.
>>>
>>>
>>>
>>> Our thinking is that a ctor does not have a return type, so
>>> getReturnType()
>>> for a ctor's Executable really must give a NoType. Annotations on the
>>> ctor
>>> with target_type=0x14 ("return type of method, or type of newly
>>> constructed
>>> object") will be exposed on the NoType. It's not worth complicating with
>>> receiver annotations.
>>>
>>> Alex
>>>
>>>
>>>> On 10/02/2013 03:32 PM, Joel Borggrén-Franck wrote:
>>>>>
>>>>>
>>>>> Hi Werner,
>>>>>
>>>>> When looking at the byte code for this class:
>>>>>
>>>>>     3 public class Test {
>>>>>     4     class Inner {
>>>>>     5         @Annot(0) public Inner(@Annot(1) Test Test.this) {}
>>>>>     6
>>>>>     7         public @Annot(5) Inner foo(@Annot(55) Test.Inner
>>>>> Test.Inner.this) { return new Inner(); }
>>>>>     8     }
>>>>>     9 }
>>>>>    10
>>>>>    11 @Retention(RetentionPolicy.RUNTIME)
>>>>>    12 @Target(ElementType.TYPE_USE)
>>>>>    13 @interface Annot {
>>>>>    14     int value();
>>>>>    15 }
>>>>>
>>>>> javap output this for the method foo();
>>>>>
>>>>>     public Test$Inner foo();
>>>>>       descriptor: ()LTest$Inner;
>>>>> ...
>>>>>       RuntimeVisibleTypeAnnotations:
>>>>>         0: #13(#14=I#21): METHOD_RETURN, location=[INNER_TYPE]
>>>>>         1: #13(#14=I#22): METHOD_RECEIVER
>>>>>
>>>>> and this for the ctor:
>>>>>
>>>>>    public Test$Inner(Test);
>>>>>       descriptor: (LTest;)V
>>>>>>>>>>       RuntimeVisibleTypeAnnotations:
>>>>>         0: #13(#14=I#15): METHOD_RETURN
>>>>>
>>>>> ^^^^^^ no location here ...
>>>>>         1: #13(#14=I#16): METHOD_RECEIVER
>>>>>
>>>>> I think it is a bug that the ctor METHOD_RETURN lacks the
>>>>> location/encoded type_path.
>>>>>
>>>>> What do you think?
>>>>>
>>>>> cheers
>>>>> /Joel
>>>>>
>>>
>>
>>
>>
>



-- 
http://www.google.com/profiles/wdietl


More information about the type-annotations-dev mailing list