summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Iry <jamesiry@gmail.com>2013-02-26 17:22:35 -0800
committerJames Iry <jamesiry@gmail.com>2013-02-26 20:20:03 -0800
commit04b147e4a0c226526d3192b68f8efa8953b531ea (patch)
treed710da2a41a065215610e838faa85f2d933071b9
parent208d6ad0bbbb4f7b5021f96bce14606869a6c899 (diff)
downloadscala-04b147e4a0c226526d3192b68f8efa8953b531ea.tar.gz
scala-04b147e4a0c226526d3192b68f8efa8953b531ea.tar.bz2
scala-04b147e4a0c226526d3192b68f8efa8953b531ea.zip
SI-7159 Prepare to remove erroneous INT <:< LONG in TypeKinds
In preparation for dealing with a problem in TypeKinds, this commit does some cleanup of code related to doing coercions. * Comments are added to clarify. * A println when converting between BOOL and anything else is removed and the code is allowed to flow through to an assertion. * Assertions are refactored to use string interpolation. * A few pattern matches were reformulated to equivalent variants In addition, a test is created for SI-107, the bug that necessitated the special case in GenICode#adapt for LONG coercion
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala35
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala17
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala12
-rw-r--r--test/files/run/t107.check1
-rw-r--r--test/files/run/t107.scala8
5 files changed, 45 insertions, 28 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 3167289a10..a76f7caba2 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -1038,14 +1038,9 @@ abstract class GenICode extends SubComponent {
// A typical example is an overloaded type assigned after typer.
log(s"GenICode#adapt($from, $to, $ctx, $pos)")
- val conforms = (from <:< to)
def coerce(from: TypeKind, to: TypeKind) = ctx.bb.emit(CALL_PRIMITIVE(Conversion(from, to)), pos)
- def checkAssertions() {
- def msg = s"Can't convert from $from to $to in unit ${unit.source} at $pos"
- debugassert(from != UNIT, msg)
- assert(!from.isReferenceType && !to.isReferenceType, msg)
- }
- if (conforms) from match {
+
+ (from, to) match {
// The JVM doesn't have a Nothing equivalent, so it doesn't know that a method of type Nothing can't actually return. So for instance, with
// def f: String = ???
// we need
@@ -1053,15 +1048,23 @@ abstract class GenICode extends SubComponent {
// 3: invokevirtual #29; //Method scala/Predef$.$qmark$qmark$qmark:()Lscala/runtime/Nothing$;
// 6: athrow
// So this case tacks on the ahtrow which makes the JVM happy because class Nothing is declared as a subclass of Throwable
- case NothingReference => ctx.bb.emit(THROW(ThrowableClass)) ; ctx.bb.enterIgnoreMode()
- case _ =>
- // widen subrange types
- if (from.isIntSizedType && to == LONG)
- coerce(INT, LONG)
- }
- else to match {
- case UNIT => ctx.bb.emit(DROP(from), pos) // value discarding
- case _ => checkAssertions() ; coerce(from, to) // other primitive coercions
+ case (NothingReference, _) =>
+ ctx.bb.emit(THROW(ThrowableClass))
+ ctx.bb.enterIgnoreMode()
+ // this special case is needed because of a special case in TypeKinds that
+ // says that the int sized primitives are subtypes of LONG
+ // even though they aren't according to the JVM
+ case (_, LONG) if from.isIntSizedType =>
+ coerce(INT, LONG)
+ case _ if (from <:< to) =>
+ ()
+ case (_, UNIT) =>
+ ctx.bb.emit(DROP(from), pos)
+ // otherwise we'd better be doing a primtive -> primitive coercion or there's a problem
+ case _ if !from.isRefOrArrayType && !to.isRefOrArrayType =>
+ coerce(from, to)
+ case _ =>
+ assert(false, s"Can't convert from $from to $to in unit ${unit.source} at $pos")
}
}
diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
index 6a392449e0..1f8c765a69 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
@@ -88,10 +88,19 @@ trait TypeKinds { self: ICodes =>
final def isNumericType: Boolean = isIntegralType | isRealType
/** Simple subtyping check */
- def <:<(other: TypeKind): Boolean = (this eq other) || (this match {
- case BOOL | BYTE | SHORT | CHAR => other == INT || other == LONG
- case _ => this eq other
- })
+ def <:<(other: TypeKind): Boolean = other match {
+ // On the JVM, BOOL, BYTE, CHAR, SHORT need no coercion to INT
+ // TODO it's pretty suspect to call this a subtyping relationship
+ // for instance JVM Arrays are covariant, but Array[Char] is not
+ // a subtype of Array[Int] on the JVM. However, when I attempted
+ // to remove it I got verify errors when compiling the library
+ // under -optimize
+ case INT => this.isIntSizedType
+ // this case is even more suspect than the previous because
+ // BOOL, BYTE, CHAR, SHORT, and INT need conversion to get to LONG
+ case LONG => this.isIntSizedType || this == LONG
+ case _ => this eq other
+ }
/** Is this type a category 2 type in JVM terms? (ie, is it LONG or DOUBLE?) */
def isWideType: Boolean = false
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
index 91cb1857ac..3830b389ba 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
@@ -2626,8 +2626,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
* @param to The type the value will be converted into.
*/
def emitT2T(from: TypeKind, to: TypeKind) {
- assert(isNonUnitValueTK(from), from)
- assert(isNonUnitValueTK(to), to)
+ assert(isNonUnitValueTK(from) && isNonUnitValueTK(to), s"Cannot emit primitive conversion from $from to $to")
def pickOne(opcs: Array[Int]) {
val chosen = (to: @unchecked) match {
@@ -2643,10 +2642,8 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
}
if(from == to) { return }
- if((from == BOOL) || (to == BOOL)) {
- // the only conversion involving BOOL that is allowed is (BOOL -> BOOL)
- throw new Error("inconvertible types : " + from.toString() + " -> " + to.toString())
- }
+ // the only conversion involving BOOL that is allowed is (BOOL -> BOOL)
+ assert(from != BOOL && to != BOOL, "inconvertible types : $from -> $to")
if(from.isIntSizedType) { // BYTE, CHAR, SHORT, and INT. (we're done with BOOL already)
@@ -2810,8 +2807,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
case Conversion(src, dst) =>
debuglog("Converting from: " + src + " to: " + dst)
- if (dst == BOOL) { println("Illegal conversion at: " + clasz + " at: " + pos.source + ":" + pos.line) }
- else { emitT2T(src, dst) }
+ emitT2T(src, dst)
case ArrayLength(_) => emit(Opcodes.ARRAYLENGTH)
diff --git a/test/files/run/t107.check b/test/files/run/t107.check
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/test/files/run/t107.check
@@ -0,0 +1 @@
+1
diff --git a/test/files/run/t107.scala b/test/files/run/t107.scala
new file mode 100644
index 0000000000..ab1b289882
--- /dev/null
+++ b/test/files/run/t107.scala
@@ -0,0 +1,8 @@
+object Test {
+ def main(args : Array[String]) : Unit = {
+ var hash : Long = 0
+ val bytes = Array(1.toByte, 2.toByte, 3.toByte)
+ hash += bytes(0)
+ Console.println(hash)
+ }
+} \ No newline at end of file