@@ -866,6 +866,30 @@ object RefChecks {
866866 }
867867 }
868868
869+ /** Check that we do not "override" anything with a private method
870+ * or something that becomes a private method. According to the Scala
871+ * modeling this is non-sensical since private members don't override.
872+ * But Java and the JVM disagree, if the private member is a method.
873+ * A test case is neg/i7926b.scala.
874+ * Note: The compiler could possibly silently rename the offending private
875+ * instead of flagging it as an error. But that might mean we see some
876+ * surprising names at runtime. E.g. in neg/i4564a.scala, a private
877+ * case class `apply` method would have to be renamed to something else.
878+ */
879+ def checkNoPrivateOverrides (tree : Tree )(using ctx : Context ): Unit =
880+ val sym = tree.symbol
881+ if sym.owner.isClass
882+ && sym.is(Private )
883+ && (sym.isOneOf(MethodOrLazyOrMutable ) || ! sym.is(Local )) // in these cases we'll produce a getter later
884+ && ! sym.isConstructor
885+ then
886+ val cls = sym.owner.asClass
887+ for bc <- cls.baseClasses.tail do
888+ val other = sym.matchingDecl(bc, cls.thisType)
889+ if other.exists then
890+ ctx.error(i " private $sym cannot override ${other.showLocated}" , sym.sourcePos)
891+ end checkNoPrivateOverrides
892+
869893 type LevelAndIndex = immutable.Map [Symbol , (LevelInfo , Int )]
870894
871895 class OptLevelInfo {
@@ -957,6 +981,7 @@ class RefChecks extends MiniPhase { thisPhase =>
957981 else ctx
958982
959983 override def transformValDef (tree : ValDef )(implicit ctx : Context ): ValDef = {
984+ checkNoPrivateOverrides(tree)
960985 checkDeprecatedOvers(tree)
961986 val sym = tree.symbol
962987 if (sym.exists && sym.owner.isTerm) {
@@ -976,6 +1001,7 @@ class RefChecks extends MiniPhase { thisPhase =>
9761001 }
9771002
9781003 override def transformDefDef (tree : DefDef )(implicit ctx : Context ): DefDef = {
1004+ checkNoPrivateOverrides(tree)
9791005 checkDeprecatedOvers(tree)
9801006 tree
9811007 }
0 commit comments