diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2014-05-21 09:40:33 +0200 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2014-05-21 09:40:33 +0200 |
commit | 75c411c85115d7907f8e2cbe0fb16bd5618ba8a5 (patch) | |
tree | d9de5c63c66d99473acefe98654ff8d730a0ed10 | |
parent | 051456c94b45057c617ae802a427533b9c8590b6 (diff) | |
download | scala-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.scala | 8 | ||||
-rw-r--r-- | test/files/run/t8607.scala | 36 |
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(); + + */ + } +} |