diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 12 | ||||
-rw-r--r-- | test/files/neg/override-object-no.check | 10 | ||||
-rw-r--r-- | test/files/neg/override-object-no.scala | 11 |
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 +} |