bug icon indicating copy to clipboard operation
bug copied to clipboard

An Array cannot be used in place of varargs with type parameters.

Open scabug opened this issue 15 years ago • 5 comments

This happens when vararg type has type parameters.

Both Array and mutable.Seq are invariant. However using Array as an argument in vararg function fails, while mutable.Seq works.

object Main {
  def main(args: Array[String]) {
    bar(new B)
  }

  def bar(b: B) {
    val array = Array(b, b)
    val seq :scala.collection.mutable.Seq[B] = array

    foo(b, b)
    foo(seq: _*) //works
    foo(array: _*) //compiler error
  }

  def foo(s: A[_]*) {
    s.foreach(println)
  }
}

class A[T]
class B extends A[String]

Compiler error:

error: type mismatch;
 found   : Array[B]
 required: Array[A[?>: Nothing <: Any]]
    foo(array: _*)
one error found

Everything works when vararg type does not have any type parameters:

object Main {
  def main(args: Array[String]) {
    bar(new B)
  }

  def bar(b: B) {
    val array = Array(b, b)
    val seq :scala.collection.mutable.Seq[B] = array

    foo(b, b)
    foo(seq: _*)
    foo(array: _*)
  }

  def foo[T](s: A*) {
    s.foreach(println)
  }
}

class A
class B extends A

Tested on 2.8.1.final and 2.9.0.r23541.

scabug avatar Nov 18 '10 14:11 scabug

Imported From: https://issues.scala-lang.org/browse/SI-4003?orig=1 Reporter: @lexn82

scabug avatar Nov 18 '10 14:11 scabug

@adriaanm said: let's have a look at the code that does type check after uncurry (scalac -Xprint:uncurry):

The vararg is considered a scala.collection.Seq[A[]], Seq is covariant so that a mutable.Seq[B] <: collection.Seq[A[]]

def bar(b: B): Unit = {
  val array: Array[B] = ...
  val seq: mutable.Seq[B] = wrapRefArray[B](array);
  foo(wrapRefArray[A[_]](Array[A[_]]{b, b}));
  foo(seq)
};

def foo(s: Seq[A[_]]): Unit = ...

So, back to the bug: when passing array to foo, the compiler complains. I guess this is indeed a bug since val x : Seq[A[_]] = array compiles (uncurry turns it into val x: Seq[A[_]] = scala.this.Predef.wrapRefArray[B](array);)

Workaround:

    val array : Array[A[_]] = Array(b, b)

scabug avatar Nov 21 '10 17:11 scabug

In Scala 2.13.0, the former code is also a compilation error, and the latter code is also a compilation error.

(The package names were compiled as pattern1 and pattern2, respectively.)

The former compilation error

[error] /xxx/src/main/scala/Main1.scala:13:9: type mismatch;
[error]  found   : Seq[pattern1.B]    (in scala.collection.mutable)
[error]  required: Seq[pattern1.A[?]] (in scala.collection.immutable)
[error]     foo(seq: _*) //works
[error]         ^
[error] /xxx/src/main/scala/Main1.scala:14:9: type mismatch;
[error]  found   : Array[pattern1.B]
[error]  required: Array[pattern1.A[?]]
[error] Note: pattern1.B <: pattern1.A[?], but class Array is invariant in type T.
[error] You may wish to investigate a wildcard type such as `_ <: pattern1.A[?]`. (SLS 3.2.10)
[error]     foo(array: _*) //compiler error
[error]         ^

The latter compilation error

[error] /xxx/src/main/scala/Main2.scala:13:9: type mismatch;
[error]  found   : Seq[pattern2.B] (in scala.collection.mutable)
[error]  required: Seq[pattern2.A] (in scala.collection.immutable)
[error]     foo(seq: _*)
[error]         ^

magnolia-k avatar Aug 12 '19 05:08 magnolia-k

the latter one is because varargs are scala.Seq, which is now an alias for scala.collection.immutable.Seq rather than scala.collection.Seq. If you change the code to val seq :scala.collection.immutable.Seq[B] = array it may work (I can't check right now)

NthPortal avatar Aug 12 '19 06:08 NthPortal

surely! After rewriting the code, the compilation passed.

magnolia-k avatar Aug 12 '19 07:08 magnolia-k