type_path of constructors for inner classes
Alex Buckley
alex.buckley at oracle.com
Fri Oct 11 16:56:06 PDT 2013
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