summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2014-05-21 09:40:33 +0200
committerJason Zaugg <jzaugg@gmail.com>2014-05-21 09:40:33 +0200
commit75c411c85115d7907f8e2cbe0fb16bd5618ba8a5 (patch)
treed9de5c63c66d99473acefe98654ff8d730a0ed10
parent051456c94b45057c617ae802a427533b9c8590b6 (diff)
downloadscala-75c411c85115d7907f8e2cbe0fb16bd5618ba8a5.tar.gz
scala-75c411c85115d7907f8e2cbe0fb16bd5618ba8a5.tar.bz2
scala-75c411c85115d7907f8e2cbe0fb16bd5618ba8a5.zip
SI-8607 Fix erasure for value class inheriting from private class
The fix for SI-4283 added a pre-emptive cast of the qualifier of a selection `qual.a` to avoid later casting to the owner of `a` if that owner might be inaccessible at the call site. This fixed a `LinkageError`. In the enclosed test, this cast led to the following diff in the tree shapes (with respect to a version with a public base class). [erasure] - new p1.C.<init>(c.$asInstanceOf[scala.this.Int]()).a(); + new p1.C.<init>(new p1.C.<init>(c.$asInstanceOf[scala.this.Int]()).$asInstanceOf[ErasedValueType( class C, scala.this.Int)]().$asInstanceOf[scala.this.Int]()).a(); [posterasure] - new p1.C.<init>(c).a(); + new p1.C.<init>(new p1.C.<init>(c).$asInstanceOf[scala.this.Int]().$asInstanceOf[scala.this.Int]()) .a(); () What we really wanted to end up with is: new p1.C.<init>(c).$asInstanceOf[C]().a(); The stray cast leads to the crash: error: should have been unboxed by erasure: new p1.C.<init>(c).$asInstanceOf[scala.this.Int]() Rather than trying to fix this in erasure/posterasure, this commit instead relies on the fact the owner of `a` cannot be Java defined if `qual`s type is a derived value class. This follows from the restrictions we place on value classes. With this knowledge, we elide the cast altogether in this case.
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala8
-rw-r--r--test/files/run/t8607.scala36
2 files changed, 43 insertions, 1 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index e036035397..e31cb02033 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -1066,7 +1066,13 @@ abstract class Erasure extends AddInterfaces
if (isAccessible(qualSym) && !qualSym.isPackageClass && !qualSym.isPackageObjectClass) {
// insert cast to prevent illegal access error (see #4283)
// util.trace("insert erasure cast ") (*/
- treeCopy.Select(tree, gen.mkAttributedCast(qual, qual.tpe.widen), name) //)
+ if (qualSym.isDerivedValueClass) {
+ assert(!owner.isJavaDefined, owner)
+ // Safe, as derived value can't extend Java classes that would be JVM inaccessible
+ devWarning("SI-8607 Not casting qualifier ${qual} to its widened type as it is a derived value class and this cast will trip up the rest of erasure/post erasure.")
+ tree
+ } else
+ treeCopy.Select(tree, gen.mkAttributedCast(qual, qual.tpe.widen), name) //)
} else tree
}
} else tree
diff --git a/test/files/run/t8607.scala b/test/files/run/t8607.scala
new file mode 100644
index 0000000000..1b8ef9bbd0
--- /dev/null
+++ b/test/files/run/t8607.scala
@@ -0,0 +1,36 @@
+package p1 {
+ private[p1] trait B extends Any {
+ def a: Any = ""
+ }
+
+ class C(val value: Int) extends AnyVal with B {
+ // def b = ""
+ }
+}
+
+object Test {
+ def main(args: Array[String]) {
+ val c = new p1.C(42)
+ c.a
+ /*
+ new p1.C.<init>(
+ c.$asInstanceOf[scala.this.Int]()
+ ).a();
+
+
+ new p1.C.<init>(
+ new p1.C.<init>(
+ c.$asInstanceOf[scala.this.Int]()
+ ).$asInstanceOf[ErasedValueType(class C, scala.this.Int)]()
+ .$asInstanceOf[scala.this.Int]()
+ ).a();
+
+ new p1.C.<init>(
+ new p1.C.<init>(c)
+ .$asInstanceOf[scala.this.Int]()
+ .$asInstanceOf[scala.this.Int]()
+ ).a();
+
+ */
+ }
+}