summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorGilles Dubochet <gilles.dubochet@epfl.ch>2007-04-30 18:14:11 +0000
committerGilles Dubochet <gilles.dubochet@epfl.ch>2007-04-30 18:14:11 +0000
commit750e57765b10d0f072eff68274047daa1c2040ae (patch)
tree8a3b19243e0ccc7ef54d6f5aaf4dd931120fd57d /src/compiler
parent10aa20170079d81f3e80d1cf5d0fc821336ae2d9 (diff)
downloadscala-750e57765b10d0f072eff68274047daa1c2040ae.tar.gz
scala-750e57765b10d0f072eff68274047daa1c2040ae.tar.bz2
scala-750e57765b10d0f072eff68274047daa1c2040ae.zip
Changed Scala's value boxing scheme to be compa...
Changed Scala's value boxing scheme to be compatible with java's wrapping classes. - “Definitions” redefines what the boxed correspondants of value types are. - “GenJVM” uses the new (un)boxing methods defined in “BoxesUtility” (MSIL not updated yet). - “GenICode” special cases the “equals” method (to that of “Comparator”) in some cases to deal with Java's silly definition of equality on wrapped values. - Various other fixes (in erasure to deal properly with boxing of labelled expressions, big integers, etc.).
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala172
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala57
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala175
-rw-r--r--src/compiler/scala/tools/nsc/symtab/StdNames.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala89
5 files changed, 278 insertions, 217 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 5752b96240..a33a820e05 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -583,8 +583,11 @@ abstract class GenICode extends SubComponent {
} else
ctx1.bb.emit(CONSTANT(Constant(false)))
}
- else if (r.isValueType /*|| r.isArrayType */)
- genBoxedConversion(l, r, ctx1, cast)
+ else if (r.isValueType && cast) {
+ assert(false) /* Erasure should have added an unboxing operation to prevent that. */
+ }
+ else if (r.isValueType)
+ ctx.bb.emit(IS_INSTANCE(REFERENCE(definitions.boxedClass(r.toType.symbol))))
else
genCast(l, r, ctx1, cast);
@@ -653,8 +656,8 @@ abstract class GenICode extends SubComponent {
if (settings.debug.value)
log("BOX : " + fun.symbol.fullNameString);
val ctx1 = genLoad(expr, ctx, toTypeKind(expr.tpe))
- val boxType = fun.symbol.owner.linkedClassOfClass.tpe
- ctx1.bb.emit(BOX(toTypeKind(boxType)), expr.pos)
+ val nativeKind = toTypeKind(expr.tpe)
+ ctx1.bb.emit(BOX(nativeKind), expr.pos)
generatedType = ANY_REF_CLASS
ctx1
@@ -663,8 +666,8 @@ abstract class GenICode extends SubComponent {
log("UNBOX : " + fun.symbol.fullNameString)
val ctx1 = genLoad(expr, ctx, toTypeKind(expr.tpe))
assert(expectedType.isValueType)
- generatedType = toTypeKind(fun.symbol.owner.linkedClassOfClass.tpe)
- ctx1.bb.emit(UNBOX(generatedType), expr.pos)
+ generatedType = expectedType
+ ctx1.bb.emit(UNBOX(expectedType), expr.pos)
ctx1
case Apply(fun, args) =>
@@ -999,11 +1002,6 @@ abstract class GenICode extends SubComponent {
def isStaticSymbol(s: Symbol): Boolean =
s.hasFlag(Flags.STATIC) || s.hasFlag(Flags.STATICMEMBER) || s.owner.isImplClass
-// def isUnbox(s: Symbol): Boolean = (
-// s.name.==(nme.unbox) && s.owner.isModuleClass
-// && s.owner.linkedClassOfClass.isSubClass(definitions.AnyValClass)
-// )
-
/**
* Generate code that loads args into label parameters.
*/
@@ -1057,42 +1055,6 @@ abstract class GenICode extends SubComponent {
}
}
- /** Generate a conversion from a reference type to a value type, like in
- * Any -> Array[Int] or Any -> Int
- *
- * @param from ...
- * @param to ...
- * @param ctx ...
- * @param cast ...
- */
- def genBoxedConversion(from: TypeKind, to: TypeKind, ctx: Context, cast: Boolean): Unit = {
- assert(to.isValueType || to.isArrayType,
- "Expecting conversion to value type: " + to)
-
- val boxedCls = to match {
- case ARRAY(ARRAY(_)) | ARRAY(REFERENCE(_)) =>
- definitions.BoxedObjectArrayClass
- case ARRAY(elem) =>
- definitions.boxedArrayClass(elem.toType.symbol)
- case _ =>
- if (cast) {
- ctx.bb.emit(UNBOX(to))
- return
- }
- else
- definitions.boxedClass(to.toType.symbol)
- }
-
- if (cast) {
- ctx.bb.emit(CHECK_CAST(REFERENCE(boxedCls)))
- ctx.bb.emit(CONSTANT(Constant(definitions.signature(to.toType))))
- ctx.bb.emit(CALL_METHOD(definitions.getMember(boxedCls, "unbox"),
- Dynamic))
- } else {
- ctx.bb.emit(IS_INSTANCE(REFERENCE(boxedCls)))
- }
- }
-
def genCast(from: TypeKind, to: TypeKind, ctx: Context, cast: Boolean) =
ctx.bb.emit(if (cast) CHECK_CAST(to) else IS_INSTANCE(to))
@@ -1331,8 +1293,8 @@ abstract class GenICode extends SubComponent {
if (code == scalaPrimitives.ZNOT) {
val Select(leftArg, _) = fun
genCond(leftArg, ctx, elseCtx, thenCtx)
- } else if ((code == scalaPrimitives.EQ ||
- code == scalaPrimitives.NE)) {
+ }
+ else if ((code == scalaPrimitives.EQ || code == scalaPrimitives.NE)) {
val Select(leftArg, _) = fun;
if (toTypeKind(leftArg.tpe).isReferenceType) {
if (code == scalaPrimitives.EQ)
@@ -1342,10 +1304,12 @@ abstract class GenICode extends SubComponent {
}
else
genComparisonOp(leftArg, args.head, code);
- } else if (scalaPrimitives.isComparisonOp(code)) {
+ }
+ else if (scalaPrimitives.isComparisonOp(code)) {
val Select(leftArg, _) = fun
genComparisonOp(leftArg, args.head, code)
- } else {
+ }
+ else {
code match {
case scalaPrimitives.ZAND =>
val Select(leftArg, _) = fun
@@ -1362,6 +1326,9 @@ abstract class GenICode extends SubComponent {
genCond(args.head, ctxInterm, thenCtx, elseCtx)
case _ =>
+ // TODO (maybe): deal with the equals case here
+ // Current semantics: rich equals (from runtime.Comparator) only when == is used
+ // See genEqEqPrimitive for implementation
var ctx1 = genLoad(tree, ctx, BOOL)
ctx1.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL), tree.pos)
ctx1.bb.close
@@ -1403,51 +1370,76 @@ abstract class GenICode extends SubComponent {
local
}
- (l, r) match {
- // null == expr -> expr eq null
- case (Literal(Constant(null)), expr) =>
- val ctx1 = genLoad(expr, ctx, ANY_REF_CLASS)
- ctx1.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ANY_REF_CLASS))
- ctx1.bb.close
+ def mustUseAnyComparator: Boolean = {
+ val lsym = l.tpe.symbol
+ val rsym = r.tpe.symbol
+ (lsym == definitions.ObjectClass) ||
+ (rsym == definitions.ObjectClass) ||
+ (lsym isNonBottomSubClass definitions.BoxedNumberClass)||
+ (lsym isNonBottomSubClass definitions.BoxedCharacterClass) ||
+ (rsym isNonBottomSubClass definitions.BoxedNumberClass) ||
+ (rsym isNonBottomSubClass definitions.BoxedCharacterClass)
+ }
- // expr == null -> if(expr eq null) true else expr.equals(null)
- case (expr, Literal(Constant(null))) =>
- val eqEqTempLocal = getTempLocal
- var ctx1 = genLoad(expr, ctx, ANY_REF_CLASS)
- ctx1.bb.emit(DUP(ANY_REF_CLASS))
- ctx1.bb.emit(STORE_LOCAL(eqEqTempLocal), l.pos)
- val nonNullCtx = ctx1.newBlock
- ctx1.bb.emit(CZJUMP(thenCtx.bb, nonNullCtx.bb, EQ, ANY_REF_CLASS))
- ctx1.bb.close
+ if (mustUseAnyComparator) {
- nonNullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal), l.pos)
- nonNullCtx.bb.emit(CONSTANT(Constant(null)), r.pos)
- nonNullCtx.bb.emit(CALL_METHOD(definitions.Object_equals, Dynamic))
- nonNullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL))
- nonNullCtx.bb.close
+ val ctx1 = genLoad(l, ctx, ANY_REF_CLASS)
+ val ctx2 = genLoad(r, ctx1, ANY_REF_CLASS)
+ ctx2.bb.emit(CALL_METHOD(definitions.Comparator_equals, Static(false)))
+ ctx2.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL))
+ ctx2.bb.close
- // l == r -> if (l eq null) r eq null else l.equals(r)
- case _ =>
- val eqEqTempLocal = getTempLocal
- var ctx1 = genLoad(l, ctx, ANY_REF_CLASS)
- ctx1 = genLoad(r, ctx1, ANY_REF_CLASS)
- val nullCtx = ctx1.newBlock
- val nonNullCtx = ctx1.newBlock
- ctx1.bb.emit(STORE_LOCAL(eqEqTempLocal), l.pos)
- ctx1.bb.emit(DUP(ANY_REF_CLASS))
- ctx1.bb.emit(CZJUMP(nullCtx.bb, nonNullCtx.bb, EQ, ANY_REF_CLASS))
- ctx1.bb.close
+ }
+ else {
- nullCtx.bb.emit(DROP(ANY_REF_CLASS), l.pos) // type of AnyRef
- nullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal))
- nullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ANY_REF_CLASS))
- nullCtx.bb.close
+ (l, r) match {
+ // null == expr -> expr eq null
+ case (Literal(Constant(null)), expr) =>
+ val ctx1 = genLoad(expr, ctx, ANY_REF_CLASS)
+ ctx1.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ANY_REF_CLASS))
+ ctx1.bb.close
+
+ // expr == null -> if(expr eq null) true else expr.equals(null)
+ case (expr, Literal(Constant(null))) =>
+ val eqEqTempLocal = getTempLocal
+ var ctx1 = genLoad(expr, ctx, ANY_REF_CLASS)
+ ctx1.bb.emit(DUP(ANY_REF_CLASS))
+ ctx1.bb.emit(STORE_LOCAL(eqEqTempLocal), l.pos)
+ val nonNullCtx = ctx1.newBlock
+ ctx1.bb.emit(CZJUMP(thenCtx.bb, nonNullCtx.bb, EQ, ANY_REF_CLASS))
+ ctx1.bb.close
+
+ nonNullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal), l.pos)
+ nonNullCtx.bb.emit(CONSTANT(Constant(null)), r.pos)
+ nonNullCtx.bb.emit(CALL_METHOD(definitions.Object_equals, Dynamic))
+ nonNullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL))
+ nonNullCtx.bb.close
+
+ // l == r -> if (l eq null) r eq null else l.equals(r)
+ case _ =>
+ val eqEqTempLocal = getTempLocal
+ var ctx1 = genLoad(l, ctx, ANY_REF_CLASS)
+ ctx1 = genLoad(r, ctx1, ANY_REF_CLASS)
+ val nullCtx = ctx1.newBlock
+ val nonNullCtx = ctx1.newBlock
+ ctx1.bb.emit(STORE_LOCAL(eqEqTempLocal), l.pos)
+ ctx1.bb.emit(DUP(ANY_REF_CLASS))
+ ctx1.bb.emit(CZJUMP(nullCtx.bb, nonNullCtx.bb, EQ, ANY_REF_CLASS))
+ ctx1.bb.close
+
+ nullCtx.bb.emit(DROP(ANY_REF_CLASS), l.pos) // type of AnyRef
+ nullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal))
+ nullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ANY_REF_CLASS))
+ nullCtx.bb.close
+
+ nonNullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal), l.pos)
+ nonNullCtx.bb.emit(CALL_METHOD(definitions.Object_equals, Dynamic))
+ nonNullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL))
+ nonNullCtx.bb.close
+ }
- nonNullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal), l.pos)
- nonNullCtx.bb.emit(CALL_METHOD(definitions.Object_equals, Dynamic))
- nonNullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL))
- nonNullCtx.bb.close
}
+
}
/**
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index 5f2613e59d..b55389216c 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -57,7 +57,6 @@ abstract class GenJVM extends SubComponent {
class BytecodeGenerator {
val MIN_SWITCH_DENSITY = 0.7
val JAVA_LANG_STRINGBUFFER = "java.lang.StringBuffer"
- val BOXED_NUMBER = "scala.runtime.BoxedNumber"
val stringBufferType = new JObjectType(JAVA_LANG_STRINGBUFFER)
val toStringType = new JMethodType(JObjectType.JAVA_LANG_STRING, JType.EMPTY_ARRAY)
@@ -788,51 +787,17 @@ abstract class GenJVM extends SubComponent {
}
case BOX(kind) =>
- val boxedClass = definitions.boxedClass(kind.toType.symbol)
- val mtype = new JMethodType(javaType(boxedClass), Array(javaType(kind)))
- jcode.emitINVOKESTATIC(javaName(boxedClass), "box", mtype)
-
- case UNBOX(BOOL) /* if (boxType.symbol == definitions.BooleanClass) */ =>
- // if null emit false
- val nonNull = jcode.newLabel()
- jcode.emitDUP()
- jcode.emitIFNONNULL(nonNull)
- jcode.emitPOP()
- jcode.emitPUSH(false)
- val lexit = jcode.newLabel()
- jcode.emitGOTO(lexit)
- nonNull.anchorToNext()
- // else unbox the reference at the top of the stack
- val boxedBoolean = javaName(definitions.boxedClass(definitions.BooleanClass))
- jcode.emitCHECKCAST(new JObjectType(boxedBoolean))
- jcode.emitGETFIELD(boxedBoolean, "value", JType.BOOLEAN)
- lexit.anchorToNext()
-
- case UNBOX(boxKind) =>
- // if null emit a zero of the appropriate kind
- val nonNull = jcode.newLabel()
- jcode.emitDUP()
- jcode.emitIFNONNULL(nonNull)
- jcode.emitPOP()
- (boxKind: @unchecked) match {
- case BYTE => jcode.emitPUSH(0: Byte)
- case SHORT => jcode.emitPUSH(0: Short)
- case CHAR => jcode.emitPUSH(0: Char)
- case INT => jcode.emitPUSH(0: Int)
- case LONG => jcode.emitPUSH(0: Long)
- case FLOAT => jcode.emitPUSH(0.0f)
- case DOUBLE => jcode.emitPUSH(0.0d)
- }
- val lexit = jcode.newLabel()
- jcode.emitGOTO(lexit)
- nonNull.anchorToNext()
- // else unbox the reference at the top of the stack
- jcode.emitCHECKCAST(new JObjectType(BOXED_NUMBER))
- val clazzName = boxKind.toType.symbol.name.toString
- val unboxMethod = clazzName.toLowerCase() + "Value"
- val mtype = new JMethodType(javaType(boxKind), new Array[JType](0))
- jcode.emitINVOKEVIRTUAL(BOXED_NUMBER, unboxMethod, mtype)
- lexit.anchorToNext()
+ val kindSymbol = kind.toType.symbol
+ val boxMethod = definitions.boxMethod(kindSymbol)
+ val boxedType = definitions.boxedClass(kindSymbol)
+ val mtype = new JMethodType(javaType(boxedType), Array(javaType(kind)))
+ jcode.emitINVOKESTATIC(javaName(definitions.BoxesUtilityModule), boxMethod.name.toString, mtype)
+
+ case UNBOX(kind) =>
+ val kindSymbol = kind.toType.symbol
+ val unboxMethod = definitions.unboxMethod(kindSymbol)
+ val mtype = new JMethodType(javaType(kind), Array(JObjectType.JAVA_LANG_OBJECT))
+ jcode.emitINVOKESTATIC(javaName(definitions.BoxesUtilityModule), unboxMethod.name.toString, mtype)
case NEW(REFERENCE(cls)) =>
val className = javaName(cls)
diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
index 89c5c6e4c5..1c898082bc 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -37,6 +37,7 @@ trait Definitions {
var AllClass: Symbol = _
var ClassClass: Symbol = _
+ var MethodClass: Symbol = _
var StringClass: Symbol = _
var ThrowableClass: Symbol = _
var NullPointerExceptionClass: Symbol = _
@@ -105,6 +106,9 @@ trait Definitions {
def SeqFactory = getMember(ScalaRunTimeModule, nme.Seq);
def checkDefinedMethod = getMember(ScalaRunTimeModule, "checkDefined")
def isArrayMethod = getMember(ScalaRunTimeModule, "isArray")
+ var BoxesUtilityModule: Symbol = _
+ var ComparatorModule: Symbol = _
+ def Comparator_equals = getMember(ComparatorModule, nme.equals_)
var RepeatedParamClass: Symbol = _
var ByNameParamClass: Symbol = _
//var UnsealedClass: Symbol = _
@@ -153,7 +157,7 @@ trait Definitions {
def getProductArgs(tpe: Type): Option[List[Type]] =
tpe.baseClasses.find { x => definitions.isExactProductType(x.tpe) } match {
case Some(p) => Some(tpe.baseType(p).typeArgs)
- case _ => None
+ case _ => None
}
var OptionClass: Symbol = _
@@ -197,9 +201,9 @@ trait Definitions {
assert(ufn.isMethod)
//Console.println("utl "+ufntpe+" "+ufntpe.symbol)
ufn.name match {
- case nme.unapply => unapplyTypeListFromReturnType(ufntpe)
- case nme.unapplySeq => unapplyTypeListFromReturnTypeSeq(ufntpe)
- case _ => throw new IllegalArgumentException("expected function symbol of extraction")
+ case nme.unapply => unapplyTypeListFromReturnType(ufntpe)
+ case nme.unapplySeq => unapplyTypeListFromReturnTypeSeq(ufntpe)
+ case _ => throw new IllegalArgumentException("expected function symbol of extraction")
}
}
/** (the inverse of unapplyReturnTypeSeq)
@@ -214,14 +218,14 @@ trait Definitions {
val O = OptionClass
val S = SomeClass
tp.symbol match { // unapplySeqResultToMethodSig
- case B => Nil
- case O | S =>
- val prod = tp.typeArgs.head
+ case B => Nil
+ case O | S =>
+ val prod = tp.typeArgs.head
getProductArgs(prod) match {
case Some(all @ (x1::x2::xs)) => all // n >= 2
case _ => prod::Nil // special n == 0 || n == 1
}
- case _ => throw new IllegalArgumentException(tp.symbol + " in not in {boolean, option, some}")
+ case _ => throw new IllegalArgumentException(tp.symbol + " in not in {boolean, option, some}")
}
}
@@ -234,13 +238,13 @@ trait Definitions {
val tp = unapplyUnwrap(tp1)
val O = OptionClass; val S = SomeClass; tp.symbol match {
case O | S =>
- val ts = unapplyTypeListFromReturnType(tp1)
- val last1 = ts.last.baseType(SeqClass) match {
+ val ts = unapplyTypeListFromReturnType(tp1)
+ val last1 = ts.last.baseType(SeqClass) match {
case TypeRef(pre, seqClass, args) => typeRef(pre, RepeatedParamClass, args)
- case _ => throw new IllegalArgumentException("last not seq")
- }
- ts.init ::: List(last1)
- case _ => throw new IllegalArgumentException(tp.symbol + " in not in {option, some}")
+ case _ => throw new IllegalArgumentException("last not seq")
+ }
+ ts.init ::: List(last1)
+ case _ => throw new IllegalArgumentException(tp.symbol + " in not in {option, some}")
}
}
@@ -250,11 +254,11 @@ trait Definitions {
* else Some[Product[Ti]]
def unapplyReturnType(elems: List[Type], useWildCards: Boolean) =
if (elems.isEmpty)
- BooleanClass.tpe
+ BooleanClass.tpe
else if (elems.length == 1)
- optionType(if(useWildCards) WildcardType else elems(0))
+ optionType(if(useWildCards) WildcardType else elems(0))
else
- productType({val es = elems; if(useWildCards) elems map { x => WildcardType} else elems})
+ productType({val es = elems; if(useWildCards) elems map { x => WildcardType} else elems})
*/
def unapplyReturnTypeExpected(argsLength: int) = argsLength match {
@@ -305,9 +309,9 @@ trait Definitions {
case _ => ()
}
- case _ => ()
- }
- }
+ case _ => ()
+ }
+ }
isCD
}
@@ -336,9 +340,9 @@ trait Definitions {
var Object_synchronized: Symbol = _
var Object_isInstanceOf: Symbol = _
var Object_asInstanceOf: Symbol = _
- def Object_equals = getMember(ObjectClass, nme.equals_)
- def Object_hashCode = getMember(ObjectClass, nme.hashCode_)
- def Object_toString = getMember(ObjectClass, nme.toString_)
+ def Object_equals = getMember(ObjectClass, nme.equals_)
+ def Object_hashCode = getMember(ObjectClass, nme.hashCode_)
+ def Object_toString = getMember(ObjectClass, nme.toString_)
var String_+ : Symbol = _
@@ -351,10 +355,11 @@ trait Definitions {
// boxed classes
var BoxedArrayClass: Symbol = _
- var BoxedNumberClass: Symbol = _
var BoxedAnyArrayClass: Symbol = _
var BoxedObjectArrayClass: Symbol = _
var BoxedUnitClass: Symbol = _
+ var BoxedNumberClass: Symbol = _
+ var BoxedCharacterClass: Symbol = _
var BoxedUnitModule: Symbol = _
def BoxedUnit_UNIT = getMember(BoxedUnitModule, "UNIT")
var ObjectRefClass: Symbol = _
@@ -445,11 +450,82 @@ trait Definitions {
.setInfo(mkTypeBounds(AllClass.typeConstructor, AnyClass.typeConstructor))
val boxedClass = new HashMap[Symbol, Symbol]
- val unboxMethod = new HashMap[Symbol, Symbol] // Type -> Method
- val boxMethod = new HashMap[Symbol, Symbol] // Type -> Method
- val boxedArrayClass = new HashMap[Symbol, Symbol]
- def isUnbox(m: Symbol) = m.name == nme.unbox && {
+ private var unboxMethodCache: collection.mutable.Map[Symbol, Symbol] = null
+ def unboxMethod =
+ if (unboxMethodCache != null) unboxMethodCache
+ else {
+ unboxMethodCache = new collection.mutable.Map[Symbol, Symbol] {
+ private val container = new HashMap[Symbol, Symbol]
+ private val classes =
+ List(BooleanClass, ByteClass, ShortClass, CharClass, IntClass, LongClass, FloatClass, DoubleClass)
+ for (val cl <- classes)
+ container.update(cl, getMember(BoxesUtilityModule, "unboxTo" + cl.name))
+ def -= (key: Symbol): Unit = throw new Error()
+ def update(key: Symbol, value: Symbol): Unit =
+ container.update(key, value)
+ def size: Int = container.size
+ def elements = container.elements
+ def get(key: Symbol): Option[Symbol] = container.get(key)
+ }
+ unboxMethodCache
+ }
+
+ private var boxMethodCache: collection.mutable.Map[Symbol, Symbol] = null
+ def boxMethod =
+ if (boxMethodCache != null) boxMethodCache
+ else {
+ boxMethodCache = new collection.mutable.Map[Symbol, Symbol] {
+ private val container = new HashMap[Symbol, Symbol]
+ private val BooleanClass = definitions.BooleanClass
+ private val ByteClass = definitions.ByteClass
+ private val CharClass = definitions.CharClass
+ private val ShortClass = definitions.ShortClass
+ private val IntClass = definitions.IntClass
+ private val LongClass = definitions.LongClass
+ private val FloatClass = definitions.FloatClass
+ private val DoubleClass = definitions.DoubleClass
+ private val classes =
+ List(BooleanClass, ByteClass, ShortClass, CharClass, IntClass, LongClass, FloatClass, DoubleClass)
+ for (val cl <- classes) {
+ val boxedName =
+ if (!forMSIL) cl match {
+ case BooleanClass => "Boolean"
+ case ByteClass => "Byte"
+ case CharClass => "Character"
+ case ShortClass => "Short"
+ case IntClass => "Integer"
+ case LongClass => "Long"
+ case FloatClass => "Float"
+ case DoubleClass => "Double"
+ }
+ else cl match {
+ case BooleanClass => "Boolean"
+ case ByteClass => "Byte"
+ case CharClass => "Char"
+ case ShortClass => "Int16"
+ case IntClass => "Int32"
+ case LongClass => "Int64"
+ case FloatClass => "Single"
+ case DoubleClass => "Double"
+ }
+ container.update(cl, getMember(BoxesUtilityModule, "boxTo" + boxedName))
+ }
+ def -= (key: Symbol): Unit = throw new Error()
+ def update(key: Symbol, value: Symbol): Unit = {
+ assert(value.isMethod)
+ container.update(key, value)
+ }
+ def size: Int = container.size
+ def elements = container.elements
+ def get(key: Symbol): Option[Symbol] = container.get(key)
+ }
+ boxMethodCache
+ }
+
+ val boxedArrayClass: collection.mutable.Map[Symbol, Symbol] = new HashMap[Symbol, Symbol]
+
+ def isUnbox(m: Symbol) = (unboxMethod.values contains m) && {
m.tpe match {
case MethodType(_, restpe) => (unboxMethod get restpe.symbol) match {
case Some(`m`) => true
@@ -459,7 +535,8 @@ trait Definitions {
}
}
- def isBox(m: Symbol) = m.name == nme.box && {
+ /** Test whether a method symbol is that of a boxing method. */
+ def isBox(m: Symbol) = (boxMethod.values contains m) && {
m.tpe match {
case MethodType(List(argtpe), _) => (boxMethod get argtpe.symbol) match {
case Some(`m`) => true
@@ -473,9 +550,18 @@ trait Definitions {
private val abbrvTag = new HashMap[Symbol, char]
private def newValueClass(name: Name, tag: char): Symbol = {
- def boxedName: String =
- if (!forMSIL) "scala.runtime.Boxed" + name
- else "System." + (name match {
+ val boxedName =
+ if (!forMSIL) name match {
+ case nme.Boolean => "Boolean"
+ case nme.Byte => "Byte"
+ case nme.Char => "Character"
+ case nme.Short => "Short"
+ case nme.Int => "Integer"
+ case nme.Long => "Long"
+ case nme.Float => "Float"
+ case nme.Double => "Double"
+ }
+ else name match {
case nme.Boolean => "Boolean"
case nme.Byte => "Byte"
case nme.Char => "Char"
@@ -484,11 +570,13 @@ trait Definitions {
case nme.Long => "Int64"
case nme.Float => "Single"
case nme.Double => "Double"
- })
+ }
+ val boxedPathName =
+ if (!forMSIL) "java.lang." + boxedName else "System." + boxedName
val clazz =
newClass(ScalaPackageClass, name, List(AnyValClass.typeConstructor))
.setFlag(ABSTRACT | FINAL)
- boxedClass(clazz) = getClass(boxedName)
+ boxedClass(clazz) = getClass(boxedPathName)
boxedArrayClass(clazz) = getClass("scala.runtime.Boxed" + name + "Array")
refClass(clazz) = getClass("scala.runtime." + name + "Ref")
abbrvTag(clazz) = tag
@@ -498,16 +586,11 @@ trait Definitions {
val mclass = module.moduleClass
mclass.setInfo(ClassInfoType(List(), newScope, mclass))
module.setInfo(mclass.tpe)
- val box = newMethod(mclass, nme.box, List(clazz.typeConstructor),
- ObjectClass.typeConstructor)
- boxMethod(clazz) = box
- val unbox = newMethod(mclass, nme.unbox, List(ObjectClass.typeConstructor),
- clazz.typeConstructor)
- unboxMethod(clazz) = unbox
-
clazz
}
+ /** Sets-up symbols etc. for value classes, and their boxed versions. This
+ * method is called once from within the body of init. */
private def initValueClasses: Unit = {
val booltype = BooleanClass.typeConstructor
val boolparam = List(booltype)
@@ -737,6 +820,7 @@ trait Definitions {
StringClass = getClass(if (forMSIL) "System.String" else "java.lang.String")
ClassClass = getClass(if (forMSIL) "System.Type" else "java.lang.Class")
+ MethodClass = getClass("java.lang.reflect.Method")
ThrowableClass = getClass(if (forMSIL) "System.Exception" else "java.lang.Throwable")
NullPointerExceptionClass = getClass(if (forMSIL) "System.NullReferenceException"
else "java.lang.NullPointerException")
@@ -789,6 +873,8 @@ trait Definitions {
getClass(if (forMSIL) "System.IndexOutOfRangeException"
else "java.lang.IndexOutOfBoundsException")
ScalaRunTimeModule = getModule("scala.runtime.ScalaRunTime")
+ BoxesUtilityModule = getModule("scala.runtime.BoxesUtility")
+ ComparatorModule = getModule("scala.runtime.Comparator")
RepeatedParamClass = newCovariantPolyClass(
ScalaPackageClass, nme.REPEATED_PARAM_CLASS_NAME,
tparam => typeRef(SeqClass.typeConstructor.prefix, SeqClass, List(tparam.typeConstructor)))
@@ -852,11 +938,12 @@ trait Definitions {
PatternWildcard = NoSymbol.newValue(NoPosition, "_").setInfo(AllClass.typeConstructor)
- BoxedNumberClass = if (forMSIL) null else getClass("scala.runtime.BoxedNumber")
+ BoxedNumberClass = if (forMSIL) null else getClass("java.lang.Number")
BoxedArrayClass = getClass("scala.runtime.BoxedArray")
BoxedAnyArrayClass = getClass("scala.runtime.BoxedAnyArray")
BoxedObjectArrayClass = getClass("scala.runtime.BoxedObjectArray")
BoxedUnitClass = getClass("scala.runtime.BoxedUnit")
+ BoxedCharacterClass = getClass("java.lang.Character")
BoxedUnitModule = getModule("scala.runtime.BoxedUnit")
ObjectRefClass = getClass("scala.runtime.ObjectRef")
@@ -902,8 +989,8 @@ trait Definitions {
newMethod(StringClass, "toCharArray", List(),
appliedType(ArrayClass.typeConstructor, List(charType)));
- // Delegate_scalaCallerInfos = new HashMap()
- Delegate_scalaCallerTargets = new HashMap()
+ // Delegate_scalaCallerInfos = new HashMap()
+ Delegate_scalaCallerTargets = new HashMap()
}
AnnotationDefaultAttr = newClass(RootClass,
diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
index 63cddbbbc7..5afe99bed0 100644
--- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala
+++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
@@ -268,12 +268,14 @@ trait StdNames {
val foreach = newTermName("foreach")
val get = newTermName("get")
val getClass_ = newTermName("getClass")
+ val getMethod_ = newTermName("getMethod")
val hasAsInstance = newTermName("hasAsInstance")
val hashCode_ = newTermName("hashCode")
val hasNext = newTermName("hasNext")
val head = newTermName("head")
val identity = newTermName("identity")
val intern = newTermName("intern")
+ val invoke_ = newTermName("invoke")
val isInstanceOf_ = newTermName("isInstanceOf")
val isInstanceOfErased = newTermName("isInstanceOf$erased")
val isDefinedAt = newTermName("isDefinedAt")
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index c4cde60bb8..ddee05f16e 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -177,32 +177,42 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer {
class Eraser(context: Context) extends Typer(context) {
/** Box `tree' of unboxed type */
- private def box(tree: Tree): Tree =
- typed {
- atPos(tree.pos) {
- val sym = tree.tpe.symbol;
- if (sym == UnitClass) {
- if (treeInfo.isPureExpr(tree)) gen.mkAttributedRef(BoxedUnit_UNIT)
- else Block(List(tree), gen.mkAttributedRef(BoxedUnit_UNIT))
- } else if (sym == ArrayClass) {
- val elemClass = tree.tpe.typeArgs.head.symbol;
- val boxedClass = if (isValueClass(elemClass)) boxedArrayClass(elemClass)
- else BoxedObjectArrayClass;
- Apply(Select(New(TypeTree(boxedClass.tpe)), nme.CONSTRUCTOR), List(tree))
- } else {
- Apply(gen.mkAttributedRef(boxMethod(tree.tpe.symbol)), List(tree)).
- setPos(tree.pos) setType ObjectClass.tpe
+ private def box(tree: Tree): Tree = tree match {
+ case LabelDef(name, params, rhs) =>
+ val rhs1 = box(rhs)
+ copy.LabelDef(tree, name, params, rhs1) setType rhs1.tpe
+ case _ =>
+ typed {
+ atPos(tree.pos) {
+ val sym = tree.tpe.symbol;
+ if (sym == UnitClass) {
+ if (treeInfo.isPureExpr(tree)) gen.mkAttributedRef(BoxedUnit_UNIT)
+ else Block(List(tree), gen.mkAttributedRef(BoxedUnit_UNIT))
+ } else if (sym == ArrayClass) {
+ val elemClass = tree.tpe.typeArgs.head.symbol;
+ val boxedClass = if (isValueClass(elemClass)) boxedArrayClass(elemClass)
+ else BoxedObjectArrayClass;
+ Apply(Select(New(TypeTree(boxedClass.tpe)), nme.CONSTRUCTOR), List(tree))
+ } else {
+ Apply(gen.mkAttributedRef(boxMethod(tree.tpe.symbol)), List(tree)).
+ setPos(tree.pos) setType ObjectClass.tpe
+ }
}
}
- }
+ }
/** generate ScalaRuntime.boxArray(tree) */
- private def boxArray(tree: Tree): Tree =
- typed {
- atPos(tree.pos) {
- gen.mkRuntimeCall(nme.boxArray, List(tree))
+ private def boxArray(tree: Tree): Tree = tree match {
+ case LabelDef(name, params, rhs) =>
+ val rhs1 = boxArray(rhs)
+ copy.LabelDef(tree, name, params, rhs1) setType rhs1.tpe
+ case _ =>
+ typed {
+ atPos(tree.pos) {
+ gen.mkRuntimeCall(nme.boxArray, List(tree))
+ }
}
- }
+ }
/** Unbox <code>tree</code> of boxed type to expected type <code>pt</code>.
*
@@ -210,24 +220,29 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer {
* @param pt the expected type.
* @return the unboxed tree
*/
- private def unbox(tree: Tree, pt: Type): Tree =
- typed {
- atPos(tree.pos) {
- if (pt.symbol == UnitClass) {
- if (treeInfo.isPureExpr(tree)) Literal(())
- else Block(List(tree), Literal(()))
- }
- else if (pt.symbol == ArrayClass) {
- val tree1 = adaptToType(tree, BoxedArrayClass.tpe)
- gen.mkRuntimeCall(nme.arrayValue, List(tree1, Literal(pt.typeArgs.head)))
- }
- else {
- atPos(tree.pos) {
- Apply(gen.mkAttributedRef(unboxMethod(pt.symbol)), List(tree)) setType pt
+ private def unbox(tree: Tree, pt: Type): Tree = tree match {
+ case LabelDef(name, params, rhs) =>
+ val rhs1 = unbox(rhs, pt)
+ copy.LabelDef(tree, name, params, rhs1) setType rhs1.tpe
+ case _ =>
+ typed {
+ atPos(tree.pos) {
+ if (pt.symbol == UnitClass) {
+ if (treeInfo.isPureExpr(tree)) Literal(())
+ else Block(List(tree), Literal(()))
+ }
+ else if (pt.symbol == ArrayClass) {
+ val tree1 = adaptToType(tree, BoxedArrayClass.tpe)
+ gen.mkRuntimeCall(nme.arrayValue, List(tree1, Literal(pt.typeArgs.head)))
+ }
+ else {
+ atPos(tree.pos) {
+ Apply(gen.mkAttributedRef(unboxMethod(pt.symbol)), List(tree)) setType pt
+ }
}
}
}
- }
+ }
/** <p>
* Generate a cast operation from <code>tree.tpe</code> to <code>pt</code>.
@@ -762,7 +777,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer {
}
// todo: get rid of instanceOfErased
// todo: also handle the case where the singleton type is buried in a compound
- else if (fn.symbol == Any_isInstanceOf || fn.symbol == Any_isInstanceOfErased)
+ else if (fn.symbol == Any_isInstanceOf || fn.symbol == Any_isInstanceOfErased)
fn match {
case TypeApply(sel @ Select(qual, name), List(targ)) =>
def mkIsInstanceOf(q: () => Tree)(tp: Type): Tree =