diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 41f720a9ae67..2c458156d1a5 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -143,9 +143,10 @@ object RefChecks { * * 1.1. M must have the same or stronger access privileges as O. * 1.2. O must not be effectively final. - * 1.3. O is deferred, or M has `override` modifier. - * 1.4. If O is stable, then so is M. - * // @M: LIFTED 1.5. Neither M nor O are a parameterized type alias + * 1.3. If M or O are extension methods, they must both be extension methods. + * (Should be before the check for the need of `override` modifier.) + * 1.4. O is deferred, or M has `override` modifier. + * 1.5. If O is stable, then so is M. * 1.6. If O is a type alias, then M is an alias of O. * 1.7. If O is an abstract type then * 1.7.1 either M is an abstract type, and M's bounds are sharper than O's bounds. @@ -156,8 +157,7 @@ object RefChecks { * 1.8.1 M's type is a subtype of O's type, or * 1.8.2 M is of type []S, O is of type ()T and S <: T, or * 1.8.3 M is of type ()S, O is of type []T and S <: T, or - * 1.9.1 If M is erased, O is erased. If O is erased, M is erased or inline. - * 1.9.2 If M or O are extension methods, they must both be extension methods. + * 1.9. If M is erased, O is erased. If O is erased, M is erased or inline. * 1.10. If O is inline (and deferred, otherwise O would be final), M must be inline * 1.11. If O is a Scala-2 macro, M must be a Scala-2 macro. * 2. Check that only abstract classes have deferred members @@ -343,6 +343,10 @@ object RefChecks { overrideError("cannot be used here - classes can only override abstract types") else if (other.isEffectivelyFinal) // (1.2) overrideError(i"cannot override final member ${other.showLocated}") + else if (member.isAllOf(ExtensionMethod) && !other.isAllOf(ExtensionMethod)) // (1.3) + overrideError("is an extension method, cannot override a normal method") + else if (other.isAllOf(ExtensionMethod) && !member.isAllOf(ExtensionMethod)) // (1.3) + overrideError("is a normal method, cannot override an extension method") else if (!other.is(Deferred) && !other.name.is(DefaultGetterName) && !member.isAnyOverride) @@ -381,7 +385,7 @@ object RefChecks { intersectionIsEmpty(member.extendedOverriddenSymbols, other.extendedOverriddenSymbols)) overrideError("cannot override a concrete member without a third member that's overridden by both " + "(this rule is designed to prevent ``accidental overrides'')") - else if (other.isStableMember && !member.isStableMember) // (1.4) + else if (other.isStableMember && !member.isStableMember) // (1.5) overrideError("needs to be a stable, immutable value") else if (member.is(ModuleVal) && !other.isRealMethod && !other.isOneOf(Deferred | Lazy)) overrideError("may not override a concrete non-lazy value") @@ -390,14 +394,10 @@ object RefChecks { overrideError("may not override a non-lazy value") else if (other.is(Lazy) && !other.isRealMethod && !member.is(Lazy)) overrideError("must be declared lazy to override a lazy value") - else if (member.is(Erased) && !other.is(Erased)) // (1.9.1) + else if (member.is(Erased) && !other.is(Erased)) // (1.9) overrideError("is erased, cannot override non-erased member") - else if (other.is(Erased) && !member.isOneOf(Erased | Inline)) // (1.9.1) + else if (other.is(Erased) && !member.isOneOf(Erased | Inline)) // (1.9) overrideError("is not erased, cannot override erased member") - else if (member.isAllOf(ExtensionMethod) && !other.isAllOf(ExtensionMethod)) // (1.9.2) - overrideError("is an extension method, cannot override a normal method") - else if (other.isAllOf(ExtensionMethod) && !member.isAllOf(ExtensionMethod)) // (1.9.2) - overrideError("is a normal method, cannot override an extension method") else if other.is(Inline) && !member.is(Inline) then // (1.10) overrideError("is not inline, cannot implement an inline method") else if (other.isScala2Macro && !member.isScala2Macro) // (1.11) diff --git a/tests/neg/override-extension_normal-methods.check b/tests/neg/override-extension_normal-methods.check new file mode 100644 index 000000000000..fdd94fe558ee --- /dev/null +++ b/tests/neg/override-extension_normal-methods.check @@ -0,0 +1,10 @@ +-- Error: tests/neg/override-extension_normal-methods.scala:6:6 -------------------------------------------------------- +6 | def m[T](x: T): String = "normal method" // error: normal method, cannot override an extension method. Also needs `override' modifier (but this error should be obfuscated). + | ^ + | error overriding method m in trait A of type [T](t: T): String; + | method m of type [T](x: T): String is a normal method, cannot override an extension method +-- Error: tests/neg/override-extension_normal-methods.scala:14:6 ------------------------------------------------------- +14 | def [T](t: T).m: String = "extrnsion method" // error: extension method, cannot override an normal method. Also needs `override' modifier (but this error should be obfuscated). + | ^ + | error overriding method m in trait B of type [T](x: T): String; + | method m of type [T](t: T): String is an extension method, cannot override a normal method diff --git a/tests/neg/override-extension_normal-methods.scala b/tests/neg/override-extension_normal-methods.scala new file mode 100644 index 000000000000..1293bf8d6b14 --- /dev/null +++ b/tests/neg/override-extension_normal-methods.scala @@ -0,0 +1,15 @@ +trait A { + def [T](t: T).m: String = "extrnsion method" +} + +trait AAA extends A { + def m[T](x: T): String = "normal method" // error: normal method, cannot override an extension method. Also needs `override' modifier (but this error should be obfuscated). +} + +trait B { + def m[T](x: T): String = "normal method" +} + +trait BBB extends B { + def [T](t: T).m: String = "extrnsion method" // error: extension method, cannot override an normal method. Also needs `override' modifier (but this error should be obfuscated). +} \ No newline at end of file