diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2016-09-26 22:11:40 +0200 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2016-09-28 10:17:53 +0200 |
commit | 19f6209e5b1db295320bfbd3ef00eeaa729c1eec (patch) | |
tree | 2d29641720f5eafacd9b020eab1a92c103282080 /test/files | |
parent | 6df14e57a4980897d5517f002c04584b82e05b15 (diff) | |
download | scala-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')
-rw-r--r-- | test/files/run/t9697.check | 1 | ||||
-rw-r--r-- | test/files/run/t9697.scala | 127 |
2 files changed, 128 insertions, 0 deletions
diff --git a/test/files/run/t9697.check b/test/files/run/t9697.check new file mode 100644 index 0000000000..bbd9fd19cf --- /dev/null +++ b/test/files/run/t9697.check @@ -0,0 +1 @@ +warning: there were 6 deprecation warnings (since 2.11.0); re-run with -deprecation for details 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") +} |