diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/Settings.scala | 12 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/icode/GenICode.scala | 44 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala | 6 | ||||
-rw-r--r-- | src/library/scala/runtime/BoxesRunTime.java | 311 | ||||
-rw-r--r-- | src/library/scala/runtime/Equality.java | 58 |
5 files changed, 140 insertions, 291 deletions
diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala index e1429b1644..eb6017815a 100644 --- a/src/compiler/scala/tools/nsc/Settings.scala +++ b/src/compiler/scala/tools/nsc/Settings.scala @@ -825,8 +825,6 @@ trait ScalacSettings { withHelpSyntax("-Ysqueeze:<enabled>") val Ystatistics = BooleanSetting ("-Ystatistics", "Print compiler statistics") val stop = PhasesSetting ("-Ystop", "Stop after phase") - val logEquality = BooleanSetting ("-Ylog-equality", "Log all noteworthy equality tests (hardcoded to /tmp/scala-equality-log.txt)") . - withPostSetHook(() => scala.runtime.Equality.logEverything = true) val refinementMethodDispatch = ChoiceSetting ("-Ystruct-dispatch", "Selects dispatch method for structural refinement method calls", List("no-cache", "mono-cache", "poly-cache", "invoke-dynamic"), "poly-cache") . @@ -838,6 +836,16 @@ trait ScalacSettings { val Ypmatdebug = BooleanSetting ("-Ypmat-debug", "Trace all pattern matcher activity.") val Ytailrec = BooleanSetting ("-Ytailrecommend", "Alert methods which would be tail-recursive if private or final.") + // Equality specific + val logEqEq = BooleanSetting ("-Ylog-eqeq", "Log all noteworthy equality tests") . + withPostSetHook(() => scala.runtime.Equality.logEverything = true) + val YfutureEqEq = BooleanSetting ("-Yfuture-eqeq", "Use proposed overloading-based numeric equality semantics.") . + withPostSetHook(() => scala.runtime.Equality.use28Semantics = true) + val YwarnEqEq = BooleanSetting ("-Ywarn-eqeq", "Warn when boxed primitives of different types are compared.") . + withPostSetHook(() => scala.runtime.Equality.warnOnBoxedCompare = true) + val YdieEqEq = BooleanSetting ("-Ydie-changed-eqeq", "Throw an exception if a comparison would have come back differently in scala 2.7.") . + withPostSetHook(() => scala.runtime.Equality.dieOnBoxedCompareIfValuesAreEqual = true) + // Warnings val Xwarninit = BooleanSetting ("-Xwarninit", "Warn about possible changes in initialization semantics") val Xchecknull = BooleanSetting ("-Xcheck-null", "Emit warning on selection of nullable reference") diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index b3d7da8f06..99f0d4cf3c 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -1291,7 +1291,7 @@ abstract class GenICode extends SubComponent { elseCtx: Context): Unit = { def genComparisonOp(l: Tree, r: Tree, code: Int) { - if (settings.logEquality.value && isUniversalEqualityOp(code)) + if (settings.logEqEq.value && isUniversalEqualityOp(code)) logEqEq(tree, l, r, code) val op: TestOp = code match { @@ -1422,9 +1422,13 @@ abstract class GenICode extends SubComponent { (rsym == ObjectClass) || (lsym != rsym) && (isBoxed(lsym) || isBoxed(rsym)) } + def cannotAvoidBoxesRuntime = + settings.logEqEq.value || settings.YwarnEqEq.value || settings.YdieEqEq.value - if (mustUseAnyComparator) { - + /** We can avoid generating calls to BoxesRuntime only if -Yfuture-eqeq + * is enabled AND none of the eqeq logging options are enabled. + */ + if (mustUseAnyComparator && (!settings.YfutureEqEq.value || cannotAvoidBoxesRuntime)) { val ctx1 = genLoad(l, ctx, ANY_REF_CLASS) val ctx2 = genLoad(r, ctx1, ANY_REF_CLASS) ctx2.bb.emitOnly( @@ -1433,7 +1437,6 @@ abstract class GenICode extends SubComponent { ) } else { - if (isNull(l)) // null == expr -> expr eq null genLoad(r, ctx, ANY_REF_CLASS).bb emitOnly CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ANY_REF_CLASS) @@ -2153,39 +2156,18 @@ abstract class GenICode extends SubComponent { override def varsInScope: Buffer[Local] = new ListBuffer } - /** Log equality tests to file if they are playing with typefire */ + /** Log equality tests between different primitives. */ def logEqEq(tree: Tree, l: Tree, r: Tree, code: Int) { import definitions._ val op = if (code == scalaPrimitives.EQ) "==" else if (code == scalaPrimitives.NE) "!=" else "??" - - def mayBeNumericComparison: Boolean = { - def isPossiblyBoxed(sym: Symbol): Boolean = { - import definitions._ - // classes as which a boxed primitive may statically appear - val possibleBoxes = List(BoxedNumberClass, BoxedCharacterClass, SerializableClass, ComparableClass) - - (sym == ObjectClass) || (possibleBoxes exists (sym isNonBottomSubClass _)) - } - - val lsym = l.tpe.typeSymbol - val rsym = r.tpe.typeSymbol - - def isSameBox = { - def isFinalBox(s: Symbol) = (s isNonBottomSubClass BoxedNumberClass) && s.isFinal - isFinalBox(lsym) && isFinalBox(rsym) && lsym == rsym - } - isPossiblyBoxed(lsym) && isPossiblyBoxed(rsym) && !isSameBox - } - val tkl = toTypeKind(l.tpe) val tkr = toTypeKind(r.tpe) - lazy val whereAreWe = tree.pos.source + ":" + tree.pos.line - def logit(preface: String) = - runtime.Equality.log("[%s] %s %s %s (%s)".format(preface, l.tpe, op, r.tpe, whereAreWe)) if (tkl.isNumericType && tkr.isNumericType && tkl != tkr) - logit(" KNOWN ") - else if (mayBeNumericComparison) - logit("UNKNOWN") + runtime.Equality.logComparison( + "Comparing actual primitives", + "%s %s %s".format(l.tpe, op, r.tpe), + tree.pos.source + ":" + tree.pos.line + ) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala b/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala index a46a987bb8..12f6f4021b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala @@ -70,6 +70,12 @@ abstract class ConstantFolder { } private def foldBinop(op: Name, x: Constant, y: Constant): Constant = try { + // temporarily logging folded ==/!= so the log doesn't have unexplained absences + if ((op == nme.EQ || op == nme.NE) && x.tag != y.tag && settings.logEqEq.value) { + val opstr = if (op == nme.EQ) "==" else "!=" + scala.runtime.Equality.log("Folding constant expression (%s %s %s)".format(x.value, opstr, y.value)) + } + val optag = if (x.tag == y.tag) x.tag else if (isNumeric(x.tag) && isNumeric(y.tag)) if (x.tag > y.tag) x.tag else y.tag diff --git a/src/library/scala/runtime/BoxesRunTime.java b/src/library/scala/runtime/BoxesRunTime.java index 010e2738c9..3e75cb213e 100644 --- a/src/library/scala/runtime/BoxesRunTime.java +++ b/src/library/scala/runtime/BoxesRunTime.java @@ -33,15 +33,19 @@ public class BoxesRunTime private static int typeCode(Object a) { if (a instanceof Integer) return INT; + if (a instanceof Byte) return BYTE; if (a instanceof Character) return CHAR; if (a instanceof Long) return LONG; if (a instanceof Double) return DOUBLE; - if (a instanceof Float) return FLOAT; - if (a instanceof Byte) return BYTE; if (a instanceof Short) return SHORT; + if (a instanceof Float) return FLOAT; return OTHER; } + private static String boxDescription(Object a) { + return "" + a.getClass().getSimpleName() + "(" + a + ")"; + } + /* BOXING ... BOXING ... BOXING ... BOXING ... BOXING ... BOXING ... BOXING ... BOXING */ public static Boolean boxToBoolean(boolean b) { @@ -135,221 +139,7 @@ public class BoxesRunTime /* COMPARISON ... COMPARISON ... COMPARISON ... COMPARISON ... COMPARISON ... COMPARISON */ - /** These methods manually implement "overloading" among boxed primitives. - * The compiler is capable of inserting (but does not presently) the specific - * equals method based on the statically known types of the boxes. - */ - - public static boolean equalsCharacterCharacter(Character a, Character b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.charValue() == b.charValue(); - } - public static boolean equalsCharacterByte(Character a, Byte b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.charValue() == b.byteValue(); - } - public static boolean equalsCharacterShort(Character a, Short b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.charValue() == b.shortValue(); - } - public static boolean equalsCharacterInteger(Character a, Integer b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.charValue() == b.intValue(); - } - public static boolean equalsCharacterLong(Character a, Long b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.charValue() == b.longValue(); - } - public static boolean equalsCharacterFloat(Character a, Float b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.charValue() == b.floatValue(); - } - public static boolean equalsCharacterDouble(Character a, Double b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.charValue() == b.doubleValue(); - } - public static boolean equalsByteCharacter(Byte a, Character b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.byteValue() == b.charValue(); - } - public static boolean equalsByteByte(Byte a, Byte b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.byteValue() == b.byteValue(); - } - public static boolean equalsByteShort(Byte a, Short b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.byteValue() == b.shortValue(); - } - public static boolean equalsByteInteger(Byte a, Integer b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.byteValue() == b.intValue(); - } - public static boolean equalsByteLong(Byte a, Long b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.byteValue() == b.longValue(); - } - public static boolean equalsByteFloat(Byte a, Float b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.byteValue() == b.floatValue(); - } - public static boolean equalsByteDouble(Byte a, Double b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.byteValue() == b.doubleValue(); - } - public static boolean equalsShortCharacter(Short a, Character b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.shortValue() == b.charValue(); - } - public static boolean equalsShortByte(Short a, Byte b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.shortValue() == b.byteValue(); - } - public static boolean equalsShortShort(Short a, Short b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.shortValue() == b.shortValue(); - } - public static boolean equalsShortInteger(Short a, Integer b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.shortValue() == b.intValue(); - } - public static boolean equalsShortLong(Short a, Long b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.shortValue() == b.longValue(); - } - public static boolean equalsShortFloat(Short a, Float b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.shortValue() == b.floatValue(); - } - public static boolean equalsShortDouble(Short a, Double b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.shortValue() == b.doubleValue(); - } - public static boolean equalsIntegerCharacter(Integer a, Character b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.intValue() == b.charValue(); - } - public static boolean equalsIntegerByte(Integer a, Byte b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.intValue() == b.byteValue(); - } - public static boolean equalsIntegerShort(Integer a, Short b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.intValue() == b.shortValue(); - } - public static boolean equalsIntegerInteger(Integer a, Integer b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.intValue() == b.intValue(); - } - public static boolean equalsIntegerLong(Integer a, Long b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.intValue() == b.longValue(); - } - public static boolean equalsIntegerFloat(Integer a, Float b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.intValue() == b.floatValue(); - } - public static boolean equalsIntegerDouble(Integer a, Double b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.intValue() == b.doubleValue(); - } - public static boolean equalsLongCharacter(Long a, Character b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.longValue() == b.charValue(); - } - public static boolean equalsLongByte(Long a, Byte b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.longValue() == b.byteValue(); - } - public static boolean equalsLongShort(Long a, Short b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.longValue() == b.shortValue(); - } - public static boolean equalsLongInteger(Long a, Integer b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.longValue() == b.intValue(); - } - public static boolean equalsLongLong(Long a, Long b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.longValue() == b.longValue(); - } - public static boolean equalsLongFloat(Long a, Float b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.longValue() == b.floatValue(); - } - public static boolean equalsLongDouble(Long a, Double b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.longValue() == b.doubleValue(); - } - public static boolean equalsFloatCharacter(Float a, Character b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.floatValue() == b.charValue(); - } - public static boolean equalsFloatByte(Float a, Byte b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.floatValue() == b.byteValue(); - } - public static boolean equalsFloatShort(Float a, Short b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.floatValue() == b.shortValue(); - } - public static boolean equalsFloatInteger(Float a, Integer b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.floatValue() == b.intValue(); - } - public static boolean equalsFloatLong(Float a, Long b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.floatValue() == b.longValue(); - } - public static boolean equalsFloatFloat(Float a, Float b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.floatValue() == b.floatValue(); - } - public static boolean equalsFloatDouble(Float a, Double b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.floatValue() == b.doubleValue(); - } - public static boolean equalsDoubleCharacter(Double a, Character b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.doubleValue() == b.charValue(); - } - public static boolean equalsDoubleByte(Double a, Byte b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.doubleValue() == b.byteValue(); - } - public static boolean equalsDoubleShort(Double a, Short b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.doubleValue() == b.shortValue(); - } - public static boolean equalsDoubleInteger(Double a, Integer b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.doubleValue() == b.intValue(); - } - public static boolean equalsDoubleLong(Double a, Long b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.doubleValue() == b.longValue(); - } - public static boolean equalsDoubleFloat(Double a, Float b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.doubleValue() == b.floatValue(); - } - public static boolean equalsDoubleDouble(Double a, Double b) { - if (a == null || b == null) return (Object)a == (Object)b; - else return a.doubleValue() == b.doubleValue(); - } - - /** The current equals method, whose logic is under review. **/ - - public static boolean equals(Object a, Object b) { - if ((a instanceof Number || a instanceof Character) && (b instanceof Number || b instanceof Character)) { - if (a.getClass() != b.getClass()) { - Equality.logInternal("[ BOXED ] Comparing: ", a, b, Equality.whereAreWe()); - } - } - - if (a == null || b == null) - return a == b; - if (a.equals(b)) - return true; + private static boolean equalsBonusLogicFromScala27(Object a, Object b) { if (a instanceof Number || a instanceof Character || b instanceof Number || b instanceof Character) { int acode = typeCode(a); int bcode = typeCode(b); @@ -376,18 +166,45 @@ public class BoxesRunTime res = (aa == bb); } - if (res || b.equals(a)) { - String msg; - if (res) msg = "[ BOXED ] Overriding equals between different types: "; - else msg = "[ BOXED ] Overriding equals because b.equals(a): "; - Equality.logInternal(msg, a, b, Equality.whereAreWe()); - return true; - } - return false; + if (res || b.equals(a)) return true; + else return false; } return false; } + private static String logMessage(Object a, Object b, String where) { + return "Compared boxed primitives (" + boxDescription(a) + " == " + boxDescription(b) + ") @ " + where; + } + + private static void verifyEqEq(Object a, Object b, boolean isFatal, boolean onlyIfActuallyEqual) { + int code1 = typeCode(a); + int code2 = typeCode(b); + + if (code1 < OTHER && code2 < OTHER && code1 != code2) { + if (!onlyIfActuallyEqual || equalsBonusLogicFromScala27(a, b)) { + String msg = logMessage(a, b, Equality.whereAreWe(5)); + Equality.warnOrDie(msg, isFatal); + } + } + } + + /** The current equals method. **/ + public static boolean equals(Object a, Object b) { + if (a == null || b == null) + return a == b; + + verifyEqEq(a, b, + (Equality.dieOnBoxedCompare || Equality.dieOnBoxedCompareIfValuesAreEqual), + (Equality.warnOnBoxedCompareIfValuesAreEqual || Equality.dieOnBoxedCompareIfValuesAreEqual) + ); + + if (a.equals(b)) + return true; + + if (Equality.use28Semantics) return false; + else return equalsBonusLogicFromScala27(a, b); + } + /* OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS */ /** arg1 + arg2 */ @@ -889,11 +706,11 @@ public class BoxesRunTime /** arg.toChar */ public static Character toCharacter(Object arg) throws NoSuchMethodException { - if (arg instanceof Character) return (Character)arg; - if (arg instanceof Byte) return boxToCharacter((char)unboxToByte(arg)); - if (arg instanceof Short) return boxToCharacter((char)unboxToShort(arg)); if (arg instanceof Integer) return boxToCharacter((char)unboxToInt(arg)); + if (arg instanceof Short) return boxToCharacter((char)unboxToShort(arg)); + if (arg instanceof Character) return (Character)arg; if (arg instanceof Long) return boxToCharacter((char)unboxToLong(arg)); + if (arg instanceof Byte) return boxToCharacter((char)unboxToByte(arg)); if (arg instanceof Float) return boxToCharacter((char)unboxToFloat(arg)); if (arg instanceof Double) return boxToCharacter((char)unboxToDouble(arg)); throw new NoSuchMethodException(); @@ -901,11 +718,11 @@ public class BoxesRunTime /** arg.toByte */ public static Byte toByte(Object arg) throws NoSuchMethodException { + if (arg instanceof Integer) return boxToByte((byte)unboxToInt(arg)); if (arg instanceof Character) return boxToByte((byte)unboxToChar(arg)); if (arg instanceof Byte) return (Byte)arg; - if (arg instanceof Short) return boxToByte((byte)unboxToShort(arg)); - if (arg instanceof Integer) return boxToByte((byte)unboxToInt(arg)); if (arg instanceof Long) return boxToByte((byte)unboxToLong(arg)); + if (arg instanceof Short) return boxToByte((byte)unboxToShort(arg)); if (arg instanceof Float) return boxToByte((byte)unboxToFloat(arg)); if (arg instanceof Double) return boxToByte((byte)unboxToDouble(arg)); throw new NoSuchMethodException(); @@ -913,11 +730,11 @@ public class BoxesRunTime /** arg.toShort */ public static Short toShort(Object arg) throws NoSuchMethodException { + if (arg instanceof Integer) return boxToShort((short)unboxToInt(arg)); + if (arg instanceof Long) return boxToShort((short)unboxToLong(arg)); if (arg instanceof Character) return boxToShort((short)unboxToChar(arg)); if (arg instanceof Byte) return boxToShort((short)unboxToByte(arg)); if (arg instanceof Short) return (Short)arg; - if (arg instanceof Integer) return boxToShort((short)unboxToInt(arg)); - if (arg instanceof Long) return boxToShort((short)unboxToLong(arg)); if (arg instanceof Float) return boxToShort((short)unboxToFloat(arg)); if (arg instanceof Double) return boxToShort((short)unboxToDouble(arg)); throw new NoSuchMethodException(); @@ -925,49 +742,49 @@ public class BoxesRunTime /** arg.toInt */ public static Integer toInteger(Object arg) throws NoSuchMethodException { - if (arg instanceof Character) return boxToInteger((int)unboxToChar(arg)); - if (arg instanceof Byte) return boxToInteger((int)unboxToByte(arg)); - if (arg instanceof Short) return boxToInteger((int)unboxToShort(arg)); if (arg instanceof Integer) return (Integer)arg; if (arg instanceof Long) return boxToInteger((int)unboxToLong(arg)); - if (arg instanceof Float) return boxToInteger((int)unboxToFloat(arg)); if (arg instanceof Double) return boxToInteger((int)unboxToDouble(arg)); + if (arg instanceof Float) return boxToInteger((int)unboxToFloat(arg)); + if (arg instanceof Character) return boxToInteger((int)unboxToChar(arg)); + if (arg instanceof Byte) return boxToInteger((int)unboxToByte(arg)); + if (arg instanceof Short) return boxToInteger((int)unboxToShort(arg)); throw new NoSuchMethodException(); } /** arg.toLong */ public static Long toLong(Object arg) throws NoSuchMethodException { + if (arg instanceof Integer) return boxToLong((long)unboxToInt(arg)); + if (arg instanceof Double) return boxToLong((long)unboxToDouble(arg)); + if (arg instanceof Float) return boxToLong((long)unboxToFloat(arg)); + if (arg instanceof Long) return (Long)arg; if (arg instanceof Character) return boxToLong((long)unboxToChar(arg)); if (arg instanceof Byte) return boxToLong((long)unboxToByte(arg)); if (arg instanceof Short) return boxToLong((long)unboxToShort(arg)); - if (arg instanceof Integer) return boxToLong((long)unboxToInt(arg)); - if (arg instanceof Long) return (Long)arg; - if (arg instanceof Float) return boxToLong((long)unboxToFloat(arg)); - if (arg instanceof Double) return boxToLong((long)unboxToDouble(arg)); throw new NoSuchMethodException(); } /** arg.toFloat */ public static Float toFloat(Object arg) throws NoSuchMethodException { - if (arg instanceof Character) return boxToFloat((float)unboxToChar(arg)); - if (arg instanceof Byte) return boxToFloat((float)unboxToByte(arg)); - if (arg instanceof Short) return boxToFloat((float)unboxToShort(arg)); if (arg instanceof Integer) return boxToFloat((float)unboxToInt(arg)); if (arg instanceof Long) return boxToFloat((float)unboxToLong(arg)); if (arg instanceof Float) return (Float)arg; if (arg instanceof Double) return boxToFloat((float)unboxToDouble(arg)); + if (arg instanceof Character) return boxToFloat((float)unboxToChar(arg)); + if (arg instanceof Byte) return boxToFloat((float)unboxToByte(arg)); + if (arg instanceof Short) return boxToFloat((float)unboxToShort(arg)); throw new NoSuchMethodException(); } /** arg.toDouble */ public static Double toDouble(Object arg) throws NoSuchMethodException { - if (arg instanceof Character) return boxToDouble((double)unboxToChar(arg)); - if (arg instanceof Byte) return boxToDouble((double)unboxToByte(arg)); - if (arg instanceof Short) return boxToDouble((double)unboxToShort(arg)); if (arg instanceof Integer) return boxToDouble((double)unboxToInt(arg)); - if (arg instanceof Long) return boxToDouble((double)unboxToLong(arg)); if (arg instanceof Float) return boxToDouble((double)unboxToFloat(arg)); if (arg instanceof Double) return (Double)arg; + if (arg instanceof Long) return boxToDouble((double)unboxToLong(arg)); + if (arg instanceof Character) return boxToDouble((double)unboxToChar(arg)); + if (arg instanceof Byte) return boxToDouble((double)unboxToByte(arg)); + if (arg instanceof Short) return boxToDouble((double)unboxToShort(arg)); throw new NoSuchMethodException(); } diff --git a/src/library/scala/runtime/Equality.java b/src/library/scala/runtime/Equality.java index 3ec89360b8..018b3b4c07 100644 --- a/src/library/scala/runtime/Equality.java +++ b/src/library/scala/runtime/Equality.java @@ -12,6 +12,11 @@ package scala.runtime; import java.io.*; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.logging.Handler; +import java.util.logging.StreamHandler; +import java.util.logging.SimpleFormatter; /** An object (static class) encapsulating the variations on equality * presently under consideration. It's written in java so it can easily @@ -19,33 +24,64 @@ import java.io.*; */ public class Equality { - public static boolean disallowNullEquals = true; - public static boolean disallowPrimitiveEquals = true; - public static boolean warnOnEqualsAny = true; - public static boolean callCanEqualIfAvailable = true; public static boolean logEverything = false; + public static boolean use28Semantics = false; + + public static boolean warnOnBoxedCompare = false; + public static boolean warnOnBoxedCompareIfValuesAreEqual = false; + public static boolean dieOnBoxedCompare = false; + public static boolean dieOnBoxedCompareIfValuesAreEqual = false; + + private static Handler handler; + public static Logger logger; + public static final Logger defaultLogger; + + static { + class EqualityLogger extends Logger { + EqualityLogger() { + super("EqualityLogger", null); + } + } + defaultLogger = new EqualityLogger(); + + handler = new StreamHandler(System.out, new SimpleFormatter()); + handler.setLevel(Level.INFO); + defaultLogger.addHandler(handler); + + logger = defaultLogger; + } + + public static void warnOrDie(String msg, boolean isFatal) { + if (isFatal) throw new RuntimeException(msg); + else log(msg); + // else System.out.println(msg); + } public static String obToString(Object o) { String s = o.toString() + " (" + o.getClass().getSimpleName() + ")"; return s.replaceAll("\\n", " "); } - public static void logInternal(String msg, Object a, Object b, String where) { - log(String.format("%s %s == %s at %s", msg, obToString(a), obToString(b), where)); + public static void logComparison(String msg, String cmp, String where) { + log(String.format("%s (%s) at %s", msg, cmp, where)); } - public static String whereAreWe() { + public static String whereAreWe() { return whereAreWe(4); } + public static String whereAreWe(int depth) { StackTraceElement[] es = Thread.currentThread().getStackTrace(); - if (es.length < 4) + if (es.length < depth) return "<unknown>"; - StackTraceElement e = es[3]; + StackTraceElement e = es[depth - 1]; String clazz = e.getClassName().replaceAll("\\$.*$", "\\$..."); return String.format("%s.%s(%s.%d)", clazz, e.getMethodName(), e.getFileName(), e.getLineNumber()); } public static void log(String msg) { - if (logEverything) - System.out.println(msg); + if (logger != null) { + logger.warning(msg); + handler.flush(); + } + else System.out.println(msg); } } |