Skip to content

Commit b5c3920

Browse files
committed
Take expected type into account when typing a sequence argument
Given an expected type `*T`, we allow a sequence argument `xs: _*` to be either a `Seq[T]` or an `Array[_ <: T]`, irrespective of whether the method we're calling is a Java or Scala method. So far we typed sequence arguments without an expected type, meaning that adaptation did not take place. But thanks to #8635, we can type them with an expected type of `Seq[T] | Array[_ <: T]` and type inference works out. This is what this commit does.
1 parent a611718 commit b5c3920

File tree

4 files changed

+38
-11
lines changed

4 files changed

+38
-11
lines changed

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -389,12 +389,14 @@ class TypeApplications(val self: Type) extends AnyVal {
389389
}
390390

391391
/** If this is a repeated parameter `*T`, translate it to either `Seq[T]` or
392-
* `Array[? <: T]` depending on the value of `toArray`, keep other types as
393-
* they are.
392+
* `Array[? <: T]` depending on the value of `toArray`, if this is a
393+
* prototype `<?>` then treat it like `*<?>`, keep other types as they are.
394394
*/
395395
def translateFromRepeated(toArray: Boolean)(using Context): Type =
396+
val seqClass = if (toArray) defn.ArrayClass else defn.SeqClass
397+
if self eq WildcardType then
398+
seqClass.typeRef.appliedTo(WildcardType)
396399
if self.isRepeatedParam then
397-
val seqClass = if (toArray) defn.ArrayClass else defn.SeqClass
398400
// We want `Array[? <: T]` because arrays aren't covariant until after
399401
// erasure. See `tests/pos/i5140`.
400402
translateParameterized(defn.RepeatedParamClass, seqClass, wildcardArg = toArray)

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -726,19 +726,19 @@ class Typer extends Namer
726726

727727
if (untpd.isWildcardStarArg(tree)) {
728728
def typedWildcardStarArgExpr = {
729+
// A sequence argument `xs: _*` can be either a `Seq[T]` or an `Array[_ <: T]`,
730+
// irrespective of whether the method we're calling is a Java or Scala method,
731+
// so the expected type is the union `Seq[T] | Array[_ <: T]`.
729732
val ptArg =
733+
// FIXME(#8680): Quoted patterns do not support Array repeated arguments
730734
if (ctx.mode.is(Mode.QuotedPattern)) pt.translateFromRepeated(toArray = false)
731-
else WildcardType
735+
else pt.translateFromRepeated(toArray = false) | pt.translateFromRepeated(toArray = true)
732736
val tpdExpr = typedExpr(tree.expr, ptArg)
733737
tpdExpr.tpe.widenDealias match {
734738
case defn.ArrayOf(_) =>
735-
val starType = defn.ArrayType.appliedTo(WildcardType)
736-
val exprAdapted = adapt(tpdExpr, starType)
737-
arrayToRepeated(exprAdapted)
739+
arrayToRepeated(tpdExpr)
738740
case _ =>
739-
val starType = defn.SeqType.appliedTo(defn.AnyType)
740-
val exprAdapted = adapt(tpdExpr, starType)
741-
seqToRepeated(exprAdapted)
741+
seqToRepeated(tpdExpr)
742742
}
743743
}
744744
cases(

tests/pos/sequence-argument.scala

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import scala.reflect.ClassTag
2+
import scala.language.implicitConversions
3+
4+
class A
5+
class B
6+
7+
object Test {
8+
def doubleSeq[T](x: T): Seq[T] = Seq(x, x)
9+
def doubleArray[T: ClassTag](x: T): Array[T] = Array(x, x)
10+
11+
def box(x: Integer*): Unit = {}
12+
def widen(x: Long*): Unit = {}
13+
def conv(x: B*): Unit = {}
14+
15+
box(doubleSeq(1): _*)
16+
box(doubleArray(1): _*)
17+
18+
widen(doubleSeq(1): _*)
19+
widen(doubleArray(1): _*)
20+
21+
implicit def aToB(x: A): B = new B
22+
val a: A = new A
23+
conv(doubleSeq(a): _*)
24+
conv(doubleArray(a): _*)
25+
}

0 commit comments

Comments
 (0)