Skip to content

Commit 723cf3b

Browse files
authored
Merge pull request #11133 from dotty-staging/fix-#11130
Add overriding check
2 parents 8a4bcb9 + a611766 commit 723cf3b

12 files changed

+48
-46
lines changed

compiler/src/dotty/tools/dotc/typer/RefChecks.scala

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -387,9 +387,11 @@ object RefChecks {
387387
overrideError("is an extension method, cannot override a normal method")
388388
else if (other.is(ExtensionMethod) && !member.is(ExtensionMethod)) // (1.3)
389389
overrideError("is a normal method, cannot override an extension method")
390-
else if (!other.is(Deferred) &&
391-
!other.name.is(DefaultGetterName) &&
392-
!member.isAnyOverride)
390+
else if !other.is(Deferred)
391+
&& !member.is(Deferred)
392+
&& !other.name.is(DefaultGetterName)
393+
&& !member.isAnyOverride
394+
then
393395
// Exclusion for default getters, fixes SI-5178. We cannot assign the Override flag to
394396
// the default getter: one default getter might sometimes override, sometimes not. Example in comment on ticket.
395397
// Also exclusion for implicit shortcut methods
@@ -485,6 +487,22 @@ object RefChecks {
485487
while opc.hasNext do
486488
checkOverride(opc.overriding, opc.overridden)
487489
opc.next()
490+
491+
// The OverridingPairs cursor does assume that concrete overrides abstract
492+
// We have to check separately for an abstract definition in a subclass that
493+
// overrides a concrete definition in a superclass. E.g. the following (inspired
494+
// from neg/i11130.scala) needs to be rejected as well:
495+
//
496+
// class A { type T = B }
497+
// class B extends A { override type T }
498+
for
499+
dcl <- clazz.info.decls.iterator
500+
if dcl.is(Deferred)
501+
other <- dcl.allOverriddenSymbols
502+
if !other.is(Deferred)
503+
do
504+
checkOverride(dcl, other)
505+
488506
printMixinOverrideErrors()
489507

490508
// Verifying a concrete class has nothing unimplemented.
@@ -748,17 +766,6 @@ object RefChecks {
748766
checkMemberTypesOK()
749767
checkCaseClassInheritanceInvariant()
750768
}
751-
else if (clazz.is(Trait) && !(clazz derivesFrom defn.AnyValClass))
752-
// For non-AnyVal classes, prevent abstract methods in interfaces that override
753-
// final members in Object; see #4431
754-
for (decl <- clazz.info.decls) {
755-
// Have to use matchingSymbol, not a method involving overridden symbols,
756-
// because the scala type system understands that an abstract method here does not
757-
// override a concrete method in Object. The jvm, however, does not.
758-
val overridden = decl.matchingDecl(defn.ObjectClass, defn.ObjectType)
759-
if (overridden.is(Final))
760-
report.error(TraitRedefinedFinalMethodFromAnyRef(overridden), decl.srcPos)
761-
}
762769

763770
if (!clazz.is(Trait)) {
764771
// check that parameterized base classes and traits are typed in the same way as from the superclass

tests/neg/i11130.scala

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
@main def test: Unit = {
2+
class Foo
3+
class Bar extends Foo
4+
5+
trait S[-A] {
6+
type T >: A
7+
}
8+
trait PFoo extends S[Foo]
9+
trait PBar extends S[Bar] {
10+
override type T = Bar
11+
}
12+
class PFooBar extends PBar with PFoo {
13+
override type T >: Bar // error
14+
}
15+
16+
def patmat[A](s: S[A]): s.T = s match {
17+
case p: (PFoo & s.type) => (new Foo): p.T
18+
}
19+
20+
// ClassCastException: Foo cannot be cast to class Bar
21+
val x: Bar = patmat(new PFooBar: PBar)
22+
}

tests/neg/i7359-b.check

Lines changed: 0 additions & 4 deletions
This file was deleted.

tests/neg/i7359-b.scala

Lines changed: 0 additions & 3 deletions
This file was deleted.

tests/neg/i7359-c.check

Lines changed: 0 additions & 4 deletions
This file was deleted.

tests/neg/i7359-c.scala

Lines changed: 0 additions & 3 deletions
This file was deleted.

tests/neg/i7359-d.check

Lines changed: 0 additions & 4 deletions
This file was deleted.

tests/neg/i7359-d.scala

Lines changed: 0 additions & 3 deletions
This file was deleted.

tests/neg/i7359-e.check

Lines changed: 0 additions & 4 deletions
This file was deleted.

tests/neg/i7359-e.scala

Lines changed: 0 additions & 3 deletions
This file was deleted.

tests/neg/i7359.check

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
-- [E105] Syntax Error: tests/neg/i7359.scala:3:6 ----------------------------------------------------------------------
1+
-- Error: tests/neg/i7359.scala:3:6 ------------------------------------------------------------------------------------
22
3 | def notify(): Unit // error
33
| ^
4-
| Traits cannot redefine final method notify from class AnyRef.
4+
| error overriding method notify in class Object of type (): Unit;
5+
| method notify of type (): Unit cannot override final member method notify in class Object

tests/neg/inline-override.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ object Test {
2525
override def f1(): Int // OK
2626
override def f2(): Int // OK
2727
override def f3(): Int // error
28-
override def f4(): Int // OK not retained
28+
override def f4(): Int // error
2929
}
3030

3131
abstract class E extends A { // error f1
3232
inline override def f1(): Int
3333
inline override def f2(): Int
3434
inline override def f3(): Int
35-
inline override def f4(): Int // OK not retained
35+
inline override def f4(): Int // error
3636
}
3737

3838
}

0 commit comments

Comments
 (0)