summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cldc-library/scala/runtime/BoxesRunTime.java626
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala8
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala6
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolTable.scala6
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala310
-rw-r--r--src/library/scala/runtime/BoxesRunTime.java794
-rw-r--r--test/files/run/issue192.check36
-rw-r--r--test/files/run/issue192.scala89
10 files changed, 1820 insertions, 63 deletions
diff --git a/src/cldc-library/scala/runtime/BoxesRunTime.java b/src/cldc-library/scala/runtime/BoxesRunTime.java
new file mode 100644
index 0000000000..63838e5a18
--- /dev/null
+++ b/src/cldc-library/scala/runtime/BoxesRunTime.java
@@ -0,0 +1,626 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2007, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+// $Id$
+
+
+package scala.runtime;
+
+/** An object (static class) that defines methods used for creating,
+ * reverting, and calculating with, boxed values. There are four classes
+ * of methods in this object:
+ * - High-performance value boxing methods that feed from a pre-
+ * computed map of instances for the most common instanciations.
+ * - Convenience unboxing methods returning default value on null.
+ * - The generalised comparison method to be used when an object may
+ * be a boxed value.
+ * - Standard value operators for boxed number and quasi-number values.
+ *
+ * @author Gilles Dubochet
+ * @author Martin Odersky
+ * @contributor Stepan Koltsov
+ * @version 2.0 */
+public class BoxesRunTime {
+
+ private static final int CHAR = 0, BYTE = 1, SHORT = 2, INT = 3, LONG = 4, OTHER = 7;
+
+ private static int typeCode(Object a) {
+ if (a instanceof Integer) return INT;
+ if (a instanceof Character) return CHAR;
+ if (a instanceof Long) return LONG;
+ if (a instanceof Byte) return BYTE;
+ if (a instanceof Short) return SHORT;
+ return OTHER;
+ }
+
+/* BOXING ... BOXING ... BOXING ... BOXING ... BOXING ... BOXING ... BOXING ... BOXING */
+
+ private static int charLowBound = 0;
+ private static int charUpBound = 255;
+ private static Character[] charCache = new Character[charUpBound - charLowBound + 1];
+
+ private static int byteLowBound = -128;
+ private static int byteUpBound = 127;
+ private static Byte[] byteCache = new Byte[byteUpBound - byteLowBound + 1];
+
+ private static int shortLowBound = -128;
+ private static int shortUpBound = 127;
+ private static Short[] shortCache = new Short[shortUpBound - shortLowBound + 1];
+
+ private static int intLowBound = -128;
+ private static int intUpBound = 1024;
+ private static Integer[] intCache = new Integer[intUpBound - intLowBound + 1];
+
+ private static int longLowBound = -128;
+ private static int longUpBound = 1024;
+ private static Long[] longCache = new Long[longUpBound - longLowBound + 1];
+
+ static {
+ int idx = 0;
+ while (idx <= charUpBound - charLowBound) {
+ charCache[idx] = new Character((char)(idx + charLowBound));
+ idx = idx + 1;
+ }
+ idx = 0;
+ while (idx <= byteUpBound - byteLowBound) {
+ byteCache[idx] = new Byte((byte)(idx + byteLowBound));
+ idx = idx + 1;
+ }
+ idx = 0;
+ while (idx <= shortUpBound - shortLowBound) {
+ shortCache[idx] = new Short((short)(idx + shortLowBound));
+ idx = idx + 1;
+ }
+ idx = 0;
+ while (idx <= intUpBound - intLowBound) {
+ intCache[idx] = new Integer((int)(idx + intLowBound));
+ idx = idx + 1;
+ }
+ idx = 0;
+ while (idx <= longUpBound - longLowBound) {
+ longCache[idx] = new Long((long)(idx + longLowBound));
+ idx = idx + 1;
+ }
+ }
+
+ public static Boolean boxToBoolean(boolean b) {
+ return b ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ public static Character boxToCharacter(char c) {
+ if (c >= charLowBound && c <= charUpBound)
+ return charCache[(int)c - charLowBound];
+ return new Character(c);
+ }
+
+ public static Byte boxToByte(byte b) {
+ if (b >= byteLowBound && b <= byteUpBound)
+ return byteCache[(int)b - byteLowBound];
+ return new Byte(b);
+ }
+
+ public static Short boxToShort(short s) {
+ if (s >= shortLowBound && s <= shortUpBound)
+ return shortCache[(int)s - shortLowBound];
+ return new Short(s);
+ }
+
+ public static Integer boxToInteger(int i) {
+ if (i >= intLowBound && i <= intUpBound)
+ return intCache[(int)i - intLowBound];
+ return new Integer(i);
+ }
+
+ public static Long boxToLong(long l) {
+ if (l >= longLowBound && l <= longUpBound)
+ return longCache[(int)l - longLowBound];
+ return new Long(l);
+ }
+
+/* UNBOXING ... UNBOXING ... UNBOXING ... UNBOXING ... UNBOXING ... UNBOXING ... UNBOXING */
+
+ public static boolean unboxToBoolean(Object b) {
+ return b == null ? false : ((Boolean)b).booleanValue();
+ }
+
+ public static char unboxToChar(Object c) {
+ return c == null ? 0 : ((Character)c).charValue();
+ }
+
+ public static byte unboxToByte(Object b) {
+ return b == null ? 0 : ((Byte)b).byteValue();
+ }
+
+ public static short unboxToShort(Object s) {
+ return s == null ? 0 : ((Short)s).shortValue();
+ }
+
+ public static int unboxToInt(Object i) {
+ return i == null ? 0 : ((Integer)i).intValue();
+ }
+
+ public static long unboxToLong(Object l) {
+ return l == null ? 0 : ((Long)l).longValue();
+ }
+
+/* COMPARISON ... COMPARISON ... COMPARISON ... COMPARISON ... COMPARISON ... COMPARISON */
+
+ /** A rich implementation of the <code>equals</code> method that overrides the
+ * default equals because Java's boxed primitives are utterly broken. This equals
+ * is inserted instead of a normal equals by the Scala compiler (in the
+ * ICode phase, method <code>genEqEqPrimitive</code>) only when either
+ * side of the comparison is a subclass of <code>AnyVal</code>, of
+ * <code>java.lang.Number</code>, of <code>java.lang.Character</code> or
+ * is exactly <code>Any</code> or <code>AnyRef</code>. */
+ public static boolean equals(Object a, Object b) {
+ if (a == null || b == null)
+ return a == b;
+ if (a.equals(b))
+ return true;
+ if (a instanceof Number || a instanceof Character || b instanceof Number || b instanceof Character) {
+ int acode = typeCode(a);
+ int bcode = typeCode(b);
+ int maxcode = (acode < bcode) ? bcode : acode;
+ if (maxcode <= INT) {
+ int aa = (acode == CHAR) ? ((Character) a).charValue() : ((Number) a).intValue();
+ int bb = (bcode == CHAR) ? ((Character) b).charValue() : ((Number) b).intValue();
+ return aa == bb;
+ }
+ if (maxcode <= LONG) {
+ long aa = (acode == CHAR) ? ((Character) a).charValue() : ((Number) a).longValue();
+ long bb = (bcode == CHAR) ? ((Character) b).charValue() : ((Number) b).longValue();
+ return aa == bb;
+ }
+ }
+ return false;
+ }
+
+/* OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS */
+
+ /** arg1 + arg2 */
+ public static Object add(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToInteger(val1 + val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToLong(val1 + val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 - arg2 */
+ public static Object substract(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToInteger(val1 - val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToLong(val1 - val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 * arg2 */
+ public static Object multiply(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToInteger(val1 * val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToLong(val1 * val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 / arg2 */
+ public static Object divide(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToInteger(val1 / val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToLong(val1 / val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 % arg2 */
+ public static Object takeModulo(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToInteger(val1 % val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToLong(val1 % val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 >> arg2 */
+ public static Object shiftSignedRight(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ if (code1 <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ if (code2 <= INT) {
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToInteger(val1 >> val2);
+ }
+ if (code2 <= LONG) {
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToInteger(val1 >> val2);
+ }
+ }
+ if (code1 <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ if (code2 <= INT) {
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToLong(val1 >> val2);
+ }
+ if (code2 <= LONG) {
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToLong(val1 >> val2);
+ }
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 << arg2 */
+ public static Object shiftSignedLeft(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ if (code1 <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ if (code2 <= INT) {
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToInteger(val1 << val2);
+ }
+ if (code2 <= LONG) {
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToInteger(val1 << val2);
+ }
+ }
+ if (code1 <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ if (code2 <= INT) {
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToLong(val1 << val2);
+ }
+ if (code2 <= LONG) {
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToLong(val1 << val2);
+ }
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 >>> arg2 */
+ public static Object shiftLogicalRight(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ if (code1 <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ if (code2 <= INT) {
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToInteger(val1 >>> val2);
+ }
+ if (code2 <= LONG) {
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToInteger(val1 >>> val2);
+ }
+ }
+ if (code1 <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ if (code2 <= INT) {
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToLong(val1 >>> val2);
+ }
+ if (code2 <= LONG) {
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToLong(val1 >>> val2);
+ }
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** -arg */
+ public static Object negate(Object arg) throws NoSuchMethodException {
+ int code = typeCode(arg);
+ if (code <= INT) {
+ int val = (code == CHAR) ? ((Character) arg).charValue() : ((Number) arg).intValue();
+ return boxToInteger(-val);
+ }
+ if (code <= LONG) {
+ long val = (code == CHAR) ? ((Character) arg).charValue() : ((Number) arg).longValue();
+ return boxToLong(-val);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** +arg */
+ public static Object positive(Object arg) throws NoSuchMethodException {
+ int code = typeCode(arg);
+ if (code <= INT) {
+ int val = (code == CHAR) ? ((Character) arg).charValue() : ((Number) arg).intValue();
+ return boxToInteger(+val);
+ }
+ if (code <= LONG) {
+ long val = (code == CHAR) ? ((Character) arg).charValue() : ((Number) arg).longValue();
+ return boxToLong(+val);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 & arg2 */
+ public static Object takeAnd(Object arg1, Object arg2) throws NoSuchMethodException {
+ if ((arg1 instanceof Boolean) || (arg2 instanceof Boolean)) {
+ if (!((arg1 instanceof Boolean) && (arg2 instanceof Boolean))) {
+ throw new NoSuchMethodException();
+ }
+ return boxToBoolean(((Boolean) arg1).booleanValue() & ((Boolean) arg2).booleanValue());
+ }
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToInteger(val1 & val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToLong(val1 & val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 | arg2 */
+ public static Object takeOr(Object arg1, Object arg2) throws NoSuchMethodException {
+ if ((arg1 instanceof Boolean) || (arg2 instanceof Boolean)) {
+ if (!((arg1 instanceof Boolean) && (arg2 instanceof Boolean))) {
+ throw new NoSuchMethodException();
+ }
+ return boxToBoolean(((Boolean) arg1).booleanValue() | ((Boolean) arg2).booleanValue());
+ }
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToInteger(val1 | val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToLong(val1 | val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 ^ arg2 */
+ public static Object takeXor(Object arg1, Object arg2) throws NoSuchMethodException {
+ if ((arg1 instanceof Boolean) || (arg2 instanceof Boolean)) {
+ if (!((arg1 instanceof Boolean) && (arg2 instanceof Boolean))) {
+ throw new NoSuchMethodException();
+ }
+ return boxToBoolean(((Boolean) arg1).booleanValue() ^ ((Boolean) arg2).booleanValue());
+ }
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToInteger(val1 ^ val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToLong(val1 ^ val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 && arg2 */
+ public static Object takeConditionalAnd(Object arg1, Object arg2) throws NoSuchMethodException {
+ if ((arg1 instanceof Boolean) && (arg2 instanceof Boolean)) {
+ return boxToBoolean(((Boolean) arg1).booleanValue() && ((Boolean) arg2).booleanValue());
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 || arg2 */
+ public static Object takeConditionalOr(Object arg1, Object arg2) throws NoSuchMethodException {
+ if ((arg1 instanceof Boolean) && (arg2 instanceof Boolean)) {
+ return boxToBoolean(((Boolean) arg1).booleanValue() || ((Boolean) arg2).booleanValue());
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** ~arg */
+ public static Object complement(Object arg) throws NoSuchMethodException {
+ int code = typeCode(arg);
+ if (code <= INT) {
+ int val = (code == CHAR) ? ((Character) arg).charValue() : ((Number) arg).intValue();
+ return boxToInteger(~val);
+ }
+ if (code <= LONG) {
+ long val = (code == CHAR) ? ((Character) arg).charValue() : ((Number) arg).longValue();
+ return boxToLong(~val);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** !arg */
+ public static Object takeNot(Object arg) throws NoSuchMethodException {
+ if (arg instanceof Boolean) {
+ return boxToBoolean(!((Boolean) arg).booleanValue());
+ }
+ throw new NoSuchMethodException();
+ }
+
+ public static Object testEqual(Object arg1, Object arg2) throws NoSuchMethodException {
+ return boxToBoolean(arg1 == arg2);
+ }
+
+ public static Object testNotEqual(Object arg1, Object arg2) throws NoSuchMethodException {
+ return boxToBoolean(arg1 != arg2);
+ }
+
+ public static Object testLessThan(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToBoolean(val1 < val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToBoolean(val1 < val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ public static Object testLessOrEqualThan(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToBoolean(val1 <= val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToBoolean(val1 <= val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ public static Object testGreaterOrEqualThan(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToBoolean(val1 >= val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToBoolean(val1 >= val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ public static Object testGreaterThan(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToBoolean(val1 > val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToBoolean(val1 > val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** 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 Long) return boxToCharacter((char)unboxToLong(arg));
+ throw new NoSuchMethodException();
+ }
+
+ /** arg.toByte */
+ public static Byte toByte(Object arg) throws NoSuchMethodException {
+ 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));
+ throw new NoSuchMethodException();
+ }
+
+ /** arg.toShort */
+ public static Short toShort(Object arg) throws NoSuchMethodException {
+ 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));
+ throw new NoSuchMethodException();
+ }
+
+ /** 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));
+ throw new NoSuchMethodException();
+ }
+
+ /** arg.toLong */
+ public static Long toLong(Object arg) throws NoSuchMethodException {
+ 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;
+ throw new NoSuchMethodException();
+ }
+
+}
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 36264dfa84..29b47abbc9 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -43,9 +43,7 @@ abstract class GenICode extends SubComponent {
val SCALA_ALLREF = REFERENCE(definitions.AllRefClass)
val THROWABLE = REFERENCE(definitions.ThrowableClass)
- val BoxedCharacterClass = if (forMSIL) null else definitions.getClass("java.lang.Character")
- val Comparator_equals = definitions.getMember(definitions.getModule("scala.runtime.Comparator"),
- nme.equals_)
+ val BoxesRunTime_equals = definitions.getMember(definitions.BoxesRunTimeClass, nme.equals_)
override def run: Unit = {
scalaPrimitives.init
@@ -1450,7 +1448,7 @@ abstract class GenICode extends SubComponent {
(sym isNonBottomSubClass definitions.LongClass)
}
else ((sym isNonBottomSubClass definitions.BoxedNumberClass) ||
- (!forMSIL && (sym isNonBottomSubClass BoxedCharacterClass)))
+ (!forMSIL && (sym isNonBottomSubClass definitions.BoxedCharacterClass)))
val lsym = l.tpe.typeSymbol
val rsym = r.tpe.typeSymbol
@@ -1463,7 +1461,7 @@ abstract class GenICode extends SubComponent {
val ctx1 = genLoad(l, ctx, ANY_REF_CLASS)
val ctx2 = genLoad(r, ctx1, ANY_REF_CLASS)
- ctx2.bb.emit(CALL_METHOD(Comparator_equals, Static(false)))
+ ctx2.bb.emit(CALL_METHOD(BoxesRunTime_equals, Static(false)))
ctx2.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL))
ctx2.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 39d6226ff4..5088c602d4 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -60,7 +60,7 @@ abstract class GenJVM extends SubComponent {
class BytecodeGenerator {
val MIN_SWITCH_DENSITY = 0.7
val StringBufferClass = if (settings.target.value == "jvm-1.5") "java.lang.StringBuilder" else "java.lang.StringBuffer"
- val BoxesUtility = "scala.runtime.BoxesUtility"
+ val BoxesRunTime = "scala.runtime.BoxesRunTime"
val stringBufferType = new JObjectType(StringBufferClass)
val toStringType = new JMethodType(JObjectType.JAVA_LANG_STRING, JType.EMPTY_ARRAY)
@@ -815,11 +815,11 @@ abstract class GenJVM extends SubComponent {
case BOX(kind) =>
val boxedType = definitions.boxedClass(kind.toType.typeSymbol)
val mtype = new JMethodType(javaType(boxedType), Array(javaType(kind)))
- jcode.emitINVOKESTATIC(BoxesUtility, "boxTo" + boxedType.nameString, mtype)
+ jcode.emitINVOKESTATIC(BoxesRunTime, "boxTo" + boxedType.nameString, mtype)
case UNBOX(kind) =>
val mtype = new JMethodType(javaType(kind), Array(JObjectType.JAVA_LANG_OBJECT))
- jcode.emitINVOKESTATIC(BoxesUtility, "unboxTo" + kind.toType.typeSymbol.nameString, mtype)
+ jcode.emitINVOKESTATIC(BoxesRunTime, "unboxTo" + kind.toType.typeSymbol.nameString, 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 42a3336137..92b4afce17 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -307,12 +307,14 @@ trait Definitions {
var PatternWildcard: Symbol = _
// boxed classes
- lazy val BoxesUtilityClass = getModule("scala.runtime.BoxesUtility")
+ lazy val BoxesRunTimeClass = getModule("scala.runtime.BoxesRunTime")
lazy val BoxedArrayClass = getClass("scala.runtime.BoxedArray")
lazy val BoxedAnyArrayClass = getClass("scala.runtime.BoxedAnyArray")
lazy val BoxedObjectArrayClass = getClass("scala.runtime.BoxedObjectArray")
lazy val BoxedUnitClass = getClass("scala.runtime.BoxedUnit")
lazy val BoxedNumberClass = getClass(sn.BoxedNumber)
+ lazy val BoxedCharacterClass = getClass(sn.BoxedCharacter)
+ lazy val BoxedBooleanClass = getClass(sn.BoxedBoolean)
lazy val BoxedUnitModule = getModule("scala.runtime.BoxedUnit")
def BoxedUnit_UNIT = getMember(BoxedUnitModule, "UNIT")
lazy val ObjectRefClass = getClass("scala.runtime.ObjectRef")
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
index 4b9b9292cf..de4fa90b7e 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
@@ -116,6 +116,8 @@ abstract class SymbolTable extends Names
val IOOBException: Name // IndexOutOfBoundsException
val Code : Name
val BoxedNumber : Name
+ val BoxedCharacter : Name
+ val BoxedBoolean : Name
import scala.collection.mutable.HashMap
val Boxed = new HashMap[Name, Name]
@@ -132,6 +134,8 @@ abstract class SymbolTable extends Names
final val Delegate = nme.NOSYMBOL
final val IOOBException = newTermName("java.lang.IndexOutOfBoundsException")
final val BoxedNumber = newTermName("java.lang.Number")
+ final val BoxedCharacter = newTermName("java.lang.Character")
+ final val BoxedBoolean = newTermName("java.lang.Boolean")
Boxed += nme.Boolean -> newTermName("java.lang.Boolean")
Boxed += nme.Byte -> newTermName("java.lang.Byte")
@@ -157,6 +161,8 @@ abstract class SymbolTable extends Names
final val IOOBException = newTermName("System.IndexOutOfRangeException")
final val Code = nme.NOSYMBOL
final val BoxedNumber = newTermName("System.IConvertible")
+ final val BoxedCharacter = newTermName("System.IConvertible")
+ final val BoxedBoolean = newTermName("System.IConvertible")
Boxed += nme.Boolean -> newTermName("System.Boolean")
Boxed += nme.Byte -> newTermName("System.Byte")
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
index 9dce5031ea..8cb95aae74 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
@@ -630,10 +630,10 @@ abstract class ICodeReader extends ClassfileParser {
/** TODO: move in Definitions and remove obsolete isBox/isUnbox found there. */
def isBox(m: Symbol): Boolean =
- (m.owner == definitions.BoxesUtilityClass.moduleClass
+ (m.owner == definitions.BoxesRunTimeClass.moduleClass
&& m.name.startsWith("boxTo"))
def isUnbox(m: Symbol): Boolean =
- (m.owner == definitions.BoxesUtilityClass.moduleClass
+ (m.owner == definitions.BoxesRunTimeClass.moduleClass
&& m.name.startsWith("unboxTo"))
/** Return the icode class that should include members with the given flags.
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
index 14739b5e31..b0140dae73 100644
--- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala
+++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
@@ -47,10 +47,7 @@ abstract class CleanUp extends Transform {
}
}
- private var localTyper: analyzer.Typer = null;
-
- private def freshClassConstantMethName() = unit.fresh.newName("class$Method")
- private def freshClassConstantVarName() = unit.fresh.newName("class$Cache")
+ private var localTyper: analyzer.Typer = null
private def classConstantMethod(pos: Position, sig: String): Symbol = classConstantMeth.get(sig) match {
case Some(meth) =>
@@ -59,7 +56,7 @@ abstract class CleanUp extends Transform {
val forName = getMember(ClassClass.linkedModuleOfClass, nme.forName)
val owner = currentOwner.enclClass
- val cvar = owner.newVariable(pos, freshClassConstantVarName())
+ val cvar = owner.newVariable(pos, unit.fresh.newName("class$Cache"))
.setFlag(PRIVATE | STATIC | MUTABLE | SYNTHETIC).setInfo(ClassClass.tpe)
owner.info.decls.enter(cvar)
val cdef =
@@ -69,7 +66,7 @@ abstract class CleanUp extends Transform {
}
}
- val meth = owner.newMethod(pos, freshClassConstantMethName())
+ val meth = owner.newMethod(pos, unit.fresh.newName("class$Method"))
.setFlag(PRIVATE | STATIC | SYNTHETIC).setInfo(MethodType(List(), ClassClass.tpe))
owner.info.decls.enter(meth)
val mdef =
@@ -88,6 +85,90 @@ abstract class CleanUp extends Transform {
meth
}
+ private val existingReflectiveMethodCache = new HashMap[(String, List[Type]), Symbol]
+
+ /* Transforms a list of types into a list of trees representing these types
+ * as java.lang.Class instances. */
+ private def paramTypeClasses(paramTypes: List[Type]): List[Tree] =
+ paramTypes map { pt => Literal(Constant(pt)) }
+
+ private def reflectiveMethodCache(pos: Position, method: String, paramTypes: List[Type]): Symbol =
+ existingReflectiveMethodCache.get((method, paramTypes)) match {
+ case Some(cache) => cache
+ case None =>
+ val owner = currentOwner.enclClass
+
+ val rmvar = owner.newVariable(pos, unit.fresh.newName("reflMethod$Cache"))
+ .setFlag(PRIVATE | STATIC | MUTABLE | SYNTHETIC)
+ .setInfo(MethodClass.tpe)
+ owner.info.decls.enter(rmvar)
+ val rmdef =
+ localTyper.typed {
+ atPos(pos) {
+ ValDef(rmvar, Literal(Constant(null)))
+ }
+ }
+
+ val rmcvar = owner.newVariable(pos, unit.fresh.newName("reflClass$Cache"))
+ .setFlag(PRIVATE | STATIC | MUTABLE | SYNTHETIC)
+ .setInfo(ClassClass.tpe)
+ owner.info.decls.enter(rmcvar)
+ val rmcdef =
+ localTyper.typed {
+ atPos(pos) {
+ ValDef(rmcvar, Literal(Constant(null)))
+ }
+ }
+
+ val rmmeth = owner.newMethod(pos, unit.fresh.newName("reflMethod$Method"))
+ .setFlag(PRIVATE | STATIC | SYNTHETIC)
+ .setInfo(MethodType(List(ClassClass.tpe), MethodClass.tpe))
+ owner.info.decls.enter(rmmeth)
+ val rmmdef =
+ localTyper.typed {
+ atPos(pos) {
+ DefDef(rmmeth, { vparamss =>
+ val callClass = vparamss(0)(0)
+ Block(
+ List(
+ If(
+ gen.mkOr(
+ Apply(Select(Select(This(owner), rmvar), nme.eq), List(Literal(Constant(null)))),
+ Apply(Select(Select(This(owner), rmcvar), nme.ne), List(gen.mkAttributedRef(callClass)))
+ ),
+ Block(
+ List(
+ Assign(
+ Select(This(owner), rmvar),
+ Apply(
+ Select(
+ gen.mkAttributedRef(callClass),
+ ClassClass.tpe.member(nme.getMethod_)
+ ),
+ List(
+ Literal(Constant(method)),
+ ArrayValue(TypeTree(ClassClass.tpe), paramTypeClasses(paramTypes))
+ )
+ )
+ ),
+ Assign(Select(This(owner), rmcvar), gen.mkAttributedRef(callClass))
+ ),
+ Literal(Constant(()))
+ ),
+ EmptyTree
+ )
+ ),
+ Select(This(owner), rmvar)
+ )
+ })
+ }
+ }
+
+ newDefs.append(transform(rmdef), transform(rmcdef), transform(rmmdef));
+ existingReflectiveMethodCache.update((method, paramTypes), rmmeth)
+ rmmeth
+ }
+
override def transformUnit(unit: CompilationUnit) =
unit.body = transform(unit.body)
@@ -131,7 +212,104 @@ abstract class CleanUp extends Transform {
* type variable. */
case ad@ApplyDynamic(qual, params) =>
assert(ad.symbol.isPublic)
- val thisTyper = typer.atOwner(tree, currentOwner)
+
+ val testForNumber: Tree =
+ gen.mkOr(
+ Apply(
+ TypeApply(
+ gen.mkAttributedSelect(qual, definitions.Object_isInstanceOf),
+ List(TypeTree(BoxedNumberClass.tpe.normalize))
+ ),
+ List()
+ ),
+ Apply(
+ TypeApply(
+ gen.mkAttributedSelect(qual, definitions.Object_isInstanceOf),
+ List(TypeTree(BoxedCharacterClass.tpe.normalize))
+ ),
+ List()
+ )
+ )
+
+ val testForBoolean: Tree =
+ Apply(
+ TypeApply(
+ gen.mkAttributedSelect(qual, definitions.Object_isInstanceOf),
+ List(TypeTree(BoxedBooleanClass.tpe.normalize))
+ ),
+ List()
+ )
+
+ val testForNumberOrBoolean: Tree = gen.mkOr(testForNumber, testForBoolean)
+
+ def getPrimitiveReplacementForStructuralCall: PartialFunction[Name, (Symbol, Tree)] = {
+ /* Unary arithmetic */
+ case nme.UNARY_+ =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("positive")), testForNumber)
+ case nme.UNARY_- =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("negate")), testForNumber)
+ /* Unary logic */
+ case nme.UNARY_~ =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("complement")), testForNumber)
+ case nme.UNARY_! =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("takeNot")), testForBoolean)
+ /* Binary arithmetic */
+ case nme.ADD =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("add")), testForNumber)
+ case nme.SUB =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("substract")), testForNumber)
+ case nme.MUL =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("multiply")), testForNumber)
+ case nme.DIV =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("divide")), testForNumber)
+ case nme.MOD =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("takeModulo")), testForNumber)
+ /* Binary logic */
+ case nme.OR =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("takeOr")), testForNumberOrBoolean)
+ case nme.XOR =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("takeXor")), testForNumberOrBoolean)
+ case nme.AND =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("takeAnd")), testForNumberOrBoolean)
+ case nme.ZOR =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("takeConditionalOr")), testForBoolean)
+ case nme.ZAND =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("takeConditionalAnd")), testForBoolean)
+ /* Shifting */
+ case nme.LSL =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("shiftSignedLeft")), testForNumber)
+ case nme.LSR =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("shiftSignedRight")), testForNumber)
+ case nme.ASR =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("shiftLogicalRight")), testForNumber)
+ case nme.EQ =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("testEqual")), testForNumberOrBoolean)
+ case nme.NE =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("testNotEqual")), testForNumberOrBoolean)
+ case nme.LT =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("testLessThan")), testForNumber)
+ case nme.LE =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("testLessOrEqualThan")), testForNumber)
+ case nme.GE =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("testGreaterOrEqualThan")), testForNumber)
+ case nme.GT =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("testGreaterThan")), testForNumber)
+ /* Conversions */
+ case nme.toByte =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("toByte")), testForNumber)
+ case nme.toShort =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("toShort")), testForNumber)
+ case nme.toChar =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("toCharacter")), testForNumber)
+ case nme.toInt =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("toInteger")), testForNumber)
+ case nme.toLong =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("toLong")), testForNumber)
+ case nme.toFloat =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("toFloat")), testForNumber)
+ case nme.toDouble =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("toDouble")), testForNumber)
+ }
/* Transforms the result of a reflective call (always an AnyRef) to
* the actual result value (an AnyRef too). The transformation
@@ -144,32 +322,33 @@ abstract class CleanUp extends Transform {
* is enough even for value (int et al.) values as the result of
* a dynamic call will box them as a side-effect. */
def fixResult(resType: Type)(tree: Tree): Tree =
- thisTyper.typed {
+ localTyper.typed {
if (resType.typeSymbol == UnitClass)
Block (
List(tree),
gen.mkAttributedRef(BoxedUnit_UNIT)
)
- else {
+ else if (resType.typeSymbol == ArrayClass) {
val sym = currentOwner.newValue(tree.pos, newTermName(unit.fresh.newName)) setInfo ObjectClass.tpe
Block(
List(ValDef(sym, tree)),
If(
Apply(Select(Literal(Constant(null)), Any_==), List(gen.mkAttributedRef(sym))),
Literal(Constant(null)),
- if (resType.typeSymbol == ArrayClass)
- Apply(
- Select(
- gen.mkAttributedRef(ScalaRunTimeModule),
- ScalaRunTimeModule.tpe.member(nme.boxArray)
- ),
- List(gen.mkAttributedRef(sym))
- )
- else
- gen.mkAttributedCast(gen.mkAttributedRef(sym), resType)
+ Apply(
+ Select(
+ gen.mkAttributedRef(ScalaRunTimeModule),
+ ScalaRunTimeModule.tpe.member(nme.boxArray)
+ ),
+ List(gen.mkAttributedRef(sym))
+ )
)
)
}
+ else if (resType.typeSymbol == ObjectClass) // TODO: remove the cast always when unnecessary.
+ tree
+ else
+ gen.mkAttributedCast(tree, resType)
}
/* Transforms the parameters of a dynamic apply (always AnyRefs) to
@@ -180,7 +359,7 @@ abstract class CleanUp extends Transform {
* unboxed array, it is left alone. */
def fixParams(params: List[Tree], paramTypes: List[Type]): List[Tree] =
(params zip paramTypes) map { case (param, paramType) =>
- thisTyper.typed {
+ localTyper.typed {
if (paramType.typeSymbol == ArrayClass) {
val sym = currentOwner.newValue(tree.pos, newTermName(unit.fresh.newName)) setInfo ObjectClass.tpe
val arrayType = {
@@ -214,15 +393,59 @@ abstract class CleanUp extends Transform {
}
}
- /* Transforms a list of types into a list of trees representing these types
- * as java.lang.Class instances. */
- def paramTypeClasses(paramTypes: List[Type]): List[Tree] =
- paramTypes map { pt => Literal(Constant(pt)) }
+ def callAsOperator(paramTypes: List[Type], resType: Type): Tree = localTyper.typed {
+ if (getPrimitiveReplacementForStructuralCall isDefinedAt ad.symbol.name) {
+ val (operator, test) = getPrimitiveReplacementForStructuralCall(ad.symbol.name)
+ If(
+ test,
+ Apply(
+ gen.mkAttributedRef(operator),
+ qual :: fixParams(params, paramTypes)
+ ),
+ callAsMethod(paramTypes, resType)
+ )
+ }
+ else callAsMethod(paramTypes, resType)
+ }
+
+ def callAsMethod(paramTypes: List[Type], resType: Type): Tree = localTyper.typed {
+ Apply(
+ Select(
+ Apply(
+ gen.mkAttributedRef(reflectiveMethodCache(tree.pos, ad.symbol.name.toString, paramTypes)),
+ List(Apply(Select(qual, ObjectClass.tpe.member(nme.getClass_)), Nil))
+ ),
+ MethodClass.tpe.member(nme.invoke_)
+ ),
+ List(
+ qual,
+ ArrayValue(TypeTree(ObjectClass.tpe), fixParams(params, paramTypes))
+ )
+ )
+ }
+
+ def mayRequirePrimitiveReplacement: Boolean = {
+
+ def isBoxed(sym: Symbol): Boolean =
+ if (forCLDC) {
+ (sym isNonBottomSubClass ByteClass) ||
+ (sym isNonBottomSubClass ShortClass) ||
+ (sym isNonBottomSubClass CharClass) ||
+ (sym isNonBottomSubClass IntClass) ||
+ (sym isNonBottomSubClass LongClass)
+ }
+ else ((sym isNonBottomSubClass BoxedNumberClass) ||
+ (!forMSIL && (sym isNonBottomSubClass BoxedCharacterClass)))
+
+ val sym = qual.tpe.typeSymbol
+ (sym == definitions.ObjectClass) || isBoxed(sym)
+
+ }
/* This creates the tree that does the reflective call (see general comment
* on the apply-dynamic tree for its format). This tree is simply composed
* of three succesive calls, first to getClass on the callee, then to
- * getMethod on the class, then to invoke on the method.
+ * getMethod on the classs, then to invoke on the method.
* - getMethod needs an array of classes for choosing one amongst many
* overloaded versions of the method. This is provided by paramTypeClasses
* and must be done on the static type as Scala's dispatching is static on
@@ -243,27 +466,12 @@ abstract class CleanUp extends Transform {
val t: Tree = ad.symbol.tpe match {
case MethodType(paramTypes, resType) =>
assert(params.length == paramTypes.length)
- atPos(tree.pos)(thisTyper.typed {
+ atPos(tree.pos)(localTyper.typed {
fixResult(if (isValueClass(resType.typeSymbol)) boxedClass(resType.typeSymbol).tpe else resType) {
- Apply(
- Select(
- Apply(
- Select(
- Apply(Select(qual, ObjectClass.tpe.member(nme.getClass_)), Nil),
- ClassClass.tpe.member(nme.getMethod_)
- ),
- List(
- Literal(Constant(ad.symbol.name.toString)),
- ArrayValue(TypeTree(ClassClass.tpe), paramTypeClasses(paramTypes))
- )
- ),
- MethodClass.tpe.member(nme.invoke_)
- ),
- List(
- transform(qual),
- ArrayValue(TypeTree(ObjectClass.tpe), fixParams(params, paramTypes))
- )
- )
+ if (mayRequirePrimitiveReplacement)
+ callAsOperator(paramTypes, resType)
+ else
+ callAsMethod(paramTypes, resType)
}
})
}
@@ -298,12 +506,10 @@ abstract class CleanUp extends Transform {
case Template(parents, self, body) if !forMSIL =>
localTyper = typer.atOwner(tree, currentOwner)
- if (settings.target.value != "jvm-1.5" && !forMSIL) {
- classConstantMeth.clear
- newDefs.clear
- val body1 = transformTrees(body)
- copy.Template(tree, parents, self, newDefs.toList ::: body1)
- } else super.transform(tree)
+ classConstantMeth.clear
+ newDefs.clear
+ val body1 = transformTrees(body)
+ copy.Template(tree, parents, self, newDefs.toList ::: body1)
case Literal(c) if (c.tag == ClassTag) && !forMSIL=>
val tpe = c.typeValue
@@ -311,7 +517,7 @@ abstract class CleanUp extends Transform {
localTyper.typed {
if (isValueClass(tpe.typeSymbol) && !forCLDC)
Select(gen.mkAttributedRef(javaBoxClassModule(tpe.typeSymbol)), "TYPE")
- else if (settings.target.value != "jvm-1.5")
+ else if (settings.target.value != "jvm-1.5" && !forMSIL)
Apply(
gen.mkAttributedRef(classConstantMethod(tree.pos, signature(tpe))),
List())
diff --git a/src/library/scala/runtime/BoxesRunTime.java b/src/library/scala/runtime/BoxesRunTime.java
new file mode 100644
index 0000000000..012360f8fe
--- /dev/null
+++ b/src/library/scala/runtime/BoxesRunTime.java
@@ -0,0 +1,794 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2007, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+// $Id$
+
+
+package scala.runtime;
+
+/** An object (static class) that defines methods used for creating,
+ * reverting, and calculating with, boxed values. There are four classes
+ * of methods in this object:
+ * - High-performance value boxing methods that feed from a pre-
+ * computed map of instances for the most common instanciations.
+ * - Convenience unboxing methods returning default value on null.
+ * - The generalised comparison method to be used when an object may
+ * be a boxed value.
+ * - Standard value operators for boxed number and quasi-number values.
+ *
+ * @author Gilles Dubochet
+ * @author Martin Odersky
+ * @contributor Stepan Koltsov
+ * @version 2.0 */
+public class BoxesRunTime {
+
+ private static final int CHAR = 0, BYTE = 1, SHORT = 2, INT = 3, LONG = 4, FLOAT = 5, DOUBLE = 6, OTHER = 7;
+
+ private static int typeCode(Object a) {
+ if (a instanceof Integer) return INT;
+ 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;
+ return OTHER;
+ }
+
+/* BOXING ... BOXING ... BOXING ... BOXING ... BOXING ... BOXING ... BOXING ... BOXING */
+
+ private static int charLowBound = 0;
+ private static int charUpBound = 255;
+ private static Character[] charCache = new Character[charUpBound - charLowBound + 1];
+
+ private static int byteLowBound = -128;
+ private static int byteUpBound = 127;
+ private static Byte[] byteCache = new Byte[byteUpBound - byteLowBound + 1];
+
+ private static int shortLowBound = -128;
+ private static int shortUpBound = 127;
+ private static Short[] shortCache = new Short[shortUpBound - shortLowBound + 1];
+
+ private static int intLowBound = -128;
+ private static int intUpBound = 1024;
+ private static Integer[] intCache = new Integer[intUpBound - intLowBound + 1];
+
+ private static int longLowBound = -128;
+ private static int longUpBound = 1024;
+ private static Long[] longCache = new Long[longUpBound - longLowBound + 1];
+
+ static {
+ int idx = 0;
+ while (idx <= charUpBound - charLowBound) {
+ charCache[idx] = new Character((char)(idx + charLowBound));
+ idx = idx + 1;
+ }
+ idx = 0;
+ while (idx <= byteUpBound - byteLowBound) {
+ byteCache[idx] = new Byte((byte)(idx + byteLowBound));
+ idx = idx + 1;
+ }
+ idx = 0;
+ while (idx <= shortUpBound - shortLowBound) {
+ shortCache[idx] = new Short((short)(idx + shortLowBound));
+ idx = idx + 1;
+ }
+ idx = 0;
+ while (idx <= intUpBound - intLowBound) {
+ intCache[idx] = new Integer((int)(idx + intLowBound));
+ idx = idx + 1;
+ }
+ idx = 0;
+ while (idx <= longUpBound - longLowBound) {
+ longCache[idx] = new Long((long)(idx + longLowBound));
+ idx = idx + 1;
+ }
+ }
+
+ public static Boolean boxToBoolean(boolean b) {
+ return b ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ public static Character boxToCharacter(char c) {
+ if (c >= charLowBound && c <= charUpBound)
+ return charCache[(int)c - charLowBound];
+ return new Character(c);
+ }
+
+ public static Byte boxToByte(byte b) {
+ if (b >= byteLowBound && b <= byteUpBound)
+ return byteCache[(int)b - byteLowBound];
+ return new Byte(b);
+ }
+
+ public static Short boxToShort(short s) {
+ if (s >= shortLowBound && s <= shortUpBound)
+ return shortCache[(int)s - shortLowBound];
+ return new Short(s);
+ }
+
+ public static Integer boxToInteger(int i) {
+ if (i >= intLowBound && i <= intUpBound)
+ return intCache[(int)i - intLowBound];
+ return new Integer(i);
+ }
+
+ public static Long boxToLong(long l) {
+ if (l >= longLowBound && l <= longUpBound)
+ return longCache[(int)l - longLowBound];
+ return new Long(l);
+ }
+
+ public static Float boxToFloat(float f) {
+ return new Float(f);
+ }
+
+ public static Double boxToDouble(double d) {
+ return new Double(d);
+ }
+
+/* UNBOXING ... UNBOXING ... UNBOXING ... UNBOXING ... UNBOXING ... UNBOXING ... UNBOXING */
+
+ public static boolean unboxToBoolean(Object b) {
+ return b == null ? false : ((Boolean)b).booleanValue();
+ }
+
+ public static char unboxToChar(Object c) {
+ return c == null ? 0 : ((Character)c).charValue();
+ }
+
+ public static byte unboxToByte(Object b) {
+ return b == null ? 0 : ((Byte)b).byteValue();
+ }
+
+ public static short unboxToShort(Object s) {
+ return s == null ? 0 : ((Short)s).shortValue();
+ }
+
+ public static int unboxToInt(Object i) {
+ return i == null ? 0 : ((Integer)i).intValue();
+ }
+
+ public static long unboxToLong(Object l) {
+ return l == null ? 0 : ((Long)l).longValue();
+ }
+
+ public static float unboxToFloat(Object f) {
+ return f == null ? 0.0f : ((Float)f).floatValue();
+ }
+
+ public static double unboxToDouble(Object d) {
+ return d == null ? 0.0d : ((Double)d).doubleValue();
+ }
+
+/* COMPARISON ... COMPARISON ... COMPARISON ... COMPARISON ... COMPARISON ... COMPARISON */
+
+ /** A rich implementation of the <code>equals</code> method that overrides the
+ * default equals because Java's boxed primitives are utterly broken. This equals
+ * is inserted instead of a normal equals by the Scala compiler (in the
+ * ICode phase, method <code>genEqEqPrimitive</code>) only when either
+ * side of the comparison is a subclass of <code>AnyVal</code>, of
+ * <code>java.lang.Number</code>, of <code>java.lang.Character</code> or
+ * is exactly <code>Any</code> or <code>AnyRef</code>. */
+ public static boolean equals(Object a, Object b) {
+ if (a == null || b == null)
+ return a == b;
+ if (a.equals(b))
+ return true;
+ if (a instanceof Number || a instanceof Character || b instanceof Number || b instanceof Character) {
+ int acode = typeCode(a);
+ int bcode = typeCode(b);
+ int maxcode = (acode < bcode) ? bcode : acode;
+ if (maxcode <= INT) {
+ int aa = (acode == CHAR) ? ((Character) a).charValue() : ((Number) a).intValue();
+ int bb = (bcode == CHAR) ? ((Character) b).charValue() : ((Number) b).intValue();
+ return aa == bb;
+ }
+ if (maxcode <= LONG) {
+ long aa = (acode == CHAR) ? ((Character) a).charValue() : ((Number) a).longValue();
+ long bb = (bcode == CHAR) ? ((Character) b).charValue() : ((Number) b).longValue();
+ return aa == bb;
+ }
+ if (maxcode <= FLOAT) {
+ float aa = (acode == CHAR) ? ((Character) a).charValue() : ((Number) a).floatValue();
+ float bb = (bcode == CHAR) ? ((Character) b).charValue() : ((Number) b).floatValue();
+ return aa == bb;
+ }
+ if (maxcode <= DOUBLE) {
+ double aa = (acode == CHAR) ? ((Character) a).charValue() : ((Number) a).doubleValue();
+ double bb = (bcode == CHAR) ? ((Character) b).charValue() : ((Number) b).doubleValue();
+ return aa == bb;
+ }
+ }
+ return false;
+ }
+
+/* OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS */
+
+ /** arg1 + arg2 */
+ public static Object add(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToInteger(val1 + val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToLong(val1 + val2);
+ }
+ if (maxcode <= FLOAT) {
+ float val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).floatValue();
+ float val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).floatValue();
+ return boxToFloat(val1 + val2);
+ }
+ if (maxcode <= DOUBLE) {
+ double val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).doubleValue();
+ double val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).doubleValue();
+ return boxToDouble(val1 + val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 - arg2 */
+ public static Object substract(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToInteger(val1 - val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToLong(val1 - val2);
+ }
+ if (maxcode <= FLOAT) {
+ float val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).floatValue();
+ float val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).floatValue();
+ return boxToFloat(val1 - val2);
+ }
+ if (maxcode <= DOUBLE) {
+ double val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).doubleValue();
+ double val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).doubleValue();
+ return boxToDouble(val1 - val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 * arg2 */
+ public static Object multiply(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToInteger(val1 * val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToLong(val1 * val2);
+ }
+ if (maxcode <= FLOAT) {
+ float val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).floatValue();
+ float val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).floatValue();
+ return boxToFloat(val1 * val2);
+ }
+ if (maxcode <= DOUBLE) {
+ double val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).doubleValue();
+ double val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).doubleValue();
+ return boxToDouble(val1 * val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 / arg2 */
+ public static Object divide(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToInteger(val1 / val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToLong(val1 / val2);
+ }
+ if (maxcode <= FLOAT) {
+ float val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).floatValue();
+ float val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).floatValue();
+ return boxToFloat(val1 / val2);
+ }
+ if (maxcode <= DOUBLE) {
+ double val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).doubleValue();
+ double val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).doubleValue();
+ return boxToDouble(val1 / val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 % arg2 */
+ public static Object takeModulo(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToInteger(val1 % val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToLong(val1 % val2);
+ }
+ if (maxcode <= FLOAT) {
+ float val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).floatValue();
+ float val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).floatValue();
+ return boxToFloat(val1 % val2);
+ }
+ if (maxcode <= DOUBLE) {
+ double val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).doubleValue();
+ double val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).doubleValue();
+ return boxToDouble(val1 % val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 >> arg2 */
+ public static Object shiftSignedRight(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ if (code1 <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ if (code2 <= INT) {
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToInteger(val1 >> val2);
+ }
+ if (code2 <= LONG) {
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToInteger(val1 >> val2);
+ }
+ }
+ if (code1 <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ if (code2 <= INT) {
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToLong(val1 >> val2);
+ }
+ if (code2 <= LONG) {
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToLong(val1 >> val2);
+ }
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 << arg2 */
+ public static Object shiftSignedLeft(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ if (code1 <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ if (code2 <= INT) {
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToInteger(val1 << val2);
+ }
+ if (code2 <= LONG) {
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToInteger(val1 << val2);
+ }
+ }
+ if (code1 <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ if (code2 <= INT) {
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToLong(val1 << val2);
+ }
+ if (code2 <= LONG) {
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToLong(val1 << val2);
+ }
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 >>> arg2 */
+ public static Object shiftLogicalRight(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ if (code1 <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ if (code2 <= INT) {
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToInteger(val1 >>> val2);
+ }
+ if (code2 <= LONG) {
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToInteger(val1 >>> val2);
+ }
+ }
+ if (code1 <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ if (code2 <= INT) {
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToLong(val1 >>> val2);
+ }
+ if (code2 <= LONG) {
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToLong(val1 >>> val2);
+ }
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** -arg */
+ public static Object negate(Object arg) throws NoSuchMethodException {
+ int code = typeCode(arg);
+ if (code <= INT) {
+ int val = (code == CHAR) ? ((Character) arg).charValue() : ((Number) arg).intValue();
+ return boxToInteger(-val);
+ }
+ if (code <= LONG) {
+ long val = (code == CHAR) ? ((Character) arg).charValue() : ((Number) arg).longValue();
+ return boxToLong(-val);
+ }
+ if (code <= FLOAT) {
+ float val = (code == CHAR) ? ((Character) arg).charValue() : ((Number) arg).floatValue();
+ return boxToFloat(-val);
+ }
+ if (code <= DOUBLE) {
+ double val = (code == CHAR) ? ((Character) arg).charValue() : ((Number) arg).doubleValue();
+ return boxToDouble(-val);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** +arg */
+ public static Object positive(Object arg) throws NoSuchMethodException {
+ int code = typeCode(arg);
+ if (code <= INT) {
+ int val = (code == CHAR) ? ((Character) arg).charValue() : ((Number) arg).intValue();
+ return boxToInteger(+val);
+ }
+ if (code <= LONG) {
+ long val = (code == CHAR) ? ((Character) arg).charValue() : ((Number) arg).longValue();
+ return boxToLong(+val);
+ }
+ if (code <= FLOAT) {
+ float val = (code == CHAR) ? ((Character) arg).charValue() : ((Number) arg).floatValue();
+ return boxToFloat(+val);
+ }
+ if (code <= DOUBLE) {
+ double val = (code == CHAR) ? ((Character) arg).charValue() : ((Number) arg).doubleValue();
+ return boxToDouble(+val);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 & arg2 */
+ public static Object takeAnd(Object arg1, Object arg2) throws NoSuchMethodException {
+ if ((arg1 instanceof Boolean) || (arg2 instanceof Boolean)) {
+ if (!((arg1 instanceof Boolean) && (arg2 instanceof Boolean))) {
+ throw new NoSuchMethodException();
+ }
+ return boxToBoolean(((Boolean) arg1).booleanValue() & ((Boolean) arg2).booleanValue());
+ }
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToInteger(val1 & val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToLong(val1 & val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 | arg2 */
+ public static Object takeOr(Object arg1, Object arg2) throws NoSuchMethodException {
+ if ((arg1 instanceof Boolean) || (arg2 instanceof Boolean)) {
+ if (!((arg1 instanceof Boolean) && (arg2 instanceof Boolean))) {
+ throw new NoSuchMethodException();
+ }
+ return boxToBoolean(((Boolean) arg1).booleanValue() | ((Boolean) arg2).booleanValue());
+ }
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToInteger(val1 | val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToLong(val1 | val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 ^ arg2 */
+ public static Object takeXor(Object arg1, Object arg2) throws NoSuchMethodException {
+ if ((arg1 instanceof Boolean) || (arg2 instanceof Boolean)) {
+ if (!((arg1 instanceof Boolean) && (arg2 instanceof Boolean))) {
+ throw new NoSuchMethodException();
+ }
+ return boxToBoolean(((Boolean) arg1).booleanValue() ^ ((Boolean) arg2).booleanValue());
+ }
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToInteger(val1 ^ val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToLong(val1 ^ val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 && arg2 */
+ public static Object takeConditionalAnd(Object arg1, Object arg2) throws NoSuchMethodException {
+ if ((arg1 instanceof Boolean) && (arg2 instanceof Boolean)) {
+ return boxToBoolean(((Boolean) arg1).booleanValue() && ((Boolean) arg2).booleanValue());
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 || arg2 */
+ public static Object takeConditionalOr(Object arg1, Object arg2) throws NoSuchMethodException {
+ if ((arg1 instanceof Boolean) && (arg2 instanceof Boolean)) {
+ return boxToBoolean(((Boolean) arg1).booleanValue() || ((Boolean) arg2).booleanValue());
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** ~arg */
+ public static Object complement(Object arg) throws NoSuchMethodException {
+ int code = typeCode(arg);
+ if (code <= INT) {
+ int val = (code == CHAR) ? ((Character) arg).charValue() : ((Number) arg).intValue();
+ return boxToInteger(~val);
+ }
+ if (code <= LONG) {
+ long val = (code == CHAR) ? ((Character) arg).charValue() : ((Number) arg).longValue();
+ return boxToLong(~val);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** !arg */
+ public static Object takeNot(Object arg) throws NoSuchMethodException {
+ if (arg instanceof Boolean) {
+ return boxToBoolean(!((Boolean) arg).booleanValue());
+ }
+ throw new NoSuchMethodException();
+ }
+
+ public static Object testEqual(Object arg1, Object arg2) throws NoSuchMethodException {
+ return boxToBoolean(arg1 == arg2);
+ }
+
+ public static Object testNotEqual(Object arg1, Object arg2) throws NoSuchMethodException {
+ return boxToBoolean(arg1 != arg2);
+ }
+
+ public static Object testLessThan(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToBoolean(val1 < val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToBoolean(val1 < val2);
+ }
+ if (maxcode <= FLOAT) {
+ float val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).floatValue();
+ float val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).floatValue();
+ return boxToBoolean(val1 < val2);
+ }
+ if (maxcode <= DOUBLE) {
+ double val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).doubleValue();
+ double val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).doubleValue();
+ return boxToBoolean(val1 < val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ public static Object testLessOrEqualThan(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToBoolean(val1 <= val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToBoolean(val1 <= val2);
+ }
+ if (maxcode <= FLOAT) {
+ float val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).floatValue();
+ float val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).floatValue();
+ return boxToBoolean(val1 <= val2);
+ }
+ if (maxcode <= DOUBLE) {
+ double val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).doubleValue();
+ double val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).doubleValue();
+ return boxToBoolean(val1 <= val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ public static Object testGreaterOrEqualThan(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToBoolean(val1 >= val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToBoolean(val1 >= val2);
+ }
+ if (maxcode <= FLOAT) {
+ float val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).floatValue();
+ float val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).floatValue();
+ return boxToBoolean(val1 >= val2);
+ }
+ if (maxcode <= DOUBLE) {
+ double val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).doubleValue();
+ double val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).doubleValue();
+ return boxToBoolean(val1 >= val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ public static Object testGreaterThan(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).intValue();
+ int val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).intValue();
+ return boxToBoolean(val1 > val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).longValue();
+ long val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).longValue();
+ return boxToBoolean(val1 > val2);
+ }
+ if (maxcode <= FLOAT) {
+ float val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).floatValue();
+ float val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).floatValue();
+ return boxToBoolean(val1 > val2);
+ }
+ if (maxcode <= DOUBLE) {
+ double val1 = (code1 == CHAR) ? ((Character) arg1).charValue() : ((Number) arg1).doubleValue();
+ double val2 = (code2 == CHAR) ? ((Character) arg2).charValue() : ((Number) arg2).doubleValue();
+ return boxToBoolean(val1 > val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** 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 Long) return boxToCharacter((char)unboxToLong(arg));
+ if (arg instanceof Float) return boxToCharacter((char)unboxToFloat(arg));
+ if (arg instanceof Double) return boxToCharacter((char)unboxToDouble(arg));
+ throw new NoSuchMethodException();
+ }
+
+ /** arg.toByte */
+ public static Byte toByte(Object arg) throws NoSuchMethodException {
+ 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 Float) return boxToByte((byte)unboxToFloat(arg));
+ if (arg instanceof Double) return boxToByte((byte)unboxToDouble(arg));
+ throw new NoSuchMethodException();
+ }
+
+ /** arg.toShort */
+ public static Short toShort(Object arg) throws NoSuchMethodException {
+ 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();
+ }
+
+ /** 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));
+ throw new NoSuchMethodException();
+ }
+
+ /** arg.toLong */
+ public static Long toLong(Object arg) throws NoSuchMethodException {
+ 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));
+ 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;
+ throw new NoSuchMethodException();
+ }
+
+}
diff --git a/test/files/run/issue192.check b/test/files/run/issue192.check
new file mode 100644
index 0000000000..78cd78d2fc
--- /dev/null
+++ b/test/files/run/issue192.check
@@ -0,0 +1,36 @@
+f1 = true
+f2 = true
+f3 = true
+f4 = true
+f5 = true
+f6 = true
+f7 = true
+f8 = true
+f9 = true
+f10 = true
+f11 = true
+f12 = true
+f13 = true
+f14 = true
+f15 = true
+f16 = true
+f17 = true
+f18 = true
+f19 = true
+f20 = true
+f21 = true
+f22 = true
+f23 = true
+f24 = true
+f25 = true
+f26 = true
+f27 = true
+f28 = true
+f29 = true
+f30 = true
+f31 = true
+f32 = true
+f33 = true
+f34 = true
+f35 = true
+ok
diff --git a/test/files/run/issue192.scala b/test/files/run/issue192.scala
new file mode 100644
index 0000000000..8756e6a545
--- /dev/null
+++ b/test/files/run/issue192.scala
@@ -0,0 +1,89 @@
+object Test extends Application {
+
+ def f1(p: Any{def unary_+ : Int}) = +p
+ def f2(p: Any{def unary_- : Int}) = -p
+ def f3(p: Any{def unary_~ : Int}) = ~p
+ def f4(p: Any{def unary_! : Boolean}) = !p
+
+ def f5(p: Any{def +(q: Int): Int}) = p + 7
+ def f6(p: Any{def -(q: Int): Int}) = p - 7
+ def f7(p: Any{def *(q: Int): Int}) = p * 7
+ def f8(p: Any{def /(q: Int): Int}) = p / 7
+ def f9(p: Any{def %(q: Int): Int}) = p % 7
+
+ def f10(p: Any{def |(q: Int): Int}) = p | 7
+ def f11(p: Any{def |(q: Boolean): Boolean}) = p | true
+ def f12(p: Any{def ^(q: Int): Int}) = p ^ 7
+ def f13(p: Any{def ^(q: Boolean): Boolean}) = p ^ true
+ def f14(p: Any{def &(q: Int): Int}) = p & 7
+ def f15(p: Any{def &(q: Boolean): Boolean}) = p & true
+ def f16(p: Any{def ||(q: Boolean): Boolean}) = p || true
+ def f17(p: Any{def &&(q: Boolean): Boolean}) = p && true
+
+ def f18(p: Any{def <<(q: Int): Int}) = p << 7
+ def f19(p: Any{def >>(q: Int): Int}) = p >> 7
+ def f20(p: Any{def >>>(q: Int): Int}) = p >>> 7
+
+ def f21(p: Any{def toByte: Byte}) = p.toByte
+ def f22(p: Any{def toShort: Short}) = p.toShort
+ def f23(p: Any{def toChar: Char}) = p.toChar
+ def f24(p: Any{def toInt: Int}) = p.toInt
+ def f25(p: Any{def toLong: Long}) = p.toLong
+ def f26(p: Any{def toFloat: Float}) = p.toFloat
+ def f27(p: Any{def toDouble: Double}) = p.toDouble
+
+ def f28(p: Any{def ==(q: Int): Boolean}) = p == 7
+ def f29(p: Any{def !=(q: Int): Boolean}) = p != 7
+ def f30(p: Any{def ==(q: Boolean): Boolean}) = p == true
+ def f31(p: Any{def !=(q: Boolean): Boolean}) = p != true
+
+ def f32(p: Any{def <(q: Int): Boolean}) = p < 7
+ def f33(p: Any{def <=(q: Int): Boolean}) = p <= 7
+ def f34(p: Any{def >=(q: Int): Boolean}) = p >= 7
+ def f35(p: Any{def >(q: Int): Boolean}) = p > 7
+
+ print("f1 = "); println(f1(1) == +1)
+ print("f2 = "); println(f2(1) == -1)
+ print("f3 = "); println(f3(1) == ~1)
+ print("f4 = "); println(f4(true) == !true)
+
+ print("f5 = "); println(f5(4) == (4 + 7))
+ print("f6 = "); println(f6(4) == (4 - 7))
+ print("f7 = "); println(f7(4) == (4 * 7))
+ print("f8 = "); println(f8(4) == (4 / 7))
+ print("f9 = "); println(f9(4) == (4 % 7))
+
+ print("f10 = "); println(f10(4) == (4 | 7))
+ print("f11 = "); println(f11(false) == (false | true))
+ print("f12 = "); println(f12(4) == (4 ^ 7))
+ print("f13 = "); println(f13(false) == (false ^ true))
+ print("f14 = "); println(f14(4) == (4 & 7))
+ print("f15 = "); println(f15(false) == (false & true))
+ print("f16 = "); println(f16(false) == (false || true))
+ print("f17 = "); println(f17(false) == (false && true))
+
+ print("f18 = "); println(f18(4) == (4 << 7))
+ print("f19 = "); println(f19(4) == (4 >> 7))
+ print("f20 = "); println(f20(4) == (4 >>> 7))
+
+ print("f21 = "); println(f21(4.2) == (4.2.toByte))
+ print("f22 = "); println(f22(4.2) == (4.2.toShort))
+ print("f23 = "); println(f23(4.2) == (4.2.toChar))
+ print("f24 = "); println(f24(4.2) == (4.2.toInt))
+ print("f25 = "); println(f25(4.2) == (4.2.toLong))
+ print("f26 = "); println(f26(4.2) == (4.2.toFloat))
+ print("f27 = "); println(f27(4.2) == (4.2.toDouble))
+
+ print("f28 = "); println(f28(4) == (4 == 7))
+ print("f29 = "); println(f29(4) == (4 != 7))
+ print("f30 = "); println(f30(false) == (false == true))
+ print("f31 = "); println(f31(false) == (false != true))
+
+ print("f32 = "); println(f32(4) == (4 < 7))
+ print("f33 = "); println(f33(4) == (4 <= 7))
+ print("f34 = "); println(f34(4) == (4 >= 7))
+ print("f35 = "); println(f35(4) == (4 > 7))
+
+ println("ok")
+
+} \ No newline at end of file