From d0a36c66cb18d94d15d44e5a04ed91ab00a43418 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 18 Oct 2011 17:57:29 +0000 Subject: Fix for comparison warnings. true == new java.lang.Boolean(true) will in fact sometimes be true. Also fixes a bug caused by this change in r23627. - lazy val SerializableClass = getClass(sn.Serializable) + lazy val SerializableClass = getClass("scala.Serializable") It used to be java.io.Serializable. Hey, let's not change the meaning of existing symbols which are in active use. No review. --- .../scala/reflect/internal/Definitions.scala | 6 +-- .../scala/tools/nsc/typechecker/RefChecks.scala | 6 ++- test/files/neg/checksensible.check | 48 ++++++++++++---------- test/files/neg/checksensible.scala | 6 +++ 4 files changed, 40 insertions(+), 26 deletions(-) diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index 654639adae..4ee717ce75 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -784,12 +784,12 @@ trait Definitions extends reflect.api.StandardDefinitions { /** Is symbol a boxed value class, e.g. java.lang.Integer? */ def isBoxedValueClass(sym: Symbol) = boxedValueClassesSet(sym) - /** If symbol is a value class, return the value class, with the exception - * that BoxedUnit remains BoxedUnit. If not a value class, NoSymbol. + /** If symbol is a value class (boxed or not), return the unboxed + * value class. Otherwise, NoSymbol. */ def unboxedValueClass(sym: Symbol): Symbol = if (isValueClass(sym)) sym - else if (sym == BoxedUnitClass) sym + else if (sym == BoxedUnitClass) UnitClass else boxedClass.map(_.swap).getOrElse(sym, NoSymbol) /** Is type's symbol a numeric value class? */ diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index c9237627e7..a5053eb559 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1017,7 +1017,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R def typesString = normalizeAll(qual.tpe.widen)+" and "+normalizeAll(args.head.tpe.widen) /** Symbols which limit the warnings we can issue since they may be value types */ - val isMaybeValue = Set(AnyClass, AnyRefClass, AnyValClass, ObjectClass, ComparableClass, SerializableClass) + val isMaybeValue = Set(AnyClass, AnyRefClass, AnyValClass, ObjectClass, ComparableClass, JavaSerializableClass) // Whether def equals(other: Any) is overridden def isUsingDefaultEquals = { @@ -1035,6 +1035,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R def isBoolean(s: Symbol) = unboxedValueClass(s) == BooleanClass def isUnit(s: Symbol) = unboxedValueClass(s) == UnitClass def isNumeric(s: Symbol) = isNumericValueClass(unboxedValueClass(s)) || (s isSubClass ScalaNumberClass) + def isSpecial(s: Symbol) = isValueClass(unboxedValueClass(s)) || (s isSubClass ScalaNumberClass) || isMaybeValue(s) def possibleNumericCount = onSyms(_ filter (x => isNumeric(x) || isMaybeValue(x)) size) val nullCount = onSyms(_ filter (_ == NullClass) size) @@ -1088,7 +1089,8 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R } } - if (nullCount == 0 && possibleNumericCount < 2) { + // possibleNumericCount is insufficient or this will warn on e.g. Boolean == j.l.Boolean + if (nullCount == 0 && !(isSpecial(receiver) && isSpecial(actual))) { if (actual isSubClass receiver) () else if (receiver isSubClass actual) () // warn only if they have no common supertype below Object diff --git a/test/files/neg/checksensible.check b/test/files/neg/checksensible.check index c085aa2719..d45d16165f 100644 --- a/test/files/neg/checksensible.check +++ b/test/files/neg/checksensible.check @@ -34,64 +34,70 @@ checksensible.scala:32: error: String and Int are unrelated: they will most like checksensible.scala:33: error: Some[Int] and Int are unrelated: they will most likely never compare equal Some(1) == 1 // as above ^ -checksensible.scala:35: error: comparing a fresh object using `==' will always yield false +checksensible.scala:38: error: comparing a fresh object using `==' will always yield false new AnyRef == 1 ^ -checksensible.scala:38: error: comparing values of types Int and Boolean using `==' will always yield false +checksensible.scala:41: error: comparing values of types Int and Boolean using `==' will always yield false 1 == (new java.lang.Boolean(true)) ^ -checksensible.scala:40: error: comparing values of types Int and Boolean using `!=' will always yield true +checksensible.scala:43: error: comparing values of types Int and Boolean using `!=' will always yield true 1 != true ^ -checksensible.scala:41: error: comparing values of types Unit and Boolean using `==' will always yield false +checksensible.scala:44: error: comparing values of types Unit and Boolean using `==' will always yield false () == true ^ -checksensible.scala:42: error: comparing values of types Unit and Unit using `==' will always yield true +checksensible.scala:45: error: comparing values of types Unit and Unit using `==' will always yield true () == () ^ -checksensible.scala:43: error: comparing values of types Unit and Unit using `==' will always yield true +checksensible.scala:46: error: comparing values of types Unit and Unit using `==' will always yield true () == println ^ -checksensible.scala:45: error: comparing values of types Int and Unit using `!=' will always yield true +checksensible.scala:47: error: comparing values of types Unit and scala.runtime.BoxedUnit using `==' will always yield true + () == scala.runtime.BoxedUnit.UNIT // these should warn for always being true/false + ^ +checksensible.scala:48: error: comparing values of types scala.runtime.BoxedUnit and Unit using `!=' will always yield false + scala.runtime.BoxedUnit.UNIT != () + ^ +checksensible.scala:51: error: comparing values of types Int and Unit using `!=' will always yield true (1 != println) ^ -checksensible.scala:46: error: comparing values of types Int and Symbol using `!=' will always yield true +checksensible.scala:52: error: comparing values of types Int and Symbol using `!=' will always yield true (1 != 'sym) ^ -checksensible.scala:52: error: comparing a fresh object using `==' will always yield false +checksensible.scala:58: error: comparing a fresh object using `==' will always yield false ((x: Int) => x + 1) == null ^ -checksensible.scala:53: error: comparing a fresh object using `==' will always yield false +checksensible.scala:59: error: comparing a fresh object using `==' will always yield false Bep == ((_: Int) + 1) ^ -checksensible.scala:55: error: comparing a fresh object using `==' will always yield false +checksensible.scala:61: error: comparing a fresh object using `==' will always yield false new Object == new Object ^ -checksensible.scala:56: error: comparing a fresh object using `==' will always yield false +checksensible.scala:62: error: comparing a fresh object using `==' will always yield false new Object == "abc" ^ -checksensible.scala:57: error: comparing a fresh object using `!=' will always yield true +checksensible.scala:63: error: comparing a fresh object using `!=' will always yield true new Exception() != new Exception() ^ -checksensible.scala:60: error: comparing values of types Int and Null using `==' will always yield false +checksensible.scala:66: error: comparing values of types Int and Null using `==' will always yield false if (foo.length == null) "plante" else "plante pas" ^ -checksensible.scala:65: error: comparing values of types Bip and Bop using `==' will always yield false +checksensible.scala:71: error: comparing values of types Bip and Bop using `==' will always yield false (x1 == x2) ^ -checksensible.scala:75: error: comparing values of types EqEqRefTest.this.C3 and EqEqRefTest.this.Z1 using `==' will always yield false +checksensible.scala:81: error: comparing values of types EqEqRefTest.this.C3 and EqEqRefTest.this.Z1 using `==' will always yield false c3 == z1 ^ -checksensible.scala:76: error: comparing values of types EqEqRefTest.this.Z1 and EqEqRefTest.this.C3 using `==' will always yield false +checksensible.scala:82: error: comparing values of types EqEqRefTest.this.Z1 and EqEqRefTest.this.C3 using `==' will always yield false z1 == c3 ^ -checksensible.scala:77: error: comparing values of types EqEqRefTest.this.Z1 and EqEqRefTest.this.C3 using `!=' will always yield true +checksensible.scala:83: error: comparing values of types EqEqRefTest.this.Z1 and EqEqRefTest.this.C3 using `!=' will always yield true z1 != c3 ^ -checksensible.scala:78: error: comparing values of types EqEqRefTest.this.C3 and String using `!=' will always yield true +checksensible.scala:84: error: comparing values of types EqEqRefTest.this.C3 and String using `!=' will always yield true c3 != "abc" ^ -checksensible.scala:89: error: comparing values of types Unit and Int using `!=' will always yield true +checksensible.scala:95: error: comparing values of types Unit and Int using `!=' will always yield true while ((c = in.read) != -1) ^ -32 errors found +34 errors found diff --git a/test/files/neg/checksensible.scala b/test/files/neg/checksensible.scala index 77b5a93f74..b6083f75e4 100644 --- a/test/files/neg/checksensible.scala +++ b/test/files/neg/checksensible.scala @@ -32,6 +32,9 @@ class EqEqValTest { "abc" == 1 // warns because the lub of String and Int is Any Some(1) == 1 // as above + true == new java.lang.Boolean(true) // none of these should warn + new java.lang.Boolean(true) == true + new AnyRef == 1 1 == new AnyRef // doesn't warn because it could be... 1 == (new java.lang.Integer(1)) // ...something like this @@ -41,6 +44,9 @@ class EqEqValTest { () == true () == () () == println + () == scala.runtime.BoxedUnit.UNIT // these should warn for always being true/false + scala.runtime.BoxedUnit.UNIT != () + (scala.runtime.BoxedUnit.UNIT: java.io.Serializable) != () // shouldn't warn (1 != println) (1 != 'sym) -- cgit v1.2.3