diff options
author | Paul Phillips <paulp@improving.org> | 2012-01-06 15:51:09 -0800 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2012-01-06 19:35:33 -0800 |
commit | d6346f7c567894e635d92fe9408d2b340c93b9b4 (patch) | |
tree | 27639968bcb682eec97df6d7fc2d57cdb65b4c4a | |
parent | f39537a369e3b137f5b1bef21cc8f5d86bc9d9d8 (diff) | |
download | scala-d6346f7c567894e635d92fe9408d2b340c93b9b4.tar.gz scala-d6346f7c567894e635d92fe9408d2b340c93b9b4.tar.bz2 scala-d6346f7c567894e635d92fe9408d2b340c93b9b4.zip |
Fix for crasher where Arrays meet abstract types.
This sort of thing was crashing. No longer.
trait Fooz[Q <: Array[_]] { def f0(x: Q) = x.length }
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Erasure.scala | 10 | ||||
-rw-r--r-- | test/files/run/array-existential-bound.check | 4 | ||||
-rw-r--r-- | test/files/run/array-existential-bound.scala | 17 |
3 files changed, 27 insertions, 4 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index b327579c8b..f3b1e77c8d 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -887,8 +887,9 @@ abstract class Erasure extends AddInterfaces fun.symbol != Object_isInstanceOf) => // leave all other type tests/type casts, remove all other type applications preErase(fun) - case Apply(fn @ Select(qual, name), args) if (fn.symbol.owner == ArrayClass) => - if (unboundedGenericArrayLevel(qual.tpe.widen) == 1) + case Apply(fn @ Select(qual, name), args) if fn.symbol.owner == ArrayClass => + // Have to also catch calls to abstract types which are bounded by Array. + if (unboundedGenericArrayLevel(qual.tpe.widen) == 1 || qual.tpe.typeSymbol.isAbstractType) { // convert calls to apply/update/length on generic arrays to // calls of ScalaRunTime.array_xxx method calls global.typer.typedPos(tree.pos)({ @@ -901,14 +902,15 @@ abstract class Erasure extends AddInterfaces } gen.mkRuntimeCall(arrayMethodName, qual :: args) }) - else + } + else { // store exact array erasure in map to be retrieved later when we might // need to do the cast in adaptMember treeCopy.Apply( tree, SelectFromArray(qual, name, erasure(tree.symbol, qual.tpe)).copyAttrs(fn), args) - + } case Apply(fn @ Select(qual, _), Nil) if interceptedMethods(fn.symbol) => if (fn.symbol == Any_## || fn.symbol == Object_##) { // This is unattractive, but without it we crash here on ().## because after diff --git a/test/files/run/array-existential-bound.check b/test/files/run/array-existential-bound.check new file mode 100644 index 0000000000..f5cca843e3 --- /dev/null +++ b/test/files/run/array-existential-bound.check @@ -0,0 +1,4 @@ +2 +1000 +1000 +26 diff --git a/test/files/run/array-existential-bound.scala b/test/files/run/array-existential-bound.scala new file mode 100644 index 0000000000..bc442d39f7 --- /dev/null +++ b/test/files/run/array-existential-bound.scala @@ -0,0 +1,17 @@ +trait Fooz[Q <: Array[_]] { + def f0(x: Q) = x.length +} + +object Test extends Fooz[Array[Int]] { + val f1 = new Fooz[Array[String]] { } + val f2 = new Fooz[Array[Int]] { } + val f3 = new Fooz[Array[Any]] { } + val f4 = new Fooz[Array[_]] { } + + def main(args: Array[String]): Unit = { + println(f1.f0(Array[String]("a", "b"))) + println(f2.f0(1 to 1000 toArray)) + println(f3.f0((1 to 1000).toArray[Any])) + println(f4.f0('a' to 'z' toArray)) + } +} |