Skip to content

Commit c3f4aba

Browse files
committed
Fix scala#5140: Ycheck failure in covariant java varargs
Allow passing `Array[Dog]` to a Java varargs that expects an `Array[Animal]`. This types because Java vargs are represented as `RepeatedParam[+T]`, which is covariant. However, after `elimRepeated`, the `RP`s go away and the true type (Array) is revealed, which was causing a Ycheck error because arrays are invariant before erasure. Fix the Ycheck error by casting `Array[Dog]` to `Array[Animal]`. This is unsound but consistent with the typer behaviour and what scalac does.
1 parent 2cc525a commit c3f4aba

File tree

3 files changed

+18
-2
lines changed

3 files changed

+18
-2
lines changed

compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,11 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
9191
private def seqToArray(tree: Tree, pt: Type)(implicit ctx: Context): Tree = tree match {
9292
case SeqLiteral(elems, elemtpt) =>
9393
JavaSeqLiteral(elems, elemtpt)
94-
case app@Apply(fun, args) if defn.WrapArrayMethods().contains(fun.symbol) => // rewrite a call to `wrapXArray(arr)` to `arr`
95-
args.head
94+
case app@Apply(fun, args) if defn.WrapArrayMethods().contains(fun.symbol) =>
95+
// Rewrite a call to `wrapXArray(arr)` to `arr`.
96+
// Additionally, a cast might be necessary in some instances due to arrays being invariant before
97+
// erasure. See `tests/pos/i5140`.
98+
args.head.ensureConforms(pt)
9699
case _ =>
97100
val elemType = tree.tpe.elemType
98101
var elemClass = elemType.classSymbol

tests/pos/i5140/J.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class Animal {}
2+
class Dog extends Animal {}
3+
class J {
4+
void foo(Animal... animal) {}
5+
}

tests/pos/i5140/S.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
class S {
2+
val j = new J()
3+
val x: Array[Dog] = ???
4+
// Check that x is cast to an `Array[Animal]` after elimRepeated.
5+
// Otherwise, the call below would fail in -Ycheck:elimRepeated because arrays are invariant before erasure.
6+
// This is unsound but allowed.
7+
j.foo(x: _*)
8+
}

0 commit comments

Comments
 (0)