From 603c3dae0f74ccb9d9b34c9c004713ca3d0e8847 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sun, 6 Mar 2011 21:33:18 +0000 Subject: And extempore's original plan carries the day: ... And extempore's original plan carries the day: null.## no longer throws an NPE. Took advantage of feature to simplify a bunch of sharp-sharp calculations. Closes #4311, no review. --- src/compiler/scala/tools/nsc/transform/Erasure.scala | 9 ++++----- src/library/scala/collection/immutable/HashMap.scala | 2 +- src/library/scala/collection/immutable/HashSet.scala | 2 +- src/library/scala/collection/mutable/HashTable.scala | 2 +- src/library/scala/reflect/generic/Constants.scala | 3 +-- src/library/scala/runtime/ScalaRunTime.scala | 5 +++-- src/library/scala/xml/Equality.scala | 7 +------ src/library/scala/xml/Utility.scala | 2 +- src/swing/scala/swing/Publisher.scala | 6 +++--- test/files/run/null-hash.scala | 15 +++++++++++++++ 10 files changed, 31 insertions(+), 22 deletions(-) create mode 100644 test/files/run/null-hash.scala diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index dad422a4a9..a2ab678e36 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -908,15 +908,14 @@ abstract class Erasure extends AddInterfaces SelectFromArray(qual, name, erasure(qual.tpe)).copyAttrs(fn), args) - case Apply(fn @ Select(qual, _), Nil) if (fn.symbol == Any_## || fn.symbol == Object_##) => + case Apply(fn @ Select(qual, _), Nil) if fn.symbol == Any_## || fn.symbol == Object_## => // This is unattractive, but without it we crash here on ().## because after // erasure the ScalaRunTime.hash overload goes from Unit => Int to BoxedUnit => Int. // This must be because some earlier transformation is being skipped on ##, but so - // far I don't know what. We also crash on null.## but unless we want to implement - // my good idea that null.## works (like null == "abc" works) we have to NPE. + // far I don't know what. For null we now define null.## == 0. val arg = qual.tpe.typeSymbolDirect match { - case UnitClass => BLOCK(qual, REF(BoxedUnit_UNIT)) // ({ expr; UNIT }).## - case NullClass => Typed(qual, TypeTree(ObjectClass.tpe)) // (null: Object).## + case UnitClass => BLOCK(qual, REF(BoxedUnit_UNIT)) // ({ expr; UNIT }).## + case NullClass => LIT(0) // (null: Object).## case _ => qual } Apply(gen.mkAttributedRef(scalaRuntimeHash), List(arg)) diff --git a/src/library/scala/collection/immutable/HashMap.scala b/src/library/scala/collection/immutable/HashMap.scala index e0f15f67da..d44791c2eb 100644 --- a/src/library/scala/collection/immutable/HashMap.scala +++ b/src/library/scala/collection/immutable/HashMap.scala @@ -59,7 +59,7 @@ class HashMap[A, +B] extends Map[A,B] with MapLike[A, B, HashMap[A, B]] with Par def - (key: A): HashMap[A, B] = removed0(key, computeHash(key), 0) - protected def elemHashCode(key: A) = if (key == null) 0 else key.## + protected def elemHashCode(key: A) = key.## protected final def improve(hcode: Int) = { var h: Int = hcode + ~(hcode << 9) diff --git a/src/library/scala/collection/immutable/HashSet.scala b/src/library/scala/collection/immutable/HashSet.scala index c47186b27b..7d31f20e14 100644 --- a/src/library/scala/collection/immutable/HashSet.scala +++ b/src/library/scala/collection/immutable/HashSet.scala @@ -60,7 +60,7 @@ class HashSet[A] extends Set[A] def par = ParHashSet.fromTrie(this) - protected def elemHashCode(key: A) = if (key == null) 0 else key.## + protected def elemHashCode(key: A) = key.## protected final def improve(hcode: Int) = { var h: Int = hcode + ~(hcode << 9) diff --git a/src/library/scala/collection/mutable/HashTable.scala b/src/library/scala/collection/mutable/HashTable.scala index 00c7588967..420670d755 100644 --- a/src/library/scala/collection/mutable/HashTable.scala +++ b/src/library/scala/collection/mutable/HashTable.scala @@ -363,7 +363,7 @@ private[collection] object HashTable { // so that: protected final def sizeMapBucketSize = 1 << sizeMapBucketBitSize - protected def elemHashCode(key: KeyType) = if (key == null) 0 else key.## + protected def elemHashCode(key: KeyType) = key.## protected final def improve(hcode: Int) = { /* Murmur hash diff --git a/src/library/scala/reflect/generic/Constants.scala b/src/library/scala/reflect/generic/Constants.scala index 861a4a9eab..88a213481d 100755 --- a/src/library/scala/reflect/generic/Constants.scala +++ b/src/library/scala/reflect/generic/Constants.scala @@ -233,7 +233,6 @@ trait Constants { def typeValue: Type = value.asInstanceOf[Type] def symbolValue: Symbol = value.asInstanceOf[Symbol] - override def hashCode: Int = - if (value == null) 0 else value.## * 41 + 17 + override def hashCode: Int = value.## * 41 + 17 } } diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala index 548875bb6c..8ca461d799 100644 --- a/src/library/scala/runtime/ScalaRunTime.scala +++ b/src/library/scala/runtime/ScalaRunTime.scala @@ -167,7 +167,7 @@ object ScalaRunTime { var i = 0 while (i < arr) { val elem = x.productElement(i) - h = extendHash(h, if (elem == null) 0 else elem.##, c, k) + h = extendHash(h, elem.##, c, k) c = nextMagicA(c) k = nextMagicB(k) i += 1 @@ -195,7 +195,8 @@ object ScalaRunTime { // must not call ## themselves. @inline def hash(x: Any): Int = - if (x.isInstanceOf[java.lang.Number]) BoxesRunTime.hashFromNumber(x.asInstanceOf[java.lang.Number]) + if (x == null) 0 + else if (x.isInstanceOf[java.lang.Number]) BoxesRunTime.hashFromNumber(x.asInstanceOf[java.lang.Number]) else x.hashCode @inline def hash(dv: Double): Int = { diff --git a/src/library/scala/xml/Equality.scala b/src/library/scala/xml/Equality.scala index 22c1552bbb..1e7cd482ed 100644 --- a/src/library/scala/xml/Equality.scala +++ b/src/library/scala/xml/Equality.scala @@ -74,8 +74,6 @@ trait Equality extends scala.Equals { def strict_==(other: Equality): Boolean def strict_!=(other: Equality) = !strict_==(other) - private def hashOf(x: Any) = if (x == null) 1 else x.## - /** We insist we're only equal to other xml.Equality implementors, * which heads off a lot of inconsistency up front. */ @@ -90,10 +88,7 @@ trait Equality extends scala.Equals { * are final since clearly individual classes cannot be trusted * to maintain a semblance of order. */ - override def hashCode() = basisForHashCode match { - case Nil => 0 - case x :: xs => hashOf(x) * 41 + (xs map hashOf).foldLeft(0)(_ * 7 + _) - } + override def hashCode() = basisForHashCode.## override def equals(other: Any) = doComparison(other, false) final def xml_==(other: Any) = doComparison(other, true) final def xml_!=(other: Any) = !xml_==(other) diff --git a/src/library/scala/xml/Utility.scala b/src/library/scala/xml/Utility.scala index 995563e9ac..3f1c5fb81b 100644 --- a/src/library/scala/xml/Utility.scala +++ b/src/library/scala/xml/Utility.scala @@ -263,7 +263,7 @@ object Utility extends AnyRef with parsing.TokenTests * @param children */ def hashCode(pre: String, label: String, attribHashCode: Int, scpeHash: Int, children: Seq[Node]) = { - val h = new util.MurmurHash[Node]( if (pre ne null) pre.## else 0 ) + val h = new util.MurmurHash[Node](pre.##) h.append(label.##) h.append(attribHashCode) h.append(scpeHash) diff --git a/src/swing/scala/swing/Publisher.scala b/src/swing/scala/swing/Publisher.scala index 6042dce943..ebab00463a 100644 --- a/src/swing/scala/swing/Publisher.scala +++ b/src/swing/scala/swing/Publisher.scala @@ -78,9 +78,9 @@ import scala.ref._ private[swing] trait SingleRefCollection[+A <: AnyRef] extends Iterable[A] { self => trait Ref[+A <: AnyRef] extends Reference[A] { - override def hashCode() = { - val v = get - if (v == None) 0 else v.get.## + override def hashCode() = get match { + case Some(x) => x.## + case _ => 0 } override def equals(that: Any) = that match { case that: ReferenceWrapper[_] => diff --git a/test/files/run/null-hash.scala b/test/files/run/null-hash.scala new file mode 100644 index 0000000000..9b1f28b083 --- /dev/null +++ b/test/files/run/null-hash.scala @@ -0,0 +1,15 @@ +object Test { + def f1 = List(5, 10, null: String).## + def f2(x: Any) = x.## + def f3 = ((55, "abc", null: List[Int])).## + + def main(args: Array[String]): Unit = { + f1 + f2(null) + f2(null: String) + f3 + null.## + (null: Any).## + (null: String).## + } +} -- cgit v1.2.3