Skip to content

Invalid Java generic signatures for polymorphic value classes #12283

Open
@smarter

Description

@smarter

reproduction steps

using Scala 2.13.4,

class Poly[A](val value: A) extends AnyVal

class Arr[A](val value: Array[A]) extends AnyVal

class ArrRef[A <: AnyRef](val value: Array[A]) extends AnyVal

class Test {
  def poly1(x: Poly[Int]): Poly[Int] =
    new Poly(x.value)

  def poly2(x: Poly[String]): Poly[String] = // correct signature
    new Poly(x.value)

  def poly3(x: Poly[Array[Int]]): Poly[Array[Int]] = // correct signature
    new Poly(x.value)

  def poly4(x: Poly[Array[String]]): Poly[Array[String]] = // correct signature
    new Poly(x.value)

  def arr1(x: Arr[Int]): Arr[Int] =
    new Arr(x.value)

  def arr2(x: Arr[String]): Arr[String] =
    new Arr(x.value)

  def arr3(x: Arr[Array[Int]]): Arr[Array[Int]] =
    new Arr(x.value)

  def arr4(x: Arr[Array[String]]): Arr[Array[String]] =
    new Arr(x.value)

  def arrRef1(x: ArrRef[Integer]): ArrRef[Integer] =
    new ArrRef(x.value)

  def arrRef2(x: ArrRef[String]): ArrRef[String] =
    new ArrRef(x.value)

  def arrRef3(x: ArrRef[Array[Int]]): ArrRef[Array[Int]] =
    new ArrRef(x.value)

  def arrRef4(x: ArrRef[Array[String]]): ArrRef[Array[String]] =
    new ArrRef(x.value)
}

problem

When using javap we can observe that the generic signature of these methods (the one that javap displays first and that comes from the Signature attribute) does not match their descriptor (which is the actual signature the JVM cares about); except for the ones I marked // correct signature:

% javap -p -v Test|grep -B1 descriptor
...
--
  public int poly1(int);
    descriptor: (Ljava/lang/Integer;)Ljava/lang/Integer;
--
  public java.lang.String poly2(java.lang.String);
    descriptor: (Ljava/lang/String;)Ljava/lang/String;
--
  public int[] poly3(int[]);
    descriptor: ([I)[I
--
  public java.lang.String[] poly4(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)[Ljava/lang/String;
--
  public int[] arr1(int[]);
    descriptor: (Ljava/lang/Object;)Ljava/lang/Object;
--
  public java.lang.String[] arr2(java.lang.String[]);
    descriptor: (Ljava/lang/Object;)Ljava/lang/Object;
--
  public int[][] arr3(int[][]);
    descriptor: (Ljava/lang/Object;)Ljava/lang/Object;
--
  public java.lang.String[][] arr4(java.lang.String[][]);
    descriptor: (Ljava/lang/Object;)Ljava/lang/Object;
--
  public java.lang.Integer[] arrRef1(java.lang.Integer[]);
    descriptor: ([Ljava/lang/Object;)[Ljava/lang/Object;
--
  public java.lang.String[] arrRef2(java.lang.String[]);
    descriptor: ([Ljava/lang/Object;)[Ljava/lang/Object;
--
  public int[][] arrRef3(int[][]);
    descriptor: ([Ljava/lang/Object;)[Ljava/lang/Object;
--
  public java.lang.String[][] arrRef4(java.lang.String[][]);
    descriptor: ([Ljava/lang/Object;)[Ljava/lang/Object;
--
...

This can only end in disaster when Java tries to call these methods:

public class J {
  public static void main(String[] args) {
    Test test = new Test();
    test.poly1(1);
  }
}
% javac J.java
% java J
Exception in thread "main" java.lang.NoSuchMethodError: Test.poly1(I)I
        at J.main(J.java:4)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions