diff options
author | James Iry <jamesiry@gmail.com> | 2013-02-26 17:22:35 -0800 |
---|---|---|
committer | James Iry <jamesiry@gmail.com> | 2013-02-26 20:20:03 -0800 |
commit | 04b147e4a0c226526d3192b68f8efa8953b531ea (patch) | |
tree | d710da2a41a065215610e838faa85f2d933071b9 | |
parent | 208d6ad0bbbb4f7b5021f96bce14606869a6c899 (diff) | |
download | scala-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.scala | 35 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala | 17 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala | 12 | ||||
-rw-r--r-- | test/files/run/t107.check | 1 | ||||
-rw-r--r-- | test/files/run/t107.scala | 8 |
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 |