<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <p>Good catch - I believe the compiler does what it does because it
      uses the type of the cast (as well as the types of the aruments)
      to determine the final compile-time type of the method being
      called. This is the type that will (under erasure) be reified in
      the constant pool. So, here javac sees a call to a method that
      returns V and then a cast to V...</p>
    <p>Ideally javac should erase things earlier, or just use Object as
      the type of the method call, as Alex suggests. The latter might be
      slightly complicated because, after we added VarHandle support in
      Java 9, we also have some polymorphic methods whose return type is
      not Object (see VarHandle::compareAndSet). But, basically, javac
      should implement this more closely, w/o getting too distracted by
      the type inferred for the synthetic symbol attached to the method
      call AST node:</p>
    <p>
      <blockquote type="cite">The compile-time result is determined as
        follows:
        <div class="norm">
          <ul class="norm" style="list-style-type: square; ">
            <li class="listitem">
              <p class="norm-static">If the signature polymorphic method
                is either <code class="literal">void</code> or has a
                return type other than <code class="literal">Object</code>,
                the compile-time result is the result of the invocation
                type of the compile-time declaration (<a class="xref" href="https://docs.oracle.com/javase/specs/jls/se15/html/jls-15.html#jls-15.12.2.6" title="15.12.2.6. Method Invocation Type">§15.12.2.6</a>).
              </p>
            </li>
            <li class="listitem">
              <p class="norm-static">Otherwise, if the method invocation
                expression is an expression statement, the compile-time
                result is <code class="literal">void</code>. </p>
            </li>
            <li class="listitem">
              <p class="norm-static">Otherwise, if the method invocation
                expression is the operand of a cast expression (<a class="xref" href="https://docs.oracle.com/javase/specs/jls/se15/html/jls-15.html#jls-15.16" title="15.16. Cast Expressions">§15.16</a>), the
                compile-time result is the erasure of the type of the
                cast expression (<a class="xref" href="https://docs.oracle.com/javase/specs/jls/se15/html/jls-4.html#jls-4.6" title="4.6. Type Erasure">§4.6</a>).</p>
            </li>
          </ul>
        </div>
      </blockquote>
      <blockquote type="cite">
        <div class="norm">
          <ul class="norm" style="list-style-type: square; ">
            <li class="listitem">
              <p class="norm-static">Otherwise, the compile-time result
                is the signature polymorphic method's return type, <code class="literal">Object</code>. </p>
            </li>
          </ul>
        </div>
      </blockquote>
    </p>
    <p>Filed:<br>
      <a class="moz-txt-link-freetext" href="https://bugs.openjdk.org/browse/JDK-8343286">https://bugs.openjdk.org/browse/JDK-8343286</a><br>
    </p>
    <p>Cheers<br>
      Maurizio<br>
    </p>
    <p><br>
    </p>
    <div class="moz-cite-prefix">On 29/10/2024 22:52, Alex Buckley
      wrote:<br>
    </div>
    <blockquote type="cite" cite="mid:7ad3fb18-0335-4e05-b584-4c15ca979252@oracle.com">VarHandle::getAndSet(Object[])
      is a signature polymorphic method, which means that the type of a
      method call is sensitive to an ensuing cast:
      <br>
      <br>
      "... if the method invocation expression is the operand of a cast
      expression (§15.16), the compile-time result is the erasure of the
      type of the cast expression (§4.6)."  (JLS 15.12.3)
      <br>
      <br>
      This has implications for how the method call is compiled, but
      it's moot for your program because the type of the method call is
      Object no matter how you slice it.
      <br>
      <br>
      Casting from Object to type variable V is achieved by a narrowing
      reference conversion that is unchecked. So, I'd expect an
      "unchecked cast" warning, like for a non-signature polymorphic
      method.
      <br>
      <br>
      Alex
      <br>
      <br>
      On 10/29/2024 2:30 PM, Archie Cobbs wrote:
      <br>
      <blockquote type="cite">Question: Should this program generate an
        unchecked cast warning?
        <br>
        <br>
        import java.lang.invoke.VarHandle;
        <br>
        class VarHandleCast<V> {
        <br>
             VarHandle vh;
        <br>
             V method(Object obj) {
        <br>
                 return (V)vh.getAndSet(this, obj);  // unchecked cast?
        <br>
             }
        <br>
        }
        <br>
        <br>
        Currently, it does not.
        <br>
        <br>
        Presumably that has something to do with this code in Types.java
        but I'm not sure why this would mean there should be no warning:
        <br>
        <br>
             /**
        <br>
              * A polymorphic signature method (JLS 15.12.3) is a method
        that
        <br>
              *   (i) is declared in the
        java.lang.invoke.MethodHandle/VarHandle classes;
        <br>
              *  (ii) takes a single variable arity parameter;
        <br>
              * (iii) whose declared type is Object[];
        <br>
              *  (iv) has any return type, Object signifying a
        polymorphic return type; and
        <br>
              *   (v) is native.
        <br>
             */
        <br>
            public boolean isSignaturePolymorphic(MethodSymbol msym) {
        <br>
                List<Type> argtypes =
        msym.type.getParameterTypes();
        <br>
                return (msym.flags_field & NATIVE) != 0 &&
        <br>
                       (msym.owner == syms.methodHandleType.tsym ||
        msym.owner == syms.varHandleType.tsym) &&
        <br>
                        argtypes.length() == 1 &&
        <br>
                        argtypes.head.hasTag(TypeTag.ARRAY) &&
        <br>
                        ((ArrayType)argtypes.head).elemtype.tsym ==
        syms.objectType.tsym;
        <br>
            }
        <br>
        <br>
        Thanks,
        <br>
        -Archie
        <br>
        <br>
        -- <br>
        Archie L. Cobbs
        <br>
      </blockquote>
      <br>
    </blockquote>
  </body>
</html>