summaryrefslogtreecommitdiff
path: root/test/files/run/outertest.scala
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2013-03-14 12:50:52 +0400
committerJason Zaugg <jzaugg@gmail.com>2013-03-23 15:39:57 +0100
commitcd9e03af8d61e7def5df2a0958de31ca0c163780 (patch)
tree1b5f0eaa8bbb6903c753abb70da60a9d4a7c1213 /test/files/run/outertest.scala
parentb7b4f877326acd6a8a24ff60fa1638cc18143c45 (diff)
downloadscala-cd9e03af8d61e7def5df2a0958de31ca0c163780.tar.gz
scala-cd9e03af8d61e7def5df2a0958de31ca0c163780.tar.bz2
scala-cd9e03af8d61e7def5df2a0958de31ca0c163780.zip
SI-7246 Make $outer pointer elision Java aware
In e0853b3, a space-saving optimization elided the outer pointer of inner classes if the the (protected) outer pointer of the immediate parent class was guaranteed to point to the same instance. But, this check failed to account for Java parent classes, which don't follow the Scala scheme. This commit disables the optimization in that case. The original test case in e0853b3 was anemic, I've fleshed it out to: - test the presense or absense of $outer pointers with Java reflection - test the optimization works in the presense of aliased and annotated aliased types. (The former worked already, the latter required a change to the implementation.) - Test the negative case when the prefixes don't line up and the subclass in fact needs its own $outer. This patch is based on work by Euguene Vigdorchik with some additions by Jason Zaugg.
Diffstat (limited to 'test/files/run/outertest.scala')
-rw-r--r--test/files/run/outertest.scala47
1 files changed, 39 insertions, 8 deletions
diff --git a/test/files/run/outertest.scala b/test/files/run/outertest.scala
index 3cc96afa5b..fa0443f669 100644
--- a/test/files/run/outertest.scala
+++ b/test/files/run/outertest.scala
@@ -1,26 +1,57 @@
// A test for the case where the outer field of class B#J should be eliminated.
-// You can verify this by running a javap on B.J
+
+import reflect.ClassTag
+
abstract class A {
+ abstract class I
- abstract class I {
+ val foo = this
+}
+class B extends A {
+ class J extends I {
+ val bar = foo
}
- val foo = "foo"
+ type II = I
+ class K extends II {
+ val bar = foo
+ }
+ class L extends (I @annotation.tailrec) {
+ val bar = foo
+ }
}
-class B extends A {
- class J extends I {
+class C extends A {
+ val c: C = this
+
+ class M extends c.I {
val bar = foo
}
-
}
-object Test extends App {
+object Test extends App {
val b = new B
- assert((new b.J).bar == b.foo)
+ val c0 = new C
+ val c = new { override val c = c0 } with C
+
+ assert((new b.J).bar eq b)
+ assert((new b.K).bar eq b)
+ assert((new b.L).bar eq b)
+ assert((new c.M).bar eq c)
+
+ def checkOuterFields[C: ClassTag](expected: Int) {
+ val cls = implicitly[ClassTag[C]].runtimeClass
+ val outerFields = cls.getDeclaredFields().filter(_.getName.contains("$outer"))
+ assert(outerFields.size == expected, outerFields.map(_.getName))
+ }
+ checkOuterFields[A#I](1) // the base class must have the $outer pointer
+ checkOuterFields[B#J](0) // reuse parent class' $outer pointer
+ checkOuterFields[B#K](0) // ... through an alias
+ checkOuterFields[B#L](0) // ... through the annotated type
+ checkOuterFields[C#M](1) // different prefix, can't share.
}