From a7276d5976f57d4f182a55f92693de97acf1de64 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 24 Oct 2012 13:23:54 -0700 Subject: New take on SI-6534, value classes. Don't prohibit equals and hashCode in universal traits; instead, always override them in value classes. --- test/files/neg/t6534.check | 14 ++++++++++++++ test/files/neg/t6534.flags | 1 + test/files/neg/t6534.scala | 7 +++++++ 3 files changed, 22 insertions(+) create mode 100644 test/files/neg/t6534.check create mode 100644 test/files/neg/t6534.flags create mode 100644 test/files/neg/t6534.scala (limited to 'test/files/neg') diff --git a/test/files/neg/t6534.check b/test/files/neg/t6534.check new file mode 100644 index 0000000000..bd7dc4b71c --- /dev/null +++ b/test/files/neg/t6534.check @@ -0,0 +1,14 @@ +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 + ^ +two warnings found +two 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..a193179399 --- /dev/null +++ b/test/files/neg/t6534.scala @@ -0,0 +1,7 @@ +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 -- cgit v1.2.3 From c3e2a81b38133f2b997e56ccd85d9bea38896a6b Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 30 Oct 2012 07:43:03 -0700 Subject: Modification to SI-6534 patch. Only exclude hashCode and equals from being overridden in value classes, not other synthetics which may turn up such as case class methods. --- .../tools/nsc/typechecker/SyntheticMethods.scala | 20 +++++++++++--------- test/files/neg/t6534.check | 5 ++++- test/files/neg/t6534.scala | 3 +++ 3 files changed, 18 insertions(+), 10 deletions(-) (limited to 'test/files/neg') diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 0fda025972..903b5904d3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -310,17 +310,19 @@ trait SyntheticMethods extends ast.TreeDSL { * so they can appear in universal traits without breaking value semantics. */ def impls = { - if (clazz.isDerivedValueClass) - for ((m, impl) <- methods) yield { - 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") + 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") + } } - - impl() + true + } } - else - for ((m, impl) <- methods ; if !hasOverridingImplementation(m)) yield impl() + } + for ((m, impl) <- methods ; if shouldGenerate(m)) yield impl() } def extras = ( if (needsReadResolve) { diff --git a/test/files/neg/t6534.check b/test/files/neg/t6534.check index bd7dc4b71c..52e70cfa8a 100644 --- a/test/files/neg/t6534.check +++ b/test/files/neg/t6534.check @@ -10,5 +10,8 @@ class Bippy3(val x: Int) extends AnyVal { override def equals(x: Any) = false } 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 -two errors found +three errors found diff --git a/test/files/neg/t6534.scala b/test/files/neg/t6534.scala index a193179399..de588b69a7 100644 --- a/test/files/neg/t6534.scala +++ b/test/files/neg/t6534.scala @@ -5,3 +5,6 @@ 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 + -- cgit v1.2.3 From 1e2328ea6a8b592b5a2abe3557dc633e96f688f2 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 31 Oct 2012 14:08:29 -0700 Subject: Fix for SI-6597, implicit case class crasher. It seems to me like every call to scope.lookup in the compiler is a latent bug. If a symbol is overloaded, you get one at random. (See the FIXME comment in f5c336d5660 for more on this.) --- src/compiler/scala/tools/nsc/typechecker/Namers.scala | 2 +- test/files/neg/t6597.check | 4 ++++ test/files/neg/t6597.scala | 5 +++++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 test/files/neg/t6597.check create mode 100644 test/files/neg/t6597.scala (limited to 'test/files/neg') diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 9e9a22d4d1..e1afe153ad 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -398,7 +398,7 @@ trait Namers extends MethodSynthesis { * a module definition or a class definition. */ def enterModuleSymbol(tree : ModuleDef): Symbol = { - var m: Symbol = context.scope.lookup(tree.name) + var m: Symbol = context.scope lookupAll tree.name find (_.isModule) getOrElse NoSymbol val moduleFlags = tree.mods.flags | MODULE if (m.isModule && !m.isPackage && inCurrentScope(m) && (currentRun.canRedefine(m) || m.isSynthetic)) { updatePosFlags(m, tree.pos, moduleFlags) diff --git a/test/files/neg/t6597.check b/test/files/neg/t6597.check new file mode 100644 index 0000000000..1d52519d1d --- /dev/null +++ b/test/files/neg/t6597.check @@ -0,0 +1,4 @@ +t6597.scala:3: error: illegal combination of modifiers: implicit and case for: class Quux + implicit case class Quux(value: Int) extends AnyVal with T + ^ +one error found diff --git a/test/files/neg/t6597.scala b/test/files/neg/t6597.scala new file mode 100644 index 0000000000..dde53bcc89 --- /dev/null +++ b/test/files/neg/t6597.scala @@ -0,0 +1,5 @@ +object Test { + trait T extends Any + implicit case class Quux(value: Int) extends AnyVal with T + object Quux +} -- cgit v1.2.3