diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 43 | ||||
-rw-r--r-- | src/library/scala/Array.scala | 10 | ||||
-rw-r--r-- | src/library/scala/Console.scala | 5 | ||||
-rw-r--r-- | src/library/scala/Predef.scala | 23 | ||||
-rw-r--r-- | src/library/scala/runtime/BoxedArray.scala | 2 | ||||
-rw-r--r-- | test/files/neg/checksensible.check | 28 | ||||
-rw-r--r-- | test/files/neg/checksensible.scala | 26 |
7 files changed, 135 insertions, 2 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 4f1a9388b7..a5f6f785b9 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -437,6 +437,46 @@ abstract class RefChecks extends InfoTransform { } } +// Comparison checking ------------------------------------------------------- + + def checkSensible(pos: int, fn: Tree, args: List[Tree]) = fn match { + case Select(qual, name) if (args.length == 1) => + def isNew = qual match { + case Function(_, _) + | Apply(Select(New(_), nme.CONSTRUCTOR), _) => true + case _ => false + } + name match { + case nme.EQ | nme.NE | nme.LT | nme.GT | nme.LE | nme.GE => + val formal = fn.tpe.paramTypes.head.widen.symbol + val actual = args.head.tpe.widen.symbol + val receiver = qual.tpe.widen.symbol + def nonSensibleWarning(what: String, alwaysEqual: boolean) = + unit.warning(pos, "comparing "+what+" using `"+name.decode+"' will always yield "+ + (alwaysEqual == (name == nme.EQ || name == nme.LE || name == nme.GE))) + def nonSensible(alwaysEqual: boolean) = + nonSensibleWarning("values of types "+qual.tpe.widen+" and "+args.head.tpe.widen, + alwaysEqual) + if (formal == UnitClass && actual == UnitClass) + nonSensible(true) + else if ((receiver == BooleanClass || receiver == UnitClass) && + !(receiver isSubClass actual)) + nonSensible(false) + else if (isNumericValueClass(receiver) && + !isNumericValueClass(actual) && + !(receiver isSubClass actual)) + nonSensible(false) + else if ((receiver hasFlag FINAL) && + (fn.symbol == Object_== || fn.symbol == Object_!=) && + !(receiver isSubClass actual)) + nonSensible(false) + else if (isNew && (fn.symbol == Object_== || fn.symbol == Object_!=)) + nonSensibleWarning("a fresh object", false) + case _ => + } + case _ => + } + // Transformation ------------------------------------------------------------ /* Convert a reference to a case factory of type `tpe' to a new of the class it produces. */ @@ -628,6 +668,9 @@ abstract class RefChecks extends InfoTransform { isIrrefutable(pat1, tpt.tpe)) => result = qual + case Apply(fn, args) => + checkSensible(tree.pos, fn, args) + case If(cond, thenpart, elsepart) => cond.tpe match { case ConstantType(value) => diff --git a/src/library/scala/Array.scala b/src/library/scala/Array.scala index 34b64358f5..44da0b11eb 100644 --- a/src/library/scala/Array.scala +++ b/src/library/scala/Array.scala @@ -13,7 +13,7 @@ package scala import compat.Platform.arraycopy -/** This object ... +/** This object contains utility methods operating on arrays. * * @author Martin Odersky * @version 1.0 @@ -182,7 +182,8 @@ object Array { if (x.isInstanceOf[Array[A]]) Some(x.asInstanceOf[Array[A]]) else None } -/** This class represents polymorphic arrays. It is never instantiated. +/** This class represents polymorphic arrays. <code>Array[T]</code> is Scala's representation + * for Java's <code>T[]</code>. * * @author Martin Odersky * @version 1.0 @@ -253,6 +254,11 @@ final class Array[A](_length: Int) extends Seq[A] { */ override def filter(p: A => Boolean): Array[A] = throw new Error() + /** Returns an array consisting of all elements of this array followed + * by all elements of the argument iterable. + */ + override def ++[B >: A](that: Iterable[B]): Array[B] = throw new Error() + /** Returns the array resulting from applying the given function <code>f</code> to each * element of this array. * diff --git a/src/library/scala/Console.scala b/src/library/scala/Console.scala index 4dfc1d90ad..b7f68c3588 100644 --- a/src/library/scala/Console.scala +++ b/src/library/scala/Console.scala @@ -16,6 +16,7 @@ import java.io.{OutputStream, PrintStream} import java.text.MessageFormat import scala.util.Fluid +import Predef._ /** The <code>Console</code> object implements functionality for @@ -236,6 +237,10 @@ object Console { */ def readInt(): Int = readLine().toInt + /** Read an int value from the terminal. + */ + def readLong(): Long = readLine().toLong + /** Read a float value from the terminal. */ def readFloat(): Float = readLine().toFloat diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala index 8b58cf6d7d..296792b4c3 100644 --- a/src/library/scala/Predef.scala +++ b/src/library/scala/Predef.scala @@ -128,6 +128,29 @@ object Predef { def Tuple[a1, a2, a3, a4, a5, a6, a7, a8](x1: a1, x2: a2, x3: a3, x4: a4, x5: a5, x6: a6, x7: a7, x8: a8) = Tuple8(x1, x2, x3, x4, x5, x6, x7, x8) def Tuple[a1, a2, a3, a4, a5, a6, a7, a8, a9](x1: a1, x2: a2, x3: a3, x4: a4, x5: a5, x6: a6, x7: a7, x8: a8, x9: a9) = Tuple9(x1, x2, x3, x4, x5, x6, x7, x8, x9) + // printing and reading ---------------------------------------------- + + def print(x: Any) = Console.print(x) + def println() = Console.println() + def println(x: Any) = Console.println(x) + def printf(text: String, xs: Any*) = Console.printf(text, xs: _*) + def format(text: String, xs: Any*) = Console.format(text, xs) + + def readLine(): String = Console.readLine() + def readLine(text: String, args: Any*) = Console.readLine(text, args) + def readBoolean() = Console.readBoolean() + def readByte() = Console.readByte() + def readShort() = Console.readShort() + def readChar() = Console.readChar() + def readInt() = Console.readInt() + def readLong() = Console.readLong() + def readFloat() = Console.readFloat() + def readDouble() = Console.readDouble() + def readf(format: String) = Console.readf(format) + def readf1(format: String) = Console.readf1(format) + def readf2(format: String) = Console.readf2(format) + def readf3(format: String) = Console.readf3(format) + // views ------------------------------------------------------------- implicit def identity[a](x: a): a = x diff --git a/src/library/scala/runtime/BoxedArray.scala b/src/library/scala/runtime/BoxedArray.scala index bc44e93a37..b065356c24 100644 --- a/src/library/scala/runtime/BoxedArray.scala +++ b/src/library/scala/runtime/BoxedArray.scala @@ -97,6 +97,8 @@ abstract class BoxedArray extends Seq[Any] { buf.toArray } + final override def ++[b >: Any](that: Iterable[b]): Array[b] = super.++(that).toArray + final def zip[b](that: Array[b]): Array[Tuple2[Any,b]] = { val len = length if(len != that.length) diff --git a/test/files/neg/checksensible.check b/test/files/neg/checksensible.check new file mode 100644 index 0000000000..a4cf1cfe41 --- /dev/null +++ b/test/files/neg/checksensible.check @@ -0,0 +1,28 @@ +checksensible.scala:4: warning: comparing values of types scala.Ordered[scala.Unit] and scala.Unit using `>' will always yield false + println((c = 1) > 0) + ^ +checksensible.scala:5: warning: comparing values of types scala.Ordered[scala.Unit] and scala.Unit using `<=' will always yield true + println((c = 1) <= 0) + ^ +checksensible.scala:6: warning: comparing values of types scala.Unit and scala.Int using `==' will always yield false + println((c = 1) == 0) + ^ +checksensible.scala:8: warning: comparing values of types scala.Int and java.lang.String using `==' will always yield false + println(1 == "abc") + ^ +checksensible.scala:9: warning: comparing values of types scala.Int and scala.Boolean using `!=' will always yield true + println(1 != true) + ^ +checksensible.scala:11: warning: comparing a fresh object using `==' will always yield false + println(((x: int) => x + 1) == null) + ^ +checksensible.scala:12: warning: comparing a fresh object using `==' will always yield false + println(new Object == new Object) + ^ +checksensible.scala:13: warning: comparing a fresh object using `!=' will always yield true + println(new Array(1) != new Array(1)) + ^ +checksensible.scala:20: warning: comparing values of types scala.Unit and scala.Int using `!=' will always yield true + while((c = in.read) != -1) { + ^ +9 warnings found diff --git a/test/files/neg/checksensible.scala b/test/files/neg/checksensible.scala new file mode 100644 index 0000000000..1a2c4425fd --- /dev/null +++ b/test/files/neg/checksensible.scala @@ -0,0 +1,26 @@ +import java.io._ +object Test { + var c = 0 + println((c = 1) > 0) + println((c = 1) <= 0) + println((c = 1) == 0) + + println(1 == "abc") + println(1 != true) + + println(((x: int) => x + 1) == null) + println(new Object == new Object) + println(new Array(1) != new Array(1)) + + def main(args: Array[String]) = { + val in = new FileInputStream(args(0)) + + var c = 0 + + while((c = in.read) != -1) { + Console.print(c.toChar) + } + + in.close + } +} |