summaryrefslogtreecommitdiff
path: root/test/files/run/t9697.scala
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2016-09-26 22:11:40 +0200
committerLukas Rytz <lukas.rytz@gmail.com>2016-09-28 10:17:53 +0200
commit19f6209e5b1db295320bfbd3ef00eeaa729c1eec (patch)
tree2d29641720f5eafacd9b020eab1a92c103282080 /test/files/run/t9697.scala
parent6df14e57a4980897d5517f002c04584b82e05b15 (diff)
downloadscala-19f6209e5b1db295320bfbd3ef00eeaa729c1eec.tar.gz
scala-19f6209e5b1db295320bfbd3ef00eeaa729c1eec.tar.bz2
scala-19f6209e5b1db295320bfbd3ef00eeaa729c1eec.zip
SI-9697 / SD-229 Fix DelayedInit subclass capturing local value
When a class captures an outer value, a field for that value is created in the class. The class also gets a constructor parameter for the captured value, the constructor will assign the field. LambdaLift re-writes accesses to the local value (Ident trees) to the field. However, if the statement accessing the local value will end up inside the constructor, the access is re-written to the constructor parameter instead. This is the case for constructor statements: class C { { println(capturedLocal) } } If C extends DelayedInit, the statement does not end up in C's constructor, but into a new synthetic method. The access to `capturedLocal` needs to be re-written to the field instead of the constructor parameter. LambdaLift takes the decision (field or constructor parameter) based on the owner chain of `currentOwner`. For the constructor statement block, the owner is a local dummy, for which `logicallyEnclosingMember` returns the constructor symbol. This commit introduces a special case in LambdaLift for local dummies of DelayedInit subclasses: instead of the constructor, we use a temporary symbol representing the synthetic method holding the initializer statements.
Diffstat (limited to 'test/files/run/t9697.scala')
-rw-r--r--test/files/run/t9697.scala127
1 files changed, 127 insertions, 0 deletions
diff --git a/test/files/run/t9697.scala b/test/files/run/t9697.scala
new file mode 100644
index 0000000000..b837feb237
--- /dev/null
+++ b/test/files/run/t9697.scala
@@ -0,0 +1,127 @@
+object log {
+ val b = new collection.mutable.StringBuilder
+ def apply(s: Any): Unit = b.append(s)
+ def check(s: String) = {
+ val bs = b.toString
+ assert(s == bs, bs)
+ b.clear()
+ }
+}
+
+package t9697 {
+ abstract class WA extends DelayedInit {
+ override def delayedInit(x: => Unit): Unit = x
+ val waField = "4"
+ }
+
+ class C {
+ def b(s: String) = log(s)
+ val cField = "1"
+
+ {
+ val dummyLocal = "2"
+ new WA {
+ val anonField = "3"
+ b(cField)
+ b(dummyLocal)
+ b(anonField)
+ b(waField)
+ }
+ }
+ }
+}
+
+package sd229 {
+ class Broken {
+ def is(ee: AnyRef) = {
+ new Delayed {
+ log(ee)
+ }
+ }
+ }
+
+ class Delayed extends DelayedInit {
+ def delayedInit(x: => Unit): Unit = x
+ }
+}
+
+
+// already fixed in 2.11.8, crashes in 2.10.6
+package t4683a {
+ class A { log("a") }
+ class B { log("b") }
+ class Bug extends DelayedInit {
+ log("bug")
+ def foo(a: A): B = new B
+ def delayedInit(init: => Unit): Unit = init
+ }
+}
+
+// already fixed in 2.12.0-RC1, crashes in 2.11.8
+package t4683b {
+ class Entity extends DelayedInit {
+ def delayedInit(x: => Unit): Unit = x
+
+ class Field
+
+ protected def EntityField[T <: Entity: reflect.ClassTag] = new Field
+
+ def find[T <: Entity: reflect.ClassTag] {
+ Nil.map(dbo => {
+ class EntityHolder extends Entity {
+ val entity = EntityField[T]
+ }
+ })
+ log("find")
+ }
+ }
+}
+
+package t4683c {
+ trait T extends DelayedInit {
+ def delayedInit(body: => Unit) = {
+ log("init")
+ body
+ }
+ }
+}
+
+package t4683d {
+ class C extends DelayedInit {
+ def delayedInit(body: => Unit): Unit = body
+ }
+ class Injector {
+ def test: Object = {
+ val name = "k"
+ class crash extends C {
+ log(name)
+ }
+ new crash()
+ }
+ }
+}
+
+object Test extends App {
+ new t9697.C()
+ log.check("1234")
+
+ new sd229.Broken().is("hi")
+ log.check("hi")
+
+ val a: t4683a.A = new t4683a.A
+ var b: t4683a.B = null
+ new t4683a.Bug {
+ val b = foo(a)
+ }
+ log.check("abugb")
+
+ new t4683b.Entity().find[t4683b.Entity]
+ log.check("find")
+
+ val f = (p1: Int) => new t4683c.T { log(p1) }
+ f(5)
+ log.check("init5")
+
+ new t4683d.Injector().test
+ log.check("k")
+}