summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala43
-rw-r--r--src/library/scala/Array.scala10
-rw-r--r--src/library/scala/Console.scala5
-rw-r--r--src/library/scala/Predef.scala23
-rw-r--r--src/library/scala/runtime/BoxedArray.scala2
-rw-r--r--test/files/neg/checksensible.check28
-rw-r--r--test/files/neg/checksensible.scala26
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
+ }
+}