scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
230 stars 21 forks source link

Unspecialized method on a `@specialized` class calls `AnyRef` variant of method with an `Array[E @uncheckedVariance]` argument (and not erased). #12951

Open noresttherein opened 4 months ago

noresttherein commented 4 months ago

Reproduction steps

Scala version: 2.13.12

trait Ops[@specialized(Int) +T, C] {
    protected[this] def array :Array[T]
    def copy :C = fromSpecific(array)
    def fromSpecific(array :Array[T @uncheckedVariance]) :C
}

class Spec[@specialized(Int) T](val array :Array[T]) extends Ops[T, Spec[T]] {
    override def fromSpecific(array :Array[T]) :Spec[T] = new Spec(array)
}

object app extends App {
    val spec = new Spec(Array(1, 2))
    spec.copy
}

Problem

Exception in thread "main" java.lang.ClassCastException: class [I cannot be cast to class [Ljava.lang.Object; ([I and [Ljava.lang.Object; are in module java.base of loader 'bootstrap')
    at Ops.copy(Playground.scala:17)
    at Ops.copy$(Playground.scala:17)
    at Spec.copy(Playground.scala:21)
    at Playground$.delayedEndpoint$Playground$1(Playground.scala:27)
    at Playground$delayedInit$body.apply(Playground.scala:25)
    at scala.Function0.apply$mcV$sp(Function0.scala:42)
    at scala.Function0.apply$mcV$sp$(Function0.scala:42)
    at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:17)
    at scala.App.$anonfun$main$1(App.scala:98)
    at scala.App.$anonfun$main$1$adapted(App.scala:98)
    at scala.collection.IterableOnceOps.foreach(IterableOnce.scala:576)
    at scala.collection.IterableOnceOps.foreach$(IterableOnce.scala:574)
    at scala.collection.AbstractIterable.foreach(Iterable.scala:933)

Output from javap:

public class Spec<T> implements Ops<T, Spec<T>> {
  public final java.lang.Object array;
  public java.lang.Object copy();
  public java.lang.Object array();
  public Spec<T> fromSpecific(java.lang.Object);
  public int[] array$mcI$sp();
  public Spec<java.lang.Object> fromSpecific$mcI$sp(int[]);
  public boolean specInstance$();
  public java.lang.Object fromSpecific$mcI$sp(int[]);
  public java.lang.Object fromSpecific(java.lang.Object[]);
  public Spec(java.lang.Object);
}

The line counts are off; I have not looked into raw bytecode, but it seems to me that copy calls fromSpecific(Object[]) rather than fromSpecific(Object).

som-snytt commented 1 month ago

relatedly https://github.com/scala/bug/issues/12764

This example also executes under 2.9.2 (not a workaround...).