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
View
@@ -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.

Show comment
Hide comment
@tgkprog

tgkprog 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.

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.