Skip to content

Commit 9a7b67b

Browse files
authored
Merge pull request #5577 from dotty-staging/fix-4785
Fix #4785: Change typing rule for wildcard star args
2 parents b7911f2 + 47d969f commit 9a7b67b

File tree

7 files changed

+65
-27
lines changed

7 files changed

+65
-27
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ class TypeApplications(val self: Type) extends AnyVal {
497497
}
498498

499499
/** The element type of a sequence or array */
500-
def elemType(implicit ctx: Context): Type = self match {
500+
def elemType(implicit ctx: Context): Type = self.widenDealias match {
501501
case defn.ArrayOf(elemtp) => elemtp
502502
case JavaArrayType(elemtp) => elemtp
503503
case _ => self.baseType(defn.SeqClass).argInfos.headOption.getOrElse(NoType)

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

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -71,40 +71,39 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
7171
transformTypeOfTree(tree)
7272

7373
override def transformApply(tree: Apply)(implicit ctx: Context): Tree = {
74-
val formals =
75-
ctx.atPhase(thisPhase) { implicit ctx =>
76-
tree.fun.tpe.widen.asInstanceOf[MethodType].paramInfos
77-
}
78-
val args1 = tree.args.zipWithConserve(formals) { (arg, formal) =>
79-
arg match {
80-
case arg: Typed if isWildcardStarArg(arg) =>
81-
if (tree.fun.symbol.is(JavaDefined) && arg.expr.tpe.derivesFrom(defn.SeqClass))
82-
seqToArray(arg.expr, formal.underlyingIfRepeated(isJava = true))
83-
else arg.expr
84-
case arg => arg
85-
}
74+
val args = tree.args.mapConserve {
75+
case arg: Typed if isWildcardStarArg(arg) =>
76+
val isJavaDefined = tree.fun.symbol.is(JavaDefined)
77+
val tpe = arg.expr.tpe
78+
if (isJavaDefined && tpe.derivesFrom(defn.SeqClass))
79+
seqToArray(arg.expr)
80+
else if (!isJavaDefined && tpe.derivesFrom(defn.ArrayClass))
81+
arrayToSeq(arg.expr)
82+
else
83+
arg.expr
84+
case arg => arg
8685
}
87-
transformTypeOfTree(cpy.Apply(tree)(tree.fun, args1))
86+
transformTypeOfTree(cpy.Apply(tree)(tree.fun, args))
8887
}
8988

90-
/** Convert sequence argument to Java array of type `pt` */
91-
private def seqToArray(tree: Tree, pt: Type)(implicit ctx: Context): Tree = tree match {
89+
/** Convert sequence argument to Java array */
90+
private def seqToArray(tree: Tree)(implicit ctx: Context): Tree = tree match {
9291
case SeqLiteral(elems, elemtpt) =>
9392
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
9693
case _ =>
9794
val elemType = tree.tpe.elemType
9895
var elemClass = elemType.classSymbol
99-
if (defn.NotRuntimeClasses contains elemClass) elemClass = defn.ObjectClass
96+
if (defn.NotRuntimeClasses.contains(elemClass)) elemClass = defn.ObjectClass
10097
ref(defn.DottyArraysModule)
10198
.select(nme.seqToArray)
10299
.appliedToType(elemType)
103100
.appliedTo(tree, Literal(Constant(elemClass.typeRef)))
104-
.ensureConforms(pt)
105-
// Because of phantomclasses, the Java array's type might not conform to the return type
106101
}
107102

103+
/** Convert Java array argument to Scala Seq */
104+
private def arrayToSeq(tree: Tree)(implicit ctx: Context): Tree =
105+
tpd.wrapArray(tree, tree.tpe.elemType)
106+
108107
override def transformTypeApply(tree: TypeApply)(implicit ctx: Context): Tree =
109108
transformTypeOfTree(tree)
110109

compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,12 @@ trait TypeAssigner {
153153
if (!sym.is(SyntheticOrPrivate) && sym.owner.isClass) checkNoPrivateLeaks(sym, pos)
154154
else sym.info
155155

156-
def seqToRepeated(tree: Tree)(implicit ctx: Context): Tree =
157-
Typed(tree, TypeTree(tree.tpe.widen.translateParameterized(defn.SeqClass, defn.RepeatedParamClass)))
156+
private def toRepeated(tree: Tree, from: ClassSymbol)(implicit ctx: Context): Tree =
157+
Typed(tree, TypeTree(tree.tpe.widen.translateParameterized(from, defn.RepeatedParamClass)))
158+
159+
def seqToRepeated(tree: Tree)(implicit ctx: Context): Tree = toRepeated(tree, defn.SeqClass)
160+
161+
def arrayToRepeated(tree: Tree)(implicit ctx: Context): Tree = toRepeated(tree, defn.ArrayClass)
158162

159163
/** A denotation exists really if it exists and does not point to a stale symbol. */
160164
final def reallyExists(denot: Denotation)(implicit ctx: Context): Boolean = try

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,7 @@ class Typer extends Namer
546546
}
547547
case _ => ifExpr
548548
}
549+
549550
def ascription(tpt: Tree, isWildcard: Boolean) = {
550551
val underlyingTreeTpe =
551552
if (isRepeatedParamType(tpt)) TypeTree(defn.SeqType.appliedTo(pt :: Nil))
@@ -557,11 +558,26 @@ class Typer extends Namer
557558
else typed(tree.expr, tpt.tpe.widenSkolem)
558559
assignType(cpy.Typed(tree)(expr1, tpt), underlyingTreeTpe)
559560
}
560-
if (untpd.isWildcardStarArg(tree))
561+
562+
if (untpd.isWildcardStarArg(tree)) {
563+
def typedWildcardStarArgExpr = {
564+
val tpdExpr = typedExpr(tree.expr)
565+
tpdExpr.tpe.widenDealias match {
566+
case defn.ArrayOf(_) =>
567+
val starType = defn.ArrayType.appliedTo(WildcardType)
568+
val exprAdapted = adapt(tpdExpr, starType)
569+
arrayToRepeated(exprAdapted)
570+
case _ =>
571+
val starType = defn.SeqType.appliedTo(defn.AnyType)
572+
val exprAdapted = adapt(tpdExpr, starType)
573+
seqToRepeated(exprAdapted)
574+
}
575+
}
561576
cases(
562577
ifPat = ascription(TypeTree(defn.RepeatedParamType.appliedTo(pt)), isWildcard = true),
563-
ifExpr = seqToRepeated(typedExpr(tree.expr, defn.SeqType.appliedTo(defn.AnyType))),
578+
ifExpr = typedWildcardStarArgExpr,
564579
wildName = nme.WILDCARD_STAR)
580+
}
565581
else {
566582
def typedTpt = checkSimpleKinded(typedType(tree.tpt))
567583
def handlePattern: Tree = {

tests/neg/repeatedArgs213.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ class repeatedArgs {
3333
bar("a", "b", "c")
3434
bar(xs: _*)
3535
bar(ys: _*) // error: immutable.Seq expected, found Seq
36-
bar(zs: _*) // error: immutable.Seq expected, found Array
36+
bar(zs: _*) // old-error: Remove (compiler generated) Array to Seq convertion in 2.13?
3737

3838
Paths.get("Hello", "World")
3939
Paths.get("Hello", xs: _*)
4040
Paths.get("Hello", ys: _*) // error: immutable.Seq expected, found Seq
41-
Paths.get("Hello", zs: _*) // error: immutable.Seq expected, found Array
41+
Paths.get("Hello", zs: _*)
4242
}
4343
}

tests/pos/i4785.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import scala.Predef.Set // unimport Predef.wrapRefArray
2+
3+
import java.nio.file.Paths
4+
5+
class i4785 {
6+
def bar(xs: String*) = xs.length
7+
8+
def test(xs: Seq[String], ys: Array[String]) = {
9+
Paths.get("Hello", xs: _*)
10+
Paths.get("Hello", ys: _*)
11+
12+
bar(xs: _*)
13+
bar(ys: _*)
14+
}
15+
}

tests/pos/repeatedArgs.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import scala.collection.{immutable, mutable}
22
import java.nio.file.Paths
3+
import java.util.concurrent.ForkJoinTask
34

45
class repeatedArgs {
56
def bar(xs: String*): Int = xs.length
@@ -19,4 +20,7 @@ class repeatedArgs {
1920
val x: collection.Seq[String] = others
2021
// val y: immutable.Seq[String] = others // ok in 2.13
2122
}
23+
24+
def invokeAll[T](tasks: ForkJoinTask[T]*): Unit = ForkJoinTask.invokeAll(tasks: _*)
25+
def invokeAll2(tasks: ForkJoinTask[_]*): Unit = ForkJoinTask.invokeAll(tasks: _*)
2226
}

0 commit comments

Comments
 (0)