summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/CheckerException.scala (renamed from src/compiler/scala/tools/nsc/backend/icode/CheckerError.scala)0
-rw-r--r--src/compiler/scala/tools/nsc/symtab/StdNames.scala1
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala38
-rw-r--r--test/files/run/bug3175.check8
-rw-r--r--test/files/run/bug3175.scala44
5 files changed, 76 insertions, 15 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/CheckerError.scala b/src/compiler/scala/tools/nsc/backend/icode/CheckerException.scala
index 9d102eef28..9d102eef28 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/CheckerError.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/CheckerException.scala
diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
index 98f87ca362..5ce0025de5 100644
--- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala
+++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
@@ -295,6 +295,7 @@ trait StdNames extends reflect.generic.StdNames { self: SymbolTable =>
val hasNext = newTermName("hasNext")
val head = newTermName("head")
val invoke_ = newTermName("invoke")
+ val isArray = newTermName("isArray")
val isInstanceOf_ = newTermName("isInstanceOf")
val isDefinedAt = newTermName("isDefinedAt")
val isEmpty = newTermName("isEmpty")
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
index 114f49ad50..107a73aa66 100644
--- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala
+++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
@@ -338,6 +338,22 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
val methSym = ad.symbol
def args = qual :: params
+ def isArrayMethodSignature = {
+ def typesMatchApply = paramTypes match {
+ case List(tp) => tp <:< IntClass.tpe
+ case _ => false
+ }
+ def typesMatchUpdate = paramTypes match {
+ case List(tp1, tp2) => (tp1 <:< IntClass.tpe) && (UnitClass.tpe <:< structResType)
+ case _ => false
+ }
+
+ (methSym.name == nme.length && params.isEmpty) ||
+ (methSym.name == nme.clone_ && params.isEmpty) ||
+ (methSym.name == nme.apply && typesMatchApply) ||
+ (methSym.name == nme.update && typesMatchUpdate)
+ }
+
/** Normal non-Array call */
def defaultCall = {
// reflective method call machinery
@@ -361,33 +377,25 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
(getPrimitiveReplacementForStructuralCall isDefinedAt methSym.name) &&
((resType :: paramTypes) forall (x => isJavaValueClass(x.typeSymbol))) // issue #1110
- def isArrayMethodSignature =
- (methSym.name == nme.length && params.isEmpty) ||
- (methSym.name == nme.update && (structResType.typeSymbol eq UnitClass) && params.size == 2) ||
- (methSym.name == nme.apply && params.size == 1) ||
- (methSym.name == nme.clone_ && params.isEmpty)
-
- def isDefinitelyArray = isArrayMethodSignature && (qualSym == ArrayClass)
- def isMaybeArray = isArrayMethodSignature && (qualSym == ObjectClass) // precondition: !isDefinitelyArray
-
def genArrayCall = methSym.name match {
case nme.length => REF(boxMethod(IntClass)) APPLY (REF(arrayLengthMethod) APPLY args)
case nme.update => REF(arrayUpdateMethod) APPLY List(args(0), (REF(unboxMethod(IntClass)) APPLY args(1)), args(2))
case nme.apply => REF(arrayApplyMethod) APPLY List(args(0), (REF(unboxMethod(IntClass)) APPLY args(1)))
case nme.clone_ => REF(arrayCloneMethod) APPLY List(args(0))
}
- def genArrayTest = {
- def oneTest(s: Symbol) = qual IS_OBJ arrayType(s.tpe)
- OR((ObjectClass :: ScalaValueClasses filterNot (_ eq UnitClass)) map oneTest: _*)
- }
+ def genConditionalArrayCall =
+ IF ((qual GETCLASS()) DOT nme.isArray) THEN genArrayCall ELSE defaultCall
val callCode =
if (useValueOperator) {
val (operator, test) = getPrimitiveReplacementForStructuralCall(methSym.name)
IF (test) THEN fixResult(REF(operator) APPLY args) ELSE defaultCall
}
- else if (isDefinitelyArray) genArrayCall
- else if (isMaybeArray) IF (genArrayTest) THEN genArrayCall ELSE defaultCall
+ else if (isArrayMethodSignature) {
+ if (qualSym == ArrayClass) genArrayCall
+ else if (qualSym == ObjectClass) genConditionalArrayCall
+ else defaultCall
+ }
else defaultCall
localTyper typed callCode
diff --git a/test/files/run/bug3175.check b/test/files/run/bug3175.check
new file mode 100644
index 0000000000..daf2c23ab5
--- /dev/null
+++ b/test/files/run/bug3175.check
@@ -0,0 +1,8 @@
+10
+15
+3
+3
+3
+5
+5
+5
diff --git a/test/files/run/bug3175.scala b/test/files/run/bug3175.scala
new file mode 100644
index 0000000000..9cccff52f9
--- /dev/null
+++ b/test/files/run/bug3175.scala
@@ -0,0 +1,44 @@
+/** A bit down the road this test will examine
+ * the bytecode.
+ */
+object Test {
+ def len(x:{ def length: Int }) = x.length
+ def f1(x:{ def apply(x: Int): Long }) = x(0)
+ def f2(x:{ def apply(x: Int): Byte }) = x(0)
+ def f3(x:{ def apply(x: Int): String }) = x(0).length
+
+ def f4(x:{ def update(x: Int, y: Long): Unit }, y: Long) = x(0) = y
+ def f5(x:{ def update(x: Int, y: Byte): Unit }, y: Byte) = x(0) = y
+ def f6(x:{ def update(x: Int, y: String): Unit }, y: String) = x(0) = y
+
+ def f7(x: { def length: Any }) = x.length
+
+ def f8(x: { def apply(x: Int): Any }) = x(0)
+ def f9(x: { def apply(x: Int): Int }) = x(0)
+ def f10(x: { def apply(x: Int): Long }) = x(0)
+
+ // doesn't work yet, see #3197
+ // def fclone(x:{ def clone(): AnyRef }) = x.clone()
+
+ def main(args: Array[String]): Unit = {
+ val longs = Array(5L)
+ val bytes = Array(5: Byte)
+ val strs = Array("abcde", "fghjij")
+
+ println(len(Array(1,2,3)) + len(Array(4.0,5.0f)) + len(Array("abc", 5)) + len("bop"))
+ println(f1(longs) + f2(bytes) + f3(strs))
+
+ f4(longs, 1)
+ f5(bytes, 1)
+ f6(strs, "a")
+
+ println(f1(longs) + f2(bytes) + f3(strs))
+
+ println(f7(Array(1,2,3)))
+ println(f7("def"))
+
+ println(f8(Array(5)))
+ println(f9(Array(5)))
+ println(f10(Array(5)))
+ }
+}