From d8359a20a088a4724431ce9c7dd93869c2ad23cb Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 16 Aug 2011 16:53:16 +0000 Subject: Improved the error message given when a concret... Improved the error message given when a concrete method implementation doesn't match the abstract one. No review. --- .../scala/tools/nsc/typechecker/RefChecks.scala | 17 ++++++++++++++--- test/files/neg/abstract-concrete-methods.check | 5 +++++ test/files/neg/abstract-concrete-methods.scala | 10 ++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 test/files/neg/abstract-concrete-methods.check create mode 100644 test/files/neg/abstract-concrete-methods.scala diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 9f957af136..10918ecffa 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -533,19 +533,30 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R mismatches match { // Only one mismatched parameter: say something useful. case (pa, pc) :: Nil => - val addendum = - if (pa.typeSymbol == pc.typeSymbol) { + val abstractSym = pa.typeSymbol + val concreteSym = pc.typeSymbol + def subclassMsg(c1: Symbol, c2: Symbol) = ( + ": %s is a subclass of %s, but method parameter types must match exactly.".format( + c1.fullLocationString, c2.fullLocationString) + ) + val addendum = ( + if (abstractSym == concreteSym) { // TODO: what is the optimal way to test for a raw type at this point? // Compilation has already failed so we shouldn't have to worry overmuch // about forcing types. - if (underlying.isJavaDefined && pa.typeArgs.isEmpty && pa.typeSymbol.typeParams.nonEmpty) + if (underlying.isJavaDefined && pa.typeArgs.isEmpty && abstractSym.typeParams.nonEmpty) ". To implement a raw type, use %s[_]".format(pa) else if (pa.prefix =:= pc.prefix) ": their type parameters differ" else ": their prefixes (i.e. enclosing instances) differ" } + else if (abstractSym isSubClass concreteSym) + subclassMsg(abstractSym, concreteSym) + else if (concreteSym isSubClass abstractSym) + subclassMsg(concreteSym, abstractSym) else "" + ) undefined("\n(Note that %s does not match %s%s)".format(pa, pc, addendum)) case xs => diff --git a/test/files/neg/abstract-concrete-methods.check b/test/files/neg/abstract-concrete-methods.check new file mode 100644 index 0000000000..e128f77e26 --- /dev/null +++ b/test/files/neg/abstract-concrete-methods.check @@ -0,0 +1,5 @@ +abstract-concrete-methods.scala:7: error: class Outer2 needs to be abstract, since method score in trait Outer of type (i: Outer2#Inner)Double is not defined +(Note that This#Inner does not match Outer2#Inner: class Inner in class Outer2 is a subclass of trait Inner in trait Outer, but method parameter types must match exactly.) +class Outer2 extends Outer[Outer2] { + ^ +one error found diff --git a/test/files/neg/abstract-concrete-methods.scala b/test/files/neg/abstract-concrete-methods.scala new file mode 100644 index 0000000000..7f1aea0dbc --- /dev/null +++ b/test/files/neg/abstract-concrete-methods.scala @@ -0,0 +1,10 @@ +trait Outer[This <: Outer[This]] { + self: This => + + trait Inner + def score(i: This#Inner): Double +} +class Outer2 extends Outer[Outer2] { + class Inner extends super.Inner + def score(i: Outer2#Inner) = 0.0 +} -- cgit v1.2.3