From c43b504ac1d843a580683a78eca0cb55bb427c15 Mon Sep 17 00:00:00 2001 From: Vlad Ureche Date: Wed, 12 Jun 2013 14:58:09 +0200 Subject: SI-7343 Fixed phase ordering in specialization Specialization rewires class parents during info transformation, and the new info then guides the tree changes. But if a symbol is created during duplication, which runs after specialization, its info is not visited and thus the corresponding tree is not specialized. One manifestation is the following: ``` object Test { class Parent[@specialized(Int) T] def spec_method[@specialized(Int) T](t: T, expectedXSuper: String) = { class X extends Parent[T]() // even in the specialized variant, the local X class // doesn't extend Parent$mcI$sp, since its symbol has // been created after specialization and was not seen // by specialzation's info transformer. ... } } ``` We can fix this by forcing duplication to take place before specialization. Review by @dragos, @paulp or @axel22. --- test/files/specialized/SI-7343.scala | 55 +++++++++++++++++++++++++++++++++++ test/files/specialized/spec-ame.check | 2 +- test/files/specialized/spec-ame.scala | 3 ++ 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 test/files/specialized/SI-7343.scala (limited to 'test/files/specialized') diff --git a/test/files/specialized/SI-7343.scala b/test/files/specialized/SI-7343.scala new file mode 100644 index 0000000000..5ee683064c --- /dev/null +++ b/test/files/specialized/SI-7343.scala @@ -0,0 +1,55 @@ +class Parent[@specialized(Int) T] + +object Test extends App { + + /** + * This method will check if specialization is correctly rewiring parents + * for classes defined inside methods. The pattern is important since this + * is how closures are currently represented: as locally-defined anonymous + * classes, which usually end up inside methods. For these closures we do + * want their parents rewired correctly: + * + * ``` + * def checkSuperClass$mIc$sp[T](t: T, ...) = { + * class X extends Parent$mcI$sp // instead of just Parent + * ... + * } + */ + def checkSuperClass[@specialized(Int) T](t: T, expectedXSuper: String) = { + // test target: + // - in checkSuperClass, X should extend Parent + // - in checkSuperClass$mIc$sp, X should extend Parent$mcI$sp + class X extends Parent[T]() + + // get the superclass for X and make sure it's correct + val actualXSuper = (new X).getClass().getSuperclass().getSimpleName() + assert(actualXSuper == expectedXSuper, actualXSuper + " != " + expectedXSuper) + } + + checkSuperClass("x", "Parent") + checkSuperClass(101, "Parent$mcI$sp") + + /** + * This is the same check, but in value. It should work exactly the same + * as its method counterpart. + */ + class Val[@specialized(Int) T](t: T, expectedXSuper: String) { + val check: T = { + class X extends Parent[T]() + + // get the superclass for X and make sure it's correct + val actualXSuper = (new X).getClass().getSuperclass().getSimpleName() + assert(actualXSuper == expectedXSuper, actualXSuper + " != " + expectedXSuper) + t + } + } + + new Val("x", "Parent") + new Val(101, "Parent$mcI$sp") + + /** + * NOTE: The the same check, only modified to affect constructors, won't + * work since the class X definition will always be lifted to become a + * member of the class, making it impossible to force its duplication. + */ +} diff --git a/test/files/specialized/spec-ame.check b/test/files/specialized/spec-ame.check index 9c1713cc8a..cf18c01191 100644 --- a/test/files/specialized/spec-ame.check +++ b/test/files/specialized/spec-ame.check @@ -1,3 +1,3 @@ abc 10 -3 \ No newline at end of file +2 diff --git a/test/files/specialized/spec-ame.scala b/test/files/specialized/spec-ame.scala index 79ee4217ed..129fb9f447 100644 --- a/test/files/specialized/spec-ame.scala +++ b/test/files/specialized/spec-ame.scala @@ -13,6 +13,9 @@ object Test { def main(args: Array[String]) { println((new A("abc")).foo.value) println((new A(10)).foo.value) + // before fixing SI-7343, this was printing 3. Now it's printing 2, + // since the anonymous class created by doing new B[T] { ... } when + // T = Int is now rewired to B$mcI$sp instead of just B[Int] println(runtime.BoxesRunTime.integerBoxCount) } } -- cgit v1.2.3