Skip to content

Commit 7920e70

Browse files
authored
Merge pull request #11439 from dotty-staging/override-fix-2
Fix check for unimplemented members in a concrete class
2 parents e90c953 + f796c95 commit 7920e70

File tree

11 files changed

+61
-19
lines changed

11 files changed

+61
-19
lines changed

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

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -541,11 +541,11 @@ object RefChecks {
541541
|| mbr.is(JavaDefined) && hasJavaErasedOverriding(mbr)
542542

543543
def isImplemented(mbr: Symbol) =
544-
val mbrType = clazz.thisType.memberInfo(mbr)
544+
val mbrDenot = mbr.asSeenFrom(clazz.thisType)
545545
def isConcrete(sym: Symbol) = sym.exists && !sym.isOneOf(NotConcrete)
546546
clazz.nonPrivateMembersNamed(mbr.name)
547547
.filterWithPredicate(
548-
impl => isConcrete(impl.symbol) && mbrType.matchesLoosely(impl.info))
548+
impl => isConcrete(impl.symbol) && mbrDenot.matchesLoosely(impl))
549549
.exists
550550

551551
/** The term symbols in this class and its baseclasses that are
@@ -602,8 +602,10 @@ object RefChecks {
602602
}
603603

604604
for (member <- missing) {
605+
def showDclAndLocation(sym: Symbol) =
606+
s"${sym.showDcl} in ${sym.owner.showLocated}"
605607
def undefined(msg: String) =
606-
abstractClassError(false, s"${member.showDcl} is not defined $msg")
608+
abstractClassError(false, s"${showDclAndLocation(member)} is not defined $msg")
607609
val underlying = member.underlyingSymbol
608610

609611
// Give a specific error message for abstract vars based on why it fails:
@@ -641,13 +643,13 @@ object RefChecks {
641643
val abstractSym = pa.typeSymbol
642644
val concreteSym = pc.typeSymbol
643645
def subclassMsg(c1: Symbol, c2: Symbol) =
644-
s": ${c1.showLocated} is a subclass of ${c2.showLocated}, but method parameter types must match exactly."
646+
s"${c1.showLocated} is a subclass of ${c2.showLocated}, but method parameter types must match exactly."
645647
val addendum =
646648
if (abstractSym == concreteSym)
647649
(pa.typeConstructor, pc.typeConstructor) match {
648650
case (TypeRef(pre1, _), TypeRef(pre2, _)) =>
649-
if (pre1 =:= pre2) ": their type parameters differ"
650-
else ": their prefixes (i.e. enclosing instances) differ"
651+
if (pre1 =:= pre2) "their type parameters differ"
652+
else "their prefixes (i.e. enclosing instances) differ"
651653
case _ =>
652654
""
653655
}
@@ -657,18 +659,22 @@ object RefChecks {
657659
subclassMsg(concreteSym, abstractSym)
658660
else ""
659661

660-
undefined(s"\n(Note that ${pa.show} does not match ${pc.show}$addendum)")
662+
undefined(s"""
663+
|(Note that
664+
| parameter ${pa.show} in ${showDclAndLocation(underlying)} does not match
665+
| parameter ${pc.show} in ${showDclAndLocation(concrete.symbol)}
666+
| $addendum)""".stripMargin)
661667
case xs =>
662668
undefined(
663669
if concrete.symbol.is(AbsOverride) then
664-
s"\n(The class implements ${concrete.showDcl} but that definition still needs an implementation)"
670+
s"\n(The class implements ${showDclAndLocation(concrete.symbol)} but that definition still needs an implementation)"
665671
else
666-
s"\n(The class implements a member with a different type: ${concrete.showDcl})")
672+
s"\n(The class implements a member with a different type: ${showDclAndLocation(concrete.symbol)})")
667673
}
668674
case Nil =>
669675
undefined("")
670676
case concretes =>
671-
undefined(s"\n(The class implements members with different types: ${concretes.map(_.showDcl)}%\n %)")
677+
undefined(s"\n(The class implements members with different types: ${concretes.map(c => showDclAndLocation(c.symbol))}%\n %)")
672678
}
673679
}
674680
else undefined("")

tests/explicit-nulls/neg/override-java-object-arg.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import javax.management.{Notification, NotificationEmitter, NotificationListener
77
class Foo {
88

99
def bar(): Unit = {
10-
val listener = new NotificationListener() { // error: object creation impossible
10+
val listener = new NotificationListener() {
1111
override def handleNotification(n: Notification|Null, emitter: Object): Unit = { // error: method handleNotification overrides nothing
1212
}
1313
}
@@ -17,7 +17,7 @@ class Foo {
1717
}
1818
}
1919

20-
val listener3 = new NotificationListener() { // error: object creation impossible
20+
val listener3 = new NotificationListener() {
2121
override def handleNotification(n: Notification, emitter: Object|Null): Unit = { // error: method handleNotification overrides nothing
2222
}
2323
}

tests/explicit-nulls/neg/override-java-object-arg2.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import javax.management.{Notification, NotificationEmitter, NotificationListener
44
class Foo {
55

66
def bar(): Unit = {
7-
val listener4 = new NotificationListener() { // error: duplicate symbol error
7+
val listener4 = new NotificationListener() {
88
def handleNotification(n: Notification|Null, emitter: Object): Unit = { // error
99
}
1010
}

tests/neg/abstract-givens.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
-- Error: tests/neg/abstract-givens.scala:11:8 -------------------------------------------------------------------------
22
11 | given s[T](using T): Seq[T] with // error
33
| ^
4-
| instance cannot be created, since def iterator: => Iterator[A] is not defined
4+
|instance cannot be created, since def iterator: => Iterator[A] in trait IterableOnce in package scala.collection is not defined
55
-- Error: tests/neg/abstract-givens.scala:8:8 --------------------------------------------------------------------------
66
8 | given y(using Int): String = summon[Int].toString * 22 // error
77
| ^

tests/neg/i10666.check

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-- Error: tests/neg/i10666.scala:8:6 -----------------------------------------------------------------------------------
2+
8 |class Bar extends Foo { // error
3+
| ^
4+
| class Bar needs to be abstract, since def foo: [T <: B](tx: T): Unit in trait Foo is not defined
5+
| (Note that
6+
| parameter T in def foo: [T <: B](tx: T): Unit in trait Foo does not match
7+
| parameter T in def foo: [T <: A](tx: T): Unit in class Bar
8+
| class B is a subclass of class A, but method parameter types must match exactly.)

tests/neg/i10666.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class A
2+
class B extends A
3+
4+
trait Foo {
5+
def foo[T <: B](tx: T): Unit
6+
}
7+
8+
class Bar extends Foo { // error
9+
def foo[T <: A](tx: T): Unit = {}
10+
}
11+
12+
object Test {
13+
def main(args: Array[String]): Unit = {
14+
val f: Foo = new Bar
15+
f.foo(new B)
16+
}
17+
}

tests/neg/i7597.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
object Test extends App {
22
def foo[S <: String]: String => Int =
3-
new (String => Int) { def apply(s: S): Int = 0 } // error // error
3+
new (String => Int) { def apply(s: S): Int = 0 } // error
44

55
trait Fn[A, B] {
66
def apply(x: A): B
77
}
88

9-
class C[S <: String] extends Fn[String, Int] { // error
9+
class C[S <: String] extends Fn[String, Int] {
1010
def apply(s: S): Int = 0 // error
1111
}
1212

tests/neg/i9329.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
-- Error: tests/neg/i9329.scala:8:6 ------------------------------------------------------------------------------------
22
8 |class GrandSon extends Son // error
33
| ^
4-
| class GrandSon needs to be abstract, since def name: => String is not defined
5-
| (The class implements abstract override def name: => String but that definition still needs an implementation)
4+
|class GrandSon needs to be abstract, since def name: => String in trait Parent is not defined
5+
|(The class implements abstract override def name: => String in trait Son but that definition still needs an implementation)

tests/pos-java-interop/i10599/A.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
public abstract class A<T> {
2+
public abstract void foo(T value);
3+
public void foo(T value, Object obj) { return; }
4+
}

tests/pos-java-interop/i10599/B.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
abstract class Base[M[_], T] extends A[M[T]] {
2+
override def foo(value: M[T]): Unit = ???
3+
}
4+
5+
class ArrayTest[T] extends Base[Array, T]
6+
7+
class ListTest[T] extends Base[List, T]

0 commit comments

Comments
 (0)