summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2012-05-09 15:01:26 -0700
committerPaul Phillips <paulp@improving.org>2012-05-09 16:32:51 -0700
commit0e197e89ac96ec0dd8b136de8e07ad2e15f94371 (patch)
tree77bb056d6c7d2c48f8b5ff9102c60a9db6862277 /src/compiler
parent09f380dbda56abdfbdda0cab51bc7187eb70b516 (diff)
downloadscala-0e197e89ac96ec0dd8b136de8e07ad2e15f94371.tar.gz
scala-0e197e89ac96ec0dd8b136de8e07ad2e15f94371.tar.bz2
scala-0e197e89ac96ec0dd8b136de8e07ad2e15f94371.zip
Custom hashCode methods for case classes.
No boxing, no MODULE$ indirection.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/reflect/internal/Definitions.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala35
2 files changed, 35 insertions, 1 deletions
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala
index 1c3e11b040..edafde1346 100644
--- a/src/compiler/scala/reflect/internal/Definitions.scala
+++ b/src/compiler/scala/reflect/internal/Definitions.scala
@@ -896,6 +896,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
// boxed classes
lazy val ObjectRefClass = requiredClass[scala.runtime.ObjectRef[_]]
lazy val VolatileObjectRefClass = requiredClass[scala.runtime.VolatileObjectRef[_]]
+ lazy val RuntimeStaticsModule = getRequiredModule("scala.runtime.Statics")
lazy val BoxesRunTimeModule = getRequiredModule("scala.runtime.BoxesRunTime")
lazy val BoxesRunTimeClass = BoxesRunTimeModule.moduleClass
lazy val BoxedNumberClass = getClass(sn.BoxedNumber)
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index 57e82ed706..484c8beb1b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -89,6 +89,11 @@ trait SyntheticMethods extends ast.TreeDSL {
def forwardToRuntime(method: Symbol): Tree =
forwardMethod(method, getMember(ScalaRunTimeModule, method.name prepend "_"))(mkThis :: _)
+ def callStaticsMethod(name: String)(args: Tree*): Tree = {
+ val method = termMember(RuntimeStaticsModule, name)
+ Apply(gen.mkAttributedRef(method), args.toList)
+ }
+
// Any member, including private
def hasConcreteImpl(name: Name) =
clazz.info.member(name).alternatives exists (m => !m.isDeferred && !m.isSynthetic)
@@ -222,13 +227,41 @@ trait SyntheticMethods extends ast.TreeDSL {
)
}
+ def hashcodeImplementation(sym: Symbol): Tree = {
+ sym.tpe.finalResultType.typeSymbol match {
+ case UnitClass | NullClass => Literal(Constant(0))
+ case BooleanClass => If(Ident(sym), Literal(Constant(1231)), Literal(Constant(1237)))
+ case IntClass | ShortClass | ByteClass | CharClass => Ident(sym)
+ case LongClass => callStaticsMethod("longHash")(Ident(sym))
+ case DoubleClass => callStaticsMethod("doubleHash")(Ident(sym))
+ case FloatClass => callStaticsMethod("floatHash")(Ident(sym))
+ case _ => callStaticsMethod("anyHash")(Ident(sym))
+ }
+ }
+
+ def specializedHashcode = {
+ createMethod(nme.hashCode_, Nil, IntClass.tpe) { m =>
+ val accumulator = m.newVariable(newTermName("acc"), m.pos, SYNTHETIC) setInfo IntClass.tpe
+ val valdef = ValDef(accumulator, Literal(Constant(0xcafebabe)))
+ val mixes = accessors map (acc =>
+ Assign(
+ Ident(accumulator),
+ callStaticsMethod("mix")(Ident(accumulator), hashcodeImplementation(acc))
+ )
+ )
+ val finish = callStaticsMethod("finalizeHash")(Ident(accumulator), Literal(Constant(arity)))
+
+ Block(valdef :: mixes, finish)
+ }
+ }
+
def valueClassMethods = List(
Any_hashCode -> (() => hashCodeDerivedValueClassMethod),
Any_equals -> (() => equalsDerivedValueClassMethod)
)
def caseClassMethods = productMethods ++ productNMethods ++ Seq(
- Object_hashCode -> (() => forwardToRuntime(Object_hashCode)),
+ Object_hashCode -> (() => specializedHashcode),
Object_toString -> (() => forwardToRuntime(Object_toString)),
Object_equals -> (() => equalsCaseClassMethod)
)