Skip to content

Commit 0aa702f

Browse files
committed
Instead of a cast, change RepeatedParam[T] into Array[_ <: T] in elimRepeated
1 parent c3f4aba commit 0aa702f

File tree

3 files changed

+14
-10
lines changed

3 files changed

+14
-10
lines changed

compiler/src/dotty/tools/dotc/core/TypeApplications.scala

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -435,15 +435,19 @@ class TypeApplications(val self: Type) extends AnyVal {
435435
case _ => if (self.isMatch) MatchAlias(self) else TypeAlias(self)
436436
}
437437

438-
/** Translate a type of the form From[T] to To[T], keep other types as they are.
438+
/** Translate a type of the form From[T] to either To[T] or To[_ <: T] (if `argIsUpper` is set). Keep other types as they are.
439439
* `from` and `to` must be static classes, both with one type parameter, and the same variance.
440440
* Do the same for by name types => From[T] and => To[T]
441441
*/
442-
def translateParameterized(from: ClassSymbol, to: ClassSymbol)(implicit ctx: Context): Type = self match {
442+
def translateParameterized(from: ClassSymbol, to: ClassSymbol, argIsUpper: Boolean = false)(implicit ctx: Context): Type = self match {
443443
case self @ ExprType(tp) =>
444444
self.derivedExprType(tp.translateParameterized(from, to))
445445
case _ =>
446-
if (self.derivesFrom(from)) to.typeRef.appliedTo(self.baseType(from).argInfos)
446+
if (self.derivesFrom(from)) {
447+
val arg = self.baseType(from).argInfos.head
448+
val arg1 = if (argIsUpper) TypeBounds.upper(arg) else arg
449+
to.typeRef.appliedTo(arg1)
450+
}
447451
else self
448452
}
449453

@@ -453,7 +457,9 @@ class TypeApplications(val self: Type) extends AnyVal {
453457
def underlyingIfRepeated(isJava: Boolean)(implicit ctx: Context): Type =
454458
if (self.isRepeatedParam) {
455459
val seqClass = if (isJava) defn.ArrayClass else defn.SeqClass
456-
translateParameterized(defn.RepeatedParamClass, seqClass)
460+
// If `isJava` is set, then we want to turn `RepeatedParam[T]` into `Array[_ <: T]`,
461+
// since arrays aren't covariant until after erasure. See `tests/pos/i5140`.
462+
translateParameterized(defn.RepeatedParamClass, seqClass, argIsUpper=isJava)
457463
}
458464
else self
459465

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

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,8 @@ 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) =>
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)
94+
case app@Apply(fun, args) if defn.WrapArrayMethods().contains(fun.symbol) => // rewrite a call to `wrapXArray(arr)` to `arr`
95+
args.head
9996
case _ =>
10097
val elemType = tree.tpe.elemType
10198
var elemClass = elemType.classSymbol

tests/pos/i5140/S.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
class S {
22
val j = new J()
33
val x: Array[Dog] = ???
4-
// Check that x is cast to an `Array[Animal]` after elimRepeated.
4+
// Check that the java varargs for `foo` gets typed as `Array[_ <: Animal]`.
55
// Otherwise, the call below would fail in -Ycheck:elimRepeated because arrays are invariant before erasure.
66
// This is unsound but allowed.
77
j.foo(x: _*)
8+
j.foo(new Dog, new Dog)
89
}

0 commit comments

Comments
 (0)