diff options
author | Lukas Rytz <lukas.rytz@epfl.ch> | 2012-05-11 16:00:54 +0200 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@epfl.ch> | 2012-05-11 16:06:37 +0200 |
commit | 40e7cab7a22a8531bdd310bfb57fda51b798c690 (patch) | |
tree | baf453e3316e46b17c7e1f1a1e58ce31eb1b1763 | |
parent | 2422b064e7a52c04dfb2239fc8e7b9ffbab24251 (diff) | |
download | scala-40e7cab7a22a8531bdd310bfb57fda51b798c690.tar.gz scala-40e7cab7a22a8531bdd310bfb57fda51b798c690.tar.bz2 scala-40e7cab7a22a8531bdd310bfb57fda51b798c690.zip |
Fix SI-5009: case-class copy method now eta-expands over higher parameter 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)).
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Unapplies.scala | 22 | ||||
-rw-r--r-- | test/files/pos/t5720-ownerous.scala | 4 | ||||
-rw-r--r-- | test/files/run/names-defaults.check | 2 | ||||
-rw-r--r-- | test/files/run/names-defaults.scala | 4 | ||||
-rw-r--r-- | test/files/run/t5009.check | 4 | ||||
-rw-r--r-- | test/files/run/t5009.scala | 17 |
6 files changed, 43 insertions, 10 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index 1ebcea4a07..3d9453d8cd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -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) )) } } diff --git a/test/files/pos/t5720-ownerous.scala b/test/files/pos/t5720-ownerous.scala index 3a12499612..ad4d4c171d 100644 --- a/test/files/pos/t5720-ownerous.scala +++ b/test/files/pos/t5720-ownerous.scala @@ -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") diff --git a/test/files/run/names-defaults.check b/test/files/run/names-defaults.check index 5656d1a276..f253de71d6 100644 --- a/test/files/run/names-defaults.check +++ b/test/files/run/names-defaults.check @@ -92,7 +92,7 @@ test5 test5 5 10: 2 -slkdfj1 +slkdfj2 1 lskfdjlk 11 diff --git a/test/files/run/names-defaults.scala b/test/files/run/names-defaults.scala index e1bc7cbf59..220414f02a 100644 --- a/test/files/run/names-defaults.scala +++ b/test/files/run/names-defaults.scala @@ -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)) diff --git a/test/files/run/t5009.check b/test/files/run/t5009.check new file mode 100644 index 0000000000..cc9df54b34 --- /dev/null +++ b/test/files/run/t5009.check @@ -0,0 +1,4 @@ +C(1,true) +10 +C(7283,20) +100 diff --git a/test/files/run/t5009.scala b/test/files/run/t5009.scala new file mode 100644 index 0000000000..b4fe1bc894 --- /dev/null +++ b/test/files/run/t5009.scala @@ -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) + +} |