summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2013-08-18 12:32:17 +0200
committerJason Zaugg <jzaugg@gmail.com>2013-08-29 10:44:51 +0200
commit26dfa54ef31687e4c3e5b85be476ee5759f77950 (patch)
tree75779aa9cf7a4d97e8e06f69f8cc7418e5963040
parenta3fad0d1d42b4af4b506ce167209bdeea5cd9d5c (diff)
downloadscala-26dfa54ef31687e4c3e5b85be476ee5759f77950.tar.gz
scala-26dfa54ef31687e4c3e5b85be476ee5759f77950.tar.bz2
scala-26dfa54ef31687e4c3e5b85be476ee5759f77950.zip
SI-7763 Avoid dropping casts in erasure
466b7d29f avoided quadratic complexity in Erasure's treatment of chained `asInstanceOf` calls. It did so by using the typechecked qualifier, rather than discarding it. However, that also dropped the cast altogether! In many cases this was masked by later inclusion of a cast to the expected type by `adaptToType`: at scala.tools.nsc.transform.Erasure$Eraser.cast(Erasure.scala:636) at scala.tools.nsc.transform.Erasure$Eraser.scala$tools$nsc$transform$Erasure$Eraser$$adaptToType(Erasure.scala:665) at scala.tools.nsc.transform.Erasure$Eraser.adapt(Erasure.scala:766) at scala.tools.nsc.typechecker.Typers$Typer.runTyper$1(Typers.scala:5352) This commit re-wraps the typechecked `qual` in its original `<qual>.asInstanceOf[T]` to preserve semantics while avoiding the big-O blowup. The test includes the compiler option `-Ynooptimize` because dead code elimination *also* thinks that this cast is superfluous. I'll follow up on that problem seprately.
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala4
-rw-r--r--test/files/run/t7763.flags1
-rw-r--r--test/files/run/t7763.scala20
3 files changed, 23 insertions, 2 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 0a66ba8a32..5e99a6a933 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -680,7 +680,7 @@ abstract class Erasure extends AddInterfaces
private def adaptMember(tree: Tree): Tree = {
//Console.println("adaptMember: " + tree);
tree match {
- case Apply(TypeApply(sel @ Select(qual, name), List(targ)), List())
+ case Apply(ta @ TypeApply(sel @ Select(qual, name), List(targ)), List())
if tree.symbol == Any_asInstanceOf =>
val qual1 = typedQualifier(qual, NOmode, ObjectTpe) // need to have an expected type, see #3037
@@ -705,7 +705,7 @@ abstract class Erasure extends AddInterfaces
// }
typed(untyped)
}
- } else qual1
+ } else treeCopy.Apply(tree, treeCopy.TypeApply(ta, treeCopy.Select(sel, qual1, name), List(targ)), List())
case Apply(TypeApply(sel @ Select(qual, name), List(targ)), List())
if tree.symbol == Any_isInstanceOf =>
diff --git a/test/files/run/t7763.flags b/test/files/run/t7763.flags
new file mode 100644
index 0000000000..7f4215d1bc
--- /dev/null
+++ b/test/files/run/t7763.flags
@@ -0,0 +1 @@
+-Ynooptimize \ No newline at end of file
diff --git a/test/files/run/t7763.scala b/test/files/run/t7763.scala
new file mode 100644
index 0000000000..638077e64a
--- /dev/null
+++ b/test/files/run/t7763.scala
@@ -0,0 +1,20 @@
+object Test {
+ class A; class B
+ def main(args: Array[String]) {
+ def noExpectedType() {
+ a().asInstanceOf[B] // cast elided!
+ }
+ def withExpectedType(): B = {
+ a().asInstanceOf[B]
+ }
+ def test(a: => Any) = try {
+ a
+ sys.error("no CCE!")
+ } catch {case _: ClassCastException => }
+
+ test(noExpectedType())
+ test(withExpectedType())
+ }
+
+ def a(): Object = new A
+}