summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2012-01-06 15:51:09 -0800
committerPaul Phillips <paulp@improving.org>2012-01-06 19:35:33 -0800
commitd6346f7c567894e635d92fe9408d2b340c93b9b4 (patch)
tree27639968bcb682eec97df6d7fc2d57cdb65b4c4a
parentf39537a369e3b137f5b1bef21cc8f5d86bc9d9d8 (diff)
downloadscala-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.scala10
-rw-r--r--test/files/run/array-existential-bound.check4
-rw-r--r--test/files/run/array-existential-bound.scala17
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))
+ }
+}