summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala12
-rw-r--r--test/files/neg/override-object-no.check10
-rw-r--r--test/files/neg/override-object-no.scala11
3 files changed, 27 insertions, 6 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 3860cc252d..cafea55b4d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -88,17 +88,19 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
if (sym.hasAccessBoundary) "" + sym.privateWithin.name else ""
)
- def overridesTypeInPrefix(tp1: Type, tp2: Type, prefix: Type): Boolean = (tp1.dealiasWiden, tp2.dealiasWiden) match {
+ def overridesTypeInPrefix(tp1: Type, tp2: Type, prefix: Type, isModuleOverride: Boolean): Boolean = (tp1.dealiasWiden, tp2.dealiasWiden) match {
case (MethodType(List(), rtp1), NullaryMethodType(rtp2)) =>
rtp1 <:< rtp2
case (NullaryMethodType(rtp1), MethodType(List(), rtp2)) =>
rtp1 <:< rtp2
case (TypeRef(_, sym, _), _) if sym.isModuleClass =>
- overridesTypeInPrefix(NullaryMethodType(tp1), tp2, prefix)
+ overridesTypeInPrefix(NullaryMethodType(tp1), tp2, prefix, isModuleOverride)
case _ =>
def classBoundAsSeen(tp: Type) = tp.typeSymbol.classBound.asSeenFrom(prefix, tp.typeSymbol.owner)
-
- (tp1 <:< tp2) || ( // object override check
+ (tp1 <:< tp2) || isModuleOverride && (
+ // Object override check. This requires that both the overridden and the overriding member are object
+ // definitions. The overriding module type is allowed to replace the original one with the same name
+ // as long as it conform to the original non-singleton type.
tp1.typeSymbol.isModuleClass && tp2.typeSymbol.isModuleClass && {
val cb1 = classBoundAsSeen(tp1)
val cb2 = classBoundAsSeen(tp2)
@@ -520,7 +522,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
}
def checkOverrideTerm() {
other.cookJavaRawInfo() // #2454
- if (!overridesTypeInPrefix(lowType, highType, rootType)) { // 8
+ if (!overridesTypeInPrefix(lowType, highType, rootType, low.isModuleOrModuleClass && high.isModuleOrModuleClass)) { // 8
overrideTypeError()
explainTypes(lowType, highType)
}
diff --git a/test/files/neg/override-object-no.check b/test/files/neg/override-object-no.check
index 9cfda80fc3..972a719b3b 100644
--- a/test/files/neg/override-object-no.check
+++ b/test/files/neg/override-object-no.check
@@ -20,4 +20,12 @@ an overriding object must conform to the overridden object's class bound;
required: case2.Bar[Traversable[String]]
override object A extends Bar[List[String]] // err
^
-four errors found
+override-object-no.scala:52: error: overriding method x in trait A of type => SI9574.Foo.type;
+ method x has incompatible type
+ trait B extends A { def x: Bar.type } // should not compile (SI-9574)
+ ^
+override-object-no.scala:53: error: overriding method x in trait A of type => SI9574.Foo.type;
+ object x has incompatible type
+ trait C extends A { override object x }
+ ^
+6 errors found
diff --git a/test/files/neg/override-object-no.scala b/test/files/neg/override-object-no.scala
index 745cdb2332..517408886d 100644
--- a/test/files/neg/override-object-no.scala
+++ b/test/files/neg/override-object-no.scala
@@ -43,3 +43,14 @@ package case2 {
override object A extends Bar[List[String]] // err
}
}
+
+// Both overridden and overriding members must be objects, not vals with a module type
+object SI9574 {
+ object Foo
+ object Bar
+ trait A { def x: Foo.type }
+ trait B extends A { def x: Bar.type } // should not compile (SI-9574)
+ trait C extends A { override object x }
+ trait D { object x; def y = x }
+ trait E extends D { override val x: super.x.type = y } // OK but doesn't need object subtyping exception
+}