type_path of constructors for inner classes
Alex Buckley
alex.buckley at oracle.com
Fri Oct 11 19:56:09 PDT 2013
On 10/11/2013 5:13 PM, Werner Dietl wrote:
> 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?
Given:
@Annot(0) Inner(@Annot(1) Test Test.this) {}
I think the most natural thing to do is emit 0 and 1 and 2. Everywhere a
simple name of a nested type occurs, javac "expands" the simple name to
a qualified name when emitting class files. It seems perfectly
consistent to "expand" the zero-length string representing the type of
the newly constructed object into the qualified name "Test.Inner" - the
"Inner" which appears before the left paren is a simple type name for
sure, but the type of the constructed object is more than that.
Then, we can determine what annotations appear on the "Test" and what on
the "Inner" in the type "Test.Inner" :
- The "Test" in the type of the newly constructed object is a different
entity than the "Test" in the type of the receiver parameter, but it's
reasonable to copy @Annot(1) from the latter to the former.
- The "Inner" in the type of the newly constructed object is then
obviously annotated one level down with @Annot(0).
I can add language to the JLS to state that the type of the newly
constructed object, if annotated, is the fully qualified name of the
type; and that any annotations on the receiver type's parameter apply to
the appropriate simple type name within the fully qualified name.
>> 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?
Yes. It arises in numerous places:
- "Finally, there is an implicit use of a type as the simple name of the
class in a constructor declaration. This implicit use indicates the type
of the constructed object."
- "It is possible for an annotation to appear at a syntactic location in
a program where it could plausibly apply to a declaration, or a type, or
both. This can happen in any of the five declaration contexts where
modifiers immediately precede the type: ... Constructor declarations
(The annotation applies to the type of the constructed object, denoted
by the simple type name in the constructor declaration.)"
- "The empty_target item indicates that an annotation appears on either
the type in a field declaration, the return type of a method, the type
of a newly constructed object, or the receiver type of a method or
constructor."
>> 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.
OK, as mentioned above.
Alex
> 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
>>>>>>
>>>>
>>>
>>>
>>>
>>
>
>
>
More information about the type-annotations-dev
mailing list