Skip to content

Commit 21c6fd0

Browse files
committed
Revert scala#3248: generate unapplySeq for case class with varargs
1 parent ce81c02 commit 21c6fd0

File tree

4 files changed

+32
-31
lines changed

4 files changed

+32
-31
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,12 @@ object desugar {
432432
appliedTypeTree(tycon, targs)
433433
}
434434

435+
def isRepeated(tree: Tree): Boolean = tree match {
436+
case PostfixOp(_, Ident(tpnme.raw.STAR)) => true
437+
case ByNameTypeTree(tree1) => isRepeated(tree1)
438+
case _ => false
439+
}
440+
435441
// a reference to the class type bound by `cdef`, with type parameters coming from the constructor
436442
val classTypeRef = appliedRef(classTycon)
437443

@@ -482,11 +488,6 @@ object desugar {
482488
}
483489
def enumTagMeths = if (isEnumCase) enumTagMeth(CaseKind.Class)._1 :: Nil else Nil
484490
def copyMeths = {
485-
def isRepeated(tree: Tree): Boolean = tree match {
486-
case PostfixOp(_, Ident(tpnme.raw.STAR)) => true
487-
case ByNameTypeTree(tree1) => isRepeated(tree1)
488-
case _ => false
489-
}
490491
val hasRepeatedParam = constrVparamss.exists(_.exists {
491492
case ValDef(_, tpt, _) => isRepeated(tpt)
492493
})
@@ -560,7 +561,8 @@ object desugar {
560561
// companion definitions include:
561562
// 1. If class is a case class case class C[Ts](p1: T1, ..., pN: TN)(moreParams):
562563
// def apply[Ts](p1: T1, ..., pN: TN)(moreParams) = new C[Ts](p1, ..., pN)(moreParams) (unless C is abstract)
563-
// def unapply[Ts]($1: C[Ts]) = $1
564+
// def unapply[Ts]($1: C[Ts]) = $1 // if not repeated
565+
// def unapplySeq[Ts]($1: C[Ts]) = $1 // if repeated
564566
// 2. The default getters of the constructor
565567
// The parent of the companion object of a non-parameterized case class
566568
// (T11, ..., T1N) => ... => (TM1, ..., TMN) => C
@@ -609,9 +611,13 @@ object desugar {
609611
app :: widenDefs
610612
}
611613
val unapplyMeth = {
614+
val hasRepeatedParam = constrVparamss.head.exists {
615+
case ValDef(_, tpt, _) => isRepeated(tpt)
616+
}
617+
val methName = if (hasRepeatedParam) nme.unapplySeq else nme.unapply
612618
val unapplyParam = makeSyntheticParameter(tpt = classTypeRef)
613619
val unapplyRHS = if (arity == 0) Literal(Constant(true)) else Ident(unapplyParam.name)
614-
DefDef(nme.unapply, derivedTparams, (unapplyParam :: Nil) :: Nil, TypeTree(), unapplyRHS)
620+
DefDef(methName, derivedTparams, (unapplyParam :: Nil) :: Nil, TypeTree(), unapplyRHS)
615621
.withMods(synthetic)
616622
}
617623
companionDefs(companionParent, applyMeths ::: unapplyMeth :: companionMembers)

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

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,6 @@ object Applications {
133133
if (args.length > 1 && !(tp.derivesFrom(defn.SeqClass))) {
134134
val sels = productSelectorTypes(tp, pos)
135135
if (sels.length == args.length) sels
136-
else if (isProductSeqMatch(tp, args.length, pos)) productSeqSelectors(tp, args.length, pos)
137136
else tp :: Nil
138137
} else tp :: Nil
139138

@@ -147,7 +146,6 @@ object Applications {
147146
def unapplyArgs(unapplyResult: Type, unapplyFn: Tree, args: List[untpd.Tree], pos: SourcePosition)(implicit ctx: Context): List[Type] = {
148147

149148
val unapplyName = unapplyFn.symbol.name
150-
def seqSelector = defn.RepeatedParamType.appliedTo(unapplyResult.elemType :: Nil)
151149
def getTp = extractorMemberType(unapplyResult, nme.get, pos)
152150

153151
def fail = {
@@ -1100,19 +1098,12 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
11001098

11011099
var argTypes = unapplyArgs(unapplyApp.tpe, unapplyFn, args, tree.sourcePos)
11021100
for (argType <- argTypes) assert(!isBounds(argType), unapplyApp.tpe.show)
1103-
val bunchedArgs =
1104-
if (argTypes.nonEmpty && argTypes.last.isRepeatedParam)
1105-
args.lastOption match {
1106-
case Some(arg @ Typed(argSeq, _)) if untpd.isWildcardStarArg(arg) =>
1107-
args.init :+ argSeq
1108-
case _ =>
1109-
val (regularArgs, varArgs) = args.splitAt(argTypes.length - 1)
1110-
regularArgs :+ untpd.SeqLiteral(varArgs, untpd.TypeTree()).withSpan(tree.span)
1111-
}
1112-
else if (argTypes.lengthCompare(1) == 0 && args.lengthCompare(1) > 0 && ctx.canAutoTuple)
1113-
untpd.Tuple(args) :: Nil
1114-
else
1115-
args
1101+
val bunchedArgs = argTypes match {
1102+
case argType :: Nil =>
1103+
if (args.lengthCompare(1) > 0 && ctx.canAutoTuple) untpd.Tuple(args) :: Nil
1104+
else args
1105+
case _ => args
1106+
}
11161107
if (argTypes.length != bunchedArgs.length) {
11171108
ctx.error(UnapplyInvalidNumberOfArguments(qual, argTypes), tree.sourcePos)
11181109
argTypes = argTypes.take(args.length) ++

tests/run/i3248b.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
object Test {
22
class Foo(val name: String, val children: Int *)
33
object Foo {
4-
def unapply(f: Foo) = Some((f.name, f.children))
4+
def unapplySeq(f: Foo) = Some((f.name, f.children))
55
}
66

77
def foo(f: Foo) = f match {

tests/run/i3248d.scala

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
object Test {
2-
case class Foo(name: String, children: Seq[Int])
2+
class Foo(val name: String, val children: Seq[Int])
3+
4+
object Foo {
5+
def unapplySeq(foo: Foo): (String, Seq[Int]) = (foo.name, foo.children)
6+
}
37

48
def foo(f: Foo) = f match {
5-
case Foo(name, ns) =>
9+
case Foo(name, ns: _*) =>
610
assert(name == "hello")
711
assert(ns(0) == 3)
812
assert(ns(1) == 5)
@@ -19,17 +23,17 @@ object Test {
1923
def qux(f: Foo) = f match {
2024
case Foo(name) => 1
2125
case Foo(name, x, y) => 2
22-
case Foo(name, xs) => 0
26+
case Foo(name, xs: _*) => 0
2327
}
2428

2529

2630
def main(args: Array[String]): Unit = {
27-
val f = Foo("hello", List(3, 5))
31+
val f = new Foo("hello", List(3, 5))
2832
foo(f)
2933
bar(f)
30-
assert(qux(Foo("hello", Nil)) == 1)
31-
assert(qux(Foo("hello", 5 :: 6 :: Nil)) == 2)
32-
assert(qux(Foo("hello", 5 :: Nil)) == 0)
33-
assert(qux(Foo("hello", 5 :: 6 :: 7 :: Nil)) == 0)
34+
assert(qux(new Foo("hello", Nil)) == 1)
35+
assert(qux(new Foo("hello", 5 :: 6 :: Nil)) == 2)
36+
assert(qux(new Foo("hello", 5 :: Nil)) == 0)
37+
assert(qux(new Foo("hello", 5 :: 6 :: 7 :: Nil)) == 0)
3438
}
3539
}

0 commit comments

Comments
 (0)