diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2013-08-18 12:32:17 +0200 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2013-08-29 10:44:51 +0200 |
commit | 26dfa54ef31687e4c3e5b85be476ee5759f77950 (patch) | |
tree | 75779aa9cf7a4d97e8e06f69f8cc7418e5963040 | |
parent | a3fad0d1d42b4af4b506ce167209bdeea5cd9d5c (diff) | |
download | scala-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.scala | 4 | ||||
-rw-r--r-- | test/files/run/t7763.flags | 1 | ||||
-rw-r--r-- | test/files/run/t7763.scala | 20 |
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 +} |