summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@typesafe.com>2012-11-01 12:08:11 -0700
committerAdriaan Moors <adriaan.moors@typesafe.com>2012-11-01 12:08:11 -0700
commit59149579aec4b3d26a4cb849d80535a36b90ad30 (patch)
tree89e66e34d5420edeb480a382e777dd9b78c317a0
parentb7d78d2d6e1d970e7ef2c02a3ad42b4356672971 (diff)
parentc3e2a81b38133f2b997e56ccd85d9bea38896a6b (diff)
downloadscala-59149579aec4b3d26a4cb849d80535a36b90ad30.tar.gz
scala-59149579aec4b3d26a4cb849d80535a36b90ad30.tar.bz2
scala-59149579aec4b3d26a4cb849d80535a36b90ad30.zip
Merge pull request #1526 from paulp/value-classes/6534-equals
New take on SI-6534, value classes.
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala19
-rw-r--r--test/files/neg/t6534.check17
-rw-r--r--test/files/neg/t6534.flags1
-rw-r--r--test/files/neg/t6534.scala10
-rw-r--r--test/files/run/t6534.scala14
5 files changed, 60 insertions, 1 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index 001acc7a80..6afc823376 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -326,7 +326,24 @@ trait SyntheticMethods extends ast.TreeDSL {
else Nil
)
- def impls = for ((m, impl) <- methods ; if !hasOverridingImplementation(m)) yield impl()
+ /** Always generate overrides for equals and hashCode in value classes,
+ * so they can appear in universal traits without breaking value semantics.
+ */
+ def impls = {
+ def shouldGenerate(m: Symbol) = {
+ !hasOverridingImplementation(m) || {
+ clazz.isDerivedValueClass && (m == Any_hashCode || m == Any_equals) && {
+ if (settings.lint.value) {
+ (clazz.info nonPrivateMember m.name) filter (m => (m.owner != AnyClass) && (m.owner != clazz) && !m.isDeferred) andAlso { m =>
+ currentUnit.warning(clazz.pos, s"Implementation of ${m.name} inherited from ${m.owner} overridden in $clazz to enforce value class semantics")
+ }
+ }
+ true
+ }
+ }
+ }
+ for ((m, impl) <- methods ; if shouldGenerate(m)) yield impl()
+ }
def extras = (
if (needsReadResolve) {
// Aha, I finally decoded the original comment.
diff --git a/test/files/neg/t6534.check b/test/files/neg/t6534.check
new file mode 100644
index 0000000000..52e70cfa8a
--- /dev/null
+++ b/test/files/neg/t6534.check
@@ -0,0 +1,17 @@
+t6534.scala:4: warning: Implementation of equals inherited from trait Foo overridden in class Bippy1 to enforce value class semantics
+class Bippy1(val x: Int) extends AnyVal with Foo { } // warn
+ ^
+t6534.scala:5: warning: Implementation of hashCode inherited from trait Ding overridden in class Bippy2 to enforce value class semantics
+class Bippy2(val x: Int) extends AnyVal with Ding { } // warn
+ ^
+t6534.scala:6: error: redefinition of equals method. See SIP-15, criterion 4. is not allowed in value class
+class Bippy3(val x: Int) extends AnyVal { override def equals(x: Any) = false } // error
+ ^
+t6534.scala:7: error: redefinition of hashCode method. See SIP-15, criterion 4. is not allowed in value class
+class Bippy4(val x: Int) extends AnyVal { override def hashCode = -1 } // error
+ ^
+t6534.scala:9: error: redefinition of equals method. See SIP-15, criterion 4. is not allowed in value class
+case class Bippy6(val x: Int) extends AnyVal { override def productPrefix = "Dingo" ; override def equals(x: Any) = false } // error
+ ^
+two warnings found
+three errors found
diff --git a/test/files/neg/t6534.flags b/test/files/neg/t6534.flags
new file mode 100644
index 0000000000..1008b0a70c
--- /dev/null
+++ b/test/files/neg/t6534.flags
@@ -0,0 +1 @@
+-Xlint
diff --git a/test/files/neg/t6534.scala b/test/files/neg/t6534.scala
new file mode 100644
index 0000000000..de588b69a7
--- /dev/null
+++ b/test/files/neg/t6534.scala
@@ -0,0 +1,10 @@
+trait Foo extends Any { override def equals(x: Any) = false }
+trait Ding extends Any { override def hashCode = -1 }
+
+class Bippy1(val x: Int) extends AnyVal with Foo { } // warn
+class Bippy2(val x: Int) extends AnyVal with Ding { } // warn
+class Bippy3(val x: Int) extends AnyVal { override def equals(x: Any) = false } // error
+class Bippy4(val x: Int) extends AnyVal { override def hashCode = -1 } // error
+case class Bippy5(val x: Int) extends AnyVal { override def productPrefix = "Dingo" } // nothing
+case class Bippy6(val x: Int) extends AnyVal { override def productPrefix = "Dingo" ; override def equals(x: Any) = false } // error
+
diff --git a/test/files/run/t6534.scala b/test/files/run/t6534.scala
new file mode 100644
index 0000000000..33df97e41e
--- /dev/null
+++ b/test/files/run/t6534.scala
@@ -0,0 +1,14 @@
+trait Foo extends Any { override def equals(x: Any) = false }
+trait Ding extends Any { override def hashCode = -1 }
+
+class Bippy1(val x: Int) extends AnyVal with Foo { } // warn
+class Bippy2(val x: Int) extends AnyVal with Ding { } // warn
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ val b1 = new Bippy1(71)
+ val b2 = new Bippy2(71)
+ assert(b1 == b1 && b1.## == b1.x.##, ((b1, b1.##)))
+ assert(b2 == b2 && b2.## == b2.x.##, ((b2, b2.##)))
+ }
+}