<div dir="ltr"><div>Could someone help me confirm whether the following behavior is incorrect, or just under-specified?</div><div><br></div><div>Consider this code:</div><div><br></div><div><div style="margin-left:40px"><span style="font-family:monospace">import java.lang.annotation.*;</span></div><div style="margin-left:40px"><br><span style="font-family:monospace">public class DoubleCast {</span><br><span style="font-family:monospace">    </span><span style="font-family:monospace">DoubleCast</span><span style="font-family:monospace">(Object o) {</span><br><span style="font-family:monospace">        o = (</span><span style="font-family:monospace">DoubleCast</span><span style="font-family:monospace"> & <span style="background-color:rgb(255,255,0)">@Anno Runnable</span>)o;</span><br><span style="font-family:monospace">    }</span><br><span style="font-family:monospace">}</span><br><span style="font-family:monospace"></span><br><span style="font-family:monospace">@Retention(RetentionPolicy.RUNTIME)</span><br><span style="font-family:monospace">@Target(ElementType.TYPE_USE)</span><br><span style="font-family:monospace">@interface Anno { }</span><br><span style="font-family:monospace"></span></div><br></div><div>There is an <span style="font-family:monospace">@Anno</span> type annotation on the second class in the cast expression (<span style="font-family:monospace">Runnable</span>), so we expect to find that noted in the <span style="font-family:monospace">RuntimeVisibleTypeAnnotations</span> classfile attribute. Because the cast involves an intersection type, the bytecode will have two CHECKCAST instructions, as shown in the javap output:</div><br><div><div style="margin-left:40px"><span style="font-family:monospace">  DoubleCast(java.lang.Object);</span><br><span style="font-family:monospace">    descriptor: (Ljava/lang/Object;)V</span><br><span style="font-family:monospace">    flags: (0x0000)</span><br><span style="font-family:monospace">    Code:</span><br><span style="font-family:monospace">      stack=1, locals=2, args_size=2</span><br><span style="font-family:monospace">         0: aload_0</span><br><span style="font-family:monospace">         1: invokespecial #1                  // Method java/lang/Object."<init>":()V</span><br><span style="font-family:monospace">         4: aload_1</span><br><span style="font-family:monospace;background-color:rgb(255,255,0)">         5: checkcast     #7                  // class java/lang/Runnable</span><br><span style="font-family:monospace">         8: checkcast     #9                  // class DoubleCast</span><br><span style="font-family:monospace">        11: astore_1</span><br><span style="font-family:monospace">        12: return</span><br><span style="font-family:monospace">      LineNumberTable:</span><br><span style="font-family:monospace">        line 3: 0</span><br><span style="font-family:monospace">        line 4: 4</span><br><span style="font-family:monospace">        line 5: 12</span><br><span style="font-family:monospace">      RuntimeVisibleTypeAnnotations:</span><br><span style="font-family:monospace">        0: #15(): CAST, <span style="background-color:rgb(255,255,0)">offset=8</span>, type_index=1</span><br><span style="font-family:monospace">          Anno</span><br><span style="font-family:monospace"></span></div><br></div><div>Note that the bytecode offset in the attribute points to the CHECKCAST instruction associated with the first cast type (<span style="font-family:monospace">DoubleCheckcast</span>), not the second, annotated type (<span style="font-family:monospace">Runnable</span>), even though the <span style="font-family:monospace">type_index</span> is correctly pointing to the second type (<span style="font-family:monospace">Runnable</span>).</div><div><br></div><div>I've also seen examples where the two CHECKCAST instructions are emitted in the reverse order; in those cases, the same thing happens, i.e., <span style="font-family:monospace">offset</span> points to the first CHECKCAST to <span style="font-family:monospace">DoubleCheckcast</span><span style="font-family:arial,sans-serif"> instead of the second CHECKCAST to </span><span style="font-family:monospace">Runnable.</span></div><div><span style="font-family:arial,sans-serif"><br></span></div><div>The JLS specifies only that <span style="font-family:monospace">offset</span> refers to "the bytecode instruction
                                    corresponding to the cast expression", which is ambiguous because for an intersection cast there are multiple such bytecodes. But even if you tried to read that generously as "the first bytecode instruction corresponding to the cast expression" then the example above would still be incorrect.</div><div><br></div><div>In any case, as things stand now it seems impossible to correctly identify which type has the annotation: even if you look at the <span style="font-family:monospace">type_index</span> there's no guarantee that the order of the CHECKCAST instructions matches the order in the source code, and even if there were such a guarantee, because the bytecode offset is wrong, you'd be counting from the wrong offset.</div><div><br></div><div>Behavior confirmed on 17, 25, & 26.</div><div><br></div><div>Thanks,</div><div>-Archie</div><div><span class="gmail_signature_prefix"><br></span></div><div><span class="gmail_signature_prefix">-- </span><br></div><div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature">Archie L. Cobbs<br></div></div>