From 6b424fd9321cff583309892c5b13130eaace6a6a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 6 Jan 2021 14:45:45 +0100 Subject: [PATCH] Check for unimplemented abstract override members Fixes #9329 --- compiler/src/dotty/tools/dotc/core/Flags.scala | 1 + compiler/src/dotty/tools/dotc/typer/RefChecks.scala | 10 +++++++--- tests/neg/i9329.check | 5 +++++ tests/neg/i9329.scala | 8 ++++++++ 4 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 tests/neg/i9329.check create mode 100644 tests/neg/i9329.scala diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 04b91569a13c..8aeb68cbe984 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -530,6 +530,7 @@ object Flags { // ------- Other flag sets ------------------------------------- + val NotConcrete: FlagSet = AbsOverride | Deferred val AbstractFinal: FlagSet = Abstract | Final val AbstractOverride: FlagSet = Abstract | Override val AbstractSealed: FlagSet = Abstract | Sealed diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 46f6b18f7d37..303c74ca42e7 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -524,10 +524,10 @@ object RefChecks { def isImplemented(mbr: Symbol) = val mbrType = clazz.thisType.memberInfo(mbr) - extension (sym: Symbol) def isConcrete = sym.exists && !sym.is(Deferred) + def isConcrete(sym: Symbol) = sym.exists && !sym.isOneOf(NotConcrete) clazz.nonPrivateMembersNamed(mbr.name) .filterWithPredicate( - impl => impl.symbol.isConcrete && mbrType.matchesLoosely(impl.info)) + impl => isConcrete(impl.symbol) && mbrType.matchesLoosely(impl.info)) .exists /** The term symbols in this class and its baseclasses that are @@ -641,7 +641,11 @@ object RefChecks { undefined(s"\n(Note that ${pa.show} does not match ${pc.show}$addendum)") case xs => - undefined(s"\n(The class implements a member with a different type: ${concrete.showDcl})") + undefined( + if concrete.symbol.is(AbsOverride) then + s"\n(The class implements ${concrete.showDcl} but that definition still needs an implementation)" + else + s"\n(The class implements a member with a different type: ${concrete.showDcl})") } case Nil => undefined("") diff --git a/tests/neg/i9329.check b/tests/neg/i9329.check new file mode 100644 index 000000000000..72e5fa1a0ff9 --- /dev/null +++ b/tests/neg/i9329.check @@ -0,0 +1,5 @@ +-- Error: tests/neg/i9329.scala:8:6 ------------------------------------------------------------------------------------ +8 |class GrandSon extends Son // error + | ^ + | class GrandSon needs to be abstract, since def name: => String is not defined + | (The class implements abstract override def name: => String but that definition still needs an implementation) diff --git a/tests/neg/i9329.scala b/tests/neg/i9329.scala new file mode 100644 index 000000000000..88279d296e2e --- /dev/null +++ b/tests/neg/i9329.scala @@ -0,0 +1,8 @@ +trait Parent { + def name: String +} +trait Son extends Parent { + abstract override def name = "" + def parentName = super.name +} +class GrandSon extends Son // error \ No newline at end of file