Skip to content
Permalink
Browse files

Fix SI-5009: case-class copy method now eta-expands over higher param…

…eter lists.

Example: Given

  case class C(a: Int)(b: Int)

if you call (new C(1)(2)).copy(a = 10)), you get a function (f: Int => C) such
that (f.apply(20)) yields a (new C(10)(20)).
  • Loading branch information
lrytz committed May 11, 2012
1 parent 2422b06 commit 40e7cab7a22a8531bdd310bfb57fda51b798c690
@@ -210,13 +210,25 @@ trait Unapplies extends ast.TreeDSL
// and re-added in ``finishWith'' in the namer.
def paramWithDefault(vd: ValDef) =
treeCopy.ValDef(vd, vd.mods | DEFAULTPARAM, vd.name, atPos(vd.pos.focus)(TypeTree() setOriginal vd.tpt), toIdent(vd))

val paramss = mmap(cparamss)(paramWithDefault)
val classTpe = classType(cdef, tparams)

val (copyParamss, funParamss) = cparamss match {
case Nil => (Nil, Nil)
case ps :: pss =>
(List(ps.map(paramWithDefault)), mmap(pss)(p => copyUntyped[ValDef](p).copy(rhs = EmptyTree)))
}

val classTpe = classType(cdef, tparams)
val bodyTpe = funParamss.foldRight(classTpe)((params, restp) => gen.scalaFunctionConstr(params.map(_.tpt), restp))

val argss = copyParamss match {
case Nil => Nil
case ps :: Nil => mmap(ps :: funParamss)(toIdent)
}
val body = funParamss.foldRight(New(classTpe, argss): Tree)(Function)

Some(atPos(cdef.pos.focus)(
DefDef(Modifiers(SYNTHETIC), nme.copy, tparams, paramss, classTpe,
New(classTpe, mmap(paramss)(toIdent)))
DefDef(Modifiers(SYNTHETIC), nme.copy, tparams, copyParamss, bodyTpe,
body)
))
}
}
@@ -28,10 +28,10 @@ class C {
//def model = Option(M("foo")()).getOrElse(M("bar")()).copy(currentUser = "")()

// the bug
def model = Option(m).getOrElse(M("bar")()).copy("baz")()
def model = Option(m).getOrElse(M("bar")()).copy("baz")("empty")

// style points for this version
def modish = ((null: Option[M]) getOrElse new M()()).copy()()
def modish = ((null: Option[M]) getOrElse new M()()).copy()("empty")

// various simplifications are too simple
case class N(currentUser: String = "anon")
@@ -92,7 +92,7 @@ test5
test5
5
10: 2
slkdfj1
slkdfj2
1
lskfdjlk
11
@@ -176,7 +176,7 @@ object Test extends App {

println(Fact2()("jyp"))
println(Fact2(x = 1)())
println(Fact2(10)().copy(y = "blabla")())
println(Fact2(10)().copy(y = "blabla")(3))


// assignment to var <-> named argument
@@ -195,7 +195,7 @@ object Test extends App {
// dependent types and copy method
val a11 = new A2
val b11 = a11.B2(new a11.C2)(1)
println(b11.copy()())
println(b11.copy()(2))



@@ -0,0 +1,4 @@
C(1,true)
10
C(7283,20)
100
@@ -0,0 +1,17 @@
object Test extends App {

case class C[T, U <: String, O >: Object](x: Int, y: T)(z: U, b: Boolean)(s: O, val l: Int)

val c = C(1, true)("dlkfj", true)("dlkfjlk", 10)
println(c)
println(c.l)

val f1a = c.copy(y = 20, x = 7283)

val f1b = c.copy[Int, String, Object](y = 20, x = 7283)
val f2b = f1b("lkdjen", false)
val res = f2b(new Object, 100)
println(res)
println(res.l)

}

1 comment on commit 40e7cab

@tgkprog

This comment has been minimized.

Copy link

@tgkprog tgkprog commented on 40e7cab Nov 18, 2016

Wish there was an annotation or some signal saying we want this in a copyAll function do we do not need to spin our own. It is useful to have them copied over in many cases.

Please sign in to comment.
You can’t perform that action at this time.